stoatx 0.5.5 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -94,6 +94,7 @@ Marks a method as a command.
94
94
  aliases: ['b'], // Alternative names
95
95
  permissions: ['BanMembers'], // This is currently not implemented, but will be in the future
96
96
  cooldown: 5000, // 5 seconds
97
+ cooldownStorage: "database", // A custom flag you can use in your CustomCooldownManager
97
98
  ownerOnly: false,
98
99
  nsfw: false,
99
100
  })
@@ -129,6 +130,47 @@ export class MyCommands implements StoatLifecycle {
129
130
  }
130
131
  ```
131
132
 
133
+ ## Custom Cooldowns
134
+
135
+ By default, cooldowns are stored in memory. For persistent or distributed setups, you can implement the `CooldownManager` interface to store cooldowns in a database such as Redis, PostgreSQL or MongoDB.
136
+
137
+ ```typescript
138
+ import { Client, CooldownManager, CommandContext, CommandMetadata, DefaultCooldownManager } from "stoatx";
139
+
140
+ class MixedCooldownManager implements CooldownManager {
141
+ private memory = new DefaultCooldownManager();
142
+
143
+ async check(ctx: CommandContext, metadata: CommandMetadata): Promise<boolean> {
144
+ if (metadata.cooldownStorage === "database") {
145
+ // Return true if action is allowed in DB
146
+ return true;
147
+ }
148
+ return this.memory.check(ctx, metadata);
149
+ }
150
+
151
+ async getRemaining(ctx: CommandContext, metadata: CommandMetadata): Promise<number> {
152
+ if (metadata.cooldownStorage === "database") {
153
+ // Query remaining from DB
154
+ return 0;
155
+ }
156
+ return this.memory.getRemaining(ctx, metadata);
157
+ }
158
+
159
+ async set(ctx: CommandContext, metadata: CommandMetadata): Promise<void> {
160
+ if (metadata.cooldownStorage === "database") {
161
+ // Store cooldown expiration in your database
162
+ return;
163
+ }
164
+ this.memory.set(ctx, metadata);
165
+ }
166
+ }
167
+
168
+ const client = new Client({
169
+ prefix: "!",
170
+ cooldownManager: new MixedCooldownManager(),
171
+ });
172
+ ```
173
+
132
174
  ## Guards
133
175
 
134
176
  ### @Guard(GuardClass)
package/dist/index.d.mts CHANGED
@@ -22,6 +22,8 @@ interface SimpleCommandOptions {
22
22
  category?: string;
23
23
  /** Cooldown in milliseconds */
24
24
  cooldown?: number;
25
+ /** Storage strategy or identifier for cooldowns (e.g. "memory", "database") */
26
+ cooldownStorage?: string;
25
27
  /** Whether the command is NSFW only */
26
28
  nsfw?: boolean;
27
29
  /** Whether the command is owner only */
@@ -37,6 +39,7 @@ interface CommandMetadata {
37
39
  permissions: Permission[];
38
40
  category: string;
39
41
  cooldown: number;
42
+ cooldownStorage?: string;
40
43
  nsfw: boolean;
41
44
  ownerOnly: boolean;
42
45
  }
@@ -74,7 +77,16 @@ interface StoatLifecycle {
74
77
  /** Optional: Called when a cooldown is active */
75
78
  onCooldown?(ctx: CommandContext, remaining: number): Promise<void> | void;
76
79
  /** Allows the class to contain other methods (such as your commands) */
77
- [key: string]: any;
80
+ [method: string]: any;
81
+ }
82
+ /**
83
+ * Cooldown manager interface for custom cooldown storage (e.g., database)
84
+ */
85
+ interface CooldownManager {
86
+ check(ctx: CommandContext, metadata: CommandMetadata): boolean | Promise<boolean>;
87
+ getRemaining(ctx: CommandContext, metadata: CommandMetadata): number | Promise<number>;
88
+ set(ctx: CommandContext, metadata: CommandMetadata): void | Promise<void>;
89
+ clear?(): void | Promise<void>;
78
90
  }
79
91
  interface StoatxGuard {
80
92
  run(ctx: CommandContext): Promise<boolean> | boolean;
@@ -111,6 +123,8 @@ interface StoatxHandlerOptions {
111
123
  extensions?: string[];
112
124
  /** Disable mention prefix support (default: false) */
113
125
  disableMentionPrefix?: boolean;
126
+ /** Custom cooldown manager */
127
+ cooldownManager?: CooldownManager;
114
128
  }
115
129
 
116
130
  /**
@@ -404,6 +418,16 @@ declare class CommandRegistry {
404
418
  private getCategoryFromPath;
405
419
  }
406
420
 
421
+ /**
422
+ * Default in-memory cooldown manager
423
+ */
424
+ declare class DefaultCooldownManager implements CooldownManager {
425
+ private readonly cooldowns;
426
+ check(ctx: CommandContext, metadata: CommandMetadata): boolean;
427
+ getRemaining(ctx: CommandContext, metadata: CommandMetadata): number;
428
+ set(ctx: CommandContext, metadata: CommandMetadata): void;
429
+ clear(): void;
430
+ }
407
431
  /**
408
432
  * Client - An extended Client that integrates StoatxHandler directly
409
433
  *
@@ -440,7 +464,7 @@ declare class StoatxHandler {
440
464
  private readonly prefixResolver;
441
465
  private readonly owners;
442
466
  private readonly registry;
443
- private readonly cooldowns;
467
+ private readonly cooldownManager;
444
468
  private readonly disableMentionPrefix;
445
469
  private readonly client;
446
470
  constructor(options: StoatxHandlerOptions);
@@ -531,18 +555,6 @@ declare class StoatxHandler {
531
555
  * Resolve the prefix for a context
532
556
  */
533
557
  private resolvePrefix;
534
- /**
535
- * Check if user is on cooldown
536
- */
537
- private checkCooldown;
538
- /**
539
- * Get remaining cooldown time in ms
540
- */
541
- private getRemainingCooldown;
542
- /**
543
- * Set cooldown for a user
544
- */
545
- private setCooldown;
546
558
  }
547
559
 
548
- export { Client, type CommandContext, type CommandMetadata, CommandRegistry, type EventDefinition, Guard, METADATA_KEYS, On, Once, type Permission, type RegisteredCommand, type RegisteredEvent, SimpleCommand, type SimpleCommandDefinition, type SimpleCommandOptions, Stoat, type StoatLifecycle, type StoatxDiscoveryOptions, type StoatxGuard, StoatxHandler, type StoatxHandlerOptions, buildSimpleCommandMetadata, getEventsMetadata, getGuards, getSimpleCommands, isStoatClass };
560
+ export { Client, type CommandContext, type CommandMetadata, CommandRegistry, type CooldownManager, DefaultCooldownManager, type EventDefinition, Guard, METADATA_KEYS, On, Once, type Permission, type RegisteredCommand, type RegisteredEvent, SimpleCommand, type SimpleCommandDefinition, type SimpleCommandOptions, Stoat, type StoatLifecycle, type StoatxDiscoveryOptions, type StoatxGuard, StoatxHandler, type StoatxHandlerOptions, buildSimpleCommandMetadata, getEventsMetadata, getGuards, getSimpleCommands, isStoatClass };
package/dist/index.d.ts CHANGED
@@ -22,6 +22,8 @@ interface SimpleCommandOptions {
22
22
  category?: string;
23
23
  /** Cooldown in milliseconds */
24
24
  cooldown?: number;
25
+ /** Storage strategy or identifier for cooldowns (e.g. "memory", "database") */
26
+ cooldownStorage?: string;
25
27
  /** Whether the command is NSFW only */
26
28
  nsfw?: boolean;
27
29
  /** Whether the command is owner only */
@@ -37,6 +39,7 @@ interface CommandMetadata {
37
39
  permissions: Permission[];
38
40
  category: string;
39
41
  cooldown: number;
42
+ cooldownStorage?: string;
40
43
  nsfw: boolean;
41
44
  ownerOnly: boolean;
42
45
  }
@@ -74,7 +77,16 @@ interface StoatLifecycle {
74
77
  /** Optional: Called when a cooldown is active */
75
78
  onCooldown?(ctx: CommandContext, remaining: number): Promise<void> | void;
76
79
  /** Allows the class to contain other methods (such as your commands) */
77
- [key: string]: any;
80
+ [method: string]: any;
81
+ }
82
+ /**
83
+ * Cooldown manager interface for custom cooldown storage (e.g., database)
84
+ */
85
+ interface CooldownManager {
86
+ check(ctx: CommandContext, metadata: CommandMetadata): boolean | Promise<boolean>;
87
+ getRemaining(ctx: CommandContext, metadata: CommandMetadata): number | Promise<number>;
88
+ set(ctx: CommandContext, metadata: CommandMetadata): void | Promise<void>;
89
+ clear?(): void | Promise<void>;
78
90
  }
79
91
  interface StoatxGuard {
80
92
  run(ctx: CommandContext): Promise<boolean> | boolean;
@@ -111,6 +123,8 @@ interface StoatxHandlerOptions {
111
123
  extensions?: string[];
112
124
  /** Disable mention prefix support (default: false) */
113
125
  disableMentionPrefix?: boolean;
126
+ /** Custom cooldown manager */
127
+ cooldownManager?: CooldownManager;
114
128
  }
115
129
 
116
130
  /**
@@ -404,6 +418,16 @@ declare class CommandRegistry {
404
418
  private getCategoryFromPath;
405
419
  }
406
420
 
421
+ /**
422
+ * Default in-memory cooldown manager
423
+ */
424
+ declare class DefaultCooldownManager implements CooldownManager {
425
+ private readonly cooldowns;
426
+ check(ctx: CommandContext, metadata: CommandMetadata): boolean;
427
+ getRemaining(ctx: CommandContext, metadata: CommandMetadata): number;
428
+ set(ctx: CommandContext, metadata: CommandMetadata): void;
429
+ clear(): void;
430
+ }
407
431
  /**
408
432
  * Client - An extended Client that integrates StoatxHandler directly
409
433
  *
@@ -440,7 +464,7 @@ declare class StoatxHandler {
440
464
  private readonly prefixResolver;
441
465
  private readonly owners;
442
466
  private readonly registry;
443
- private readonly cooldowns;
467
+ private readonly cooldownManager;
444
468
  private readonly disableMentionPrefix;
445
469
  private readonly client;
446
470
  constructor(options: StoatxHandlerOptions);
@@ -531,18 +555,6 @@ declare class StoatxHandler {
531
555
  * Resolve the prefix for a context
532
556
  */
533
557
  private resolvePrefix;
534
- /**
535
- * Check if user is on cooldown
536
- */
537
- private checkCooldown;
538
- /**
539
- * Get remaining cooldown time in ms
540
- */
541
- private getRemainingCooldown;
542
- /**
543
- * Set cooldown for a user
544
- */
545
- private setCooldown;
546
558
  }
547
559
 
548
- export { Client, type CommandContext, type CommandMetadata, CommandRegistry, type EventDefinition, Guard, METADATA_KEYS, On, Once, type Permission, type RegisteredCommand, type RegisteredEvent, SimpleCommand, type SimpleCommandDefinition, type SimpleCommandOptions, Stoat, type StoatLifecycle, type StoatxDiscoveryOptions, type StoatxGuard, StoatxHandler, type StoatxHandlerOptions, buildSimpleCommandMetadata, getEventsMetadata, getGuards, getSimpleCommands, isStoatClass };
560
+ export { Client, type CommandContext, type CommandMetadata, CommandRegistry, type CooldownManager, DefaultCooldownManager, type EventDefinition, Guard, METADATA_KEYS, On, Once, type Permission, type RegisteredCommand, type RegisteredEvent, SimpleCommand, type SimpleCommandDefinition, type SimpleCommandOptions, Stoat, type StoatLifecycle, type StoatxDiscoveryOptions, type StoatxGuard, StoatxHandler, type StoatxHandlerOptions, buildSimpleCommandMetadata, getEventsMetadata, getGuards, getSimpleCommands, isStoatClass };
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ var index_exports = {};
33
33
  __export(index_exports, {
34
34
  Client: () => Client,
35
35
  CommandRegistry: () => CommandRegistry,
36
+ DefaultCooldownManager: () => DefaultCooldownManager,
36
37
  Guard: () => Guard,
37
38
  METADATA_KEYS: () => METADATA_KEYS,
38
39
  On: () => On,
@@ -201,6 +202,7 @@ function buildSimpleCommandMetadata(options, methodName, category) {
201
202
  permissions: options.permissions ?? [],
202
203
  category: options.category ?? category ?? "uncategorized",
203
204
  cooldown: options.cooldown ?? 0,
205
+ ...options.cooldownStorage !== void 0 ? { cooldownStorage: options.cooldownStorage } : {},
204
206
  nsfw: options.nsfw ?? false,
205
207
  ownerOnly: options.ownerOnly ?? false
206
208
  };
@@ -476,6 +478,38 @@ var CommandRegistry = class _CommandRegistry {
476
478
  // src/handler.ts
477
479
  var import_reflect_metadata5 = require("reflect-metadata");
478
480
  var import_client = require("@stoatx/client");
481
+ var DefaultCooldownManager = class {
482
+ cooldowns = /* @__PURE__ */ new Map();
483
+ check(ctx, metadata) {
484
+ if (metadata.cooldown <= 0) return true;
485
+ const commandCooldowns = this.cooldowns.get(metadata.name);
486
+ if (!commandCooldowns) return true;
487
+ const expirationTime = commandCooldowns.get(ctx.authorId);
488
+ if (!expirationTime) return true;
489
+ if (Date.now() > expirationTime) {
490
+ commandCooldowns.delete(ctx.authorId);
491
+ return true;
492
+ }
493
+ return false;
494
+ }
495
+ getRemaining(ctx, metadata) {
496
+ const commandCooldowns = this.cooldowns.get(metadata.name);
497
+ if (!commandCooldowns) return 0;
498
+ const userCooldown = commandCooldowns.get(ctx.authorId);
499
+ if (!userCooldown) return 0;
500
+ return Math.max(0, userCooldown - Date.now());
501
+ }
502
+ set(ctx, metadata) {
503
+ if (!this.cooldowns.has(metadata.name)) {
504
+ this.cooldowns.set(metadata.name, /* @__PURE__ */ new Map());
505
+ }
506
+ const commandCooldowns = this.cooldowns.get(metadata.name);
507
+ commandCooldowns.set(ctx.authorId, Date.now() + metadata.cooldown);
508
+ }
509
+ clear() {
510
+ this.cooldowns.clear();
511
+ }
512
+ };
479
513
  var Client = class extends import_client.Client {
480
514
  handler;
481
515
  constructor(options) {
@@ -498,7 +532,7 @@ var StoatxHandler = class {
498
532
  prefixResolver;
499
533
  owners;
500
534
  registry;
501
- cooldowns = /* @__PURE__ */ new Map();
535
+ cooldownManager;
502
536
  disableMentionPrefix;
503
537
  client;
504
538
  constructor(options) {
@@ -509,6 +543,7 @@ var StoatxHandler = class {
509
543
  this.owners = new Set(options.owners ?? []);
510
544
  this.registry = new CommandRegistry(options.extensions);
511
545
  this.disableMentionPrefix = options.disableMentionPrefix ?? false;
546
+ this.cooldownManager = options.cooldownManager ?? new DefaultCooldownManager();
512
547
  }
513
548
  /**
514
549
  * Initialize the handler - load all commands
@@ -671,8 +706,8 @@ var StoatxHandler = class {
671
706
  }
672
707
  }
673
708
  }
674
- if (!this.checkCooldown(ctx.authorId, metadata)) {
675
- const remaining = this.getRemainingCooldown(ctx.authorId, metadata);
709
+ if (!await this.cooldownManager.check(ctx, metadata)) {
710
+ const remaining = await this.cooldownManager.getRemaining(ctx, metadata);
676
711
  if (typeof instance.onCooldown === "function") {
677
712
  await instance.onCooldown(ctx, remaining);
678
713
  } else {
@@ -682,7 +717,7 @@ var StoatxHandler = class {
682
717
  }
683
718
  try {
684
719
  if (metadata.cooldown > 0) {
685
- this.setCooldown(ctx.authorId, metadata);
720
+ await this.cooldownManager.set(ctx, metadata);
686
721
  }
687
722
  await instance[methodName](ctx);
688
723
  return true;
@@ -718,7 +753,9 @@ var StoatxHandler = class {
718
753
  */
719
754
  async reload() {
720
755
  this.registry.clear();
721
- this.cooldowns.clear();
756
+ if (this.cooldownManager.clear) {
757
+ await this.cooldownManager.clear();
758
+ }
722
759
  if (this.commandsDir) {
723
760
  await this.registry.loadFromDirectory(this.commandsDir);
724
761
  return;
@@ -752,41 +789,6 @@ var StoatxHandler = class {
752
789
  }
753
790
  return this.prefixResolver;
754
791
  }
755
- /**
756
- * Check if user is on cooldown
757
- */
758
- checkCooldown(userId, metadata) {
759
- if (metadata.cooldown <= 0) return true;
760
- const commandCooldowns = this.cooldowns.get(metadata.name);
761
- if (!commandCooldowns) return true;
762
- const expirationTime = commandCooldowns.get(userId);
763
- if (!expirationTime) return true;
764
- if (Date.now() > expirationTime) {
765
- commandCooldowns.delete(userId);
766
- return true;
767
- }
768
- return false;
769
- }
770
- /**
771
- * Get remaining cooldown time in ms
772
- */
773
- getRemainingCooldown(userId, metadata) {
774
- const commandCooldowns = this.cooldowns.get(metadata.name);
775
- if (!commandCooldowns) return 0;
776
- const userCooldown = commandCooldowns.get(userId);
777
- if (!userCooldown) return 0;
778
- return Math.max(0, userCooldown - Date.now());
779
- }
780
- /**
781
- * Set cooldown for a user
782
- */
783
- setCooldown(userId, metadata) {
784
- if (!this.cooldowns.has(metadata.name)) {
785
- this.cooldowns.set(metadata.name, /* @__PURE__ */ new Map());
786
- }
787
- const commandCooldowns = this.cooldowns.get(metadata.name);
788
- commandCooldowns.set(userId, Date.now() + metadata.cooldown);
789
- }
790
792
  };
791
793
 
792
794
  // src/index.ts
@@ -795,6 +797,7 @@ __reExport(index_exports, require("@stoatx/client"), module.exports);
795
797
  0 && (module.exports = {
796
798
  Client,
797
799
  CommandRegistry,
800
+ DefaultCooldownManager,
798
801
  Guard,
799
802
  METADATA_KEYS,
800
803
  On,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/decorators/Stoat.ts","../src/decorators/keys.ts","../src/decorators/store.ts","../src/decorators/SimpleCommand.ts","../src/decorators/Guard.ts","../src/decorators/Events.ts","../src/decorators/utils.ts","../src/registry.ts","../src/handler.ts"],"sourcesContent":["// Types\nexport * from \"./types\";\n\n// Decorators\nexport * from \"./decorators\";\n\n// Registry\nexport * from \"./registry\";\n\n// Handler\nexport { Client } from \"./handler\";\nexport type { StoatxHandler } from \"./handler\";\nexport * from \"@stoatx/client\";\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\nimport { decoratorStore } from \"./store\";\n\n/**\n * @Stoat\n * Marks a class as a Stoat command container.\n * Use this decorator on classes that contain @SimpleCommand methods.\n *\n * @example\n * ```ts\n * import { Stoat, SimpleCommand, CommandContext } from 'stoatx';\n *\n * @Stoat()\n * class ModerationCommands {\n * @SimpleCommand({ name: 'ban', description: 'Ban a user' })\n * async ban(ctx: CommandContext) {\n * await ctx.reply('User banned!');\n * }\n *\n * @SimpleCommand({ name: 'kick', description: 'Kick a user' })\n * async kick(ctx: CommandContext) {\n * await ctx.reply('User kicked!');\n * }\n * }\n * ```\n */\nexport function Stoat(): ClassDecorator {\n return (target: Function) => {\n Reflect.defineMetadata(METADATA_KEYS.IS_STOAT_CLASS, true, target);\n decoratorStore.registerStoatClass(target);\n };\n}\n\n/**\n * Check if a class is decorated with @Stoat\n */\nexport function isStoatClass(target: Function): boolean {\n return Reflect.getMetadata(METADATA_KEYS.IS_STOAT_CLASS, target) === true;\n}\n","/**\n * Metadata keys used by decorators\n */\nexport const METADATA_KEYS = {\n IS_STOAT_CLASS: Symbol(\"stoatx:stoat:isClass\"),\n SIMPLE_COMMANDS: Symbol(\"stoatx:stoat:simpleCommands\"),\n GUARDS: \"stoatx:command:guards\",\n EVENTS: Symbol(\"stoatx:stoat:events\"),\n} as const;\n","import type { RegisteredCommand } from \"../registry\";\n\n/**\n * Global store for all decorated classes and commands\n * This allows automatic registration without directory scanning\n */\nexport class DecoratorStore {\n private static instance: DecoratorStore;\n\n /** Stoat classes with their SimpleCommand methods */\n private stoatClasses: Map<Function, object> = new Map();\n\n /** Registered commands from @Stoat/@SimpleCommand decorators */\n private commands: RegisteredCommand[] = [];\n\n /** Whether the store has been initialized */\n private initialized = false;\n\n private constructor() {}\n\n static getInstance(): DecoratorStore {\n if (!DecoratorStore.instance) {\n DecoratorStore.instance = new DecoratorStore();\n }\n return DecoratorStore.instance;\n }\n\n /**\n * Register a @Stoat decorated class\n */\n registerStoatClass(classConstructor: Function): void {\n if (!this.stoatClasses.has(classConstructor)) {\n // Create instance immediately when decorated\n const instance = new (classConstructor as new () => object)();\n this.stoatClasses.set(classConstructor, instance);\n }\n }\n\n /**\n * Get all registered Stoat classes with their instances\n */\n getStoatClasses(): Map<Function, object> {\n return this.stoatClasses;\n }\n\n /**\n * Add a registered command\n */\n addCommand(command: RegisteredCommand): void {\n this.commands.push(command);\n }\n\n /**\n * Get all registered commands\n */\n getCommands(): RegisteredCommand[] {\n return this.commands;\n }\n\n /**\n * Clear all registered classes (useful for testing)\n */\n clear(): void {\n this.stoatClasses.clear();\n this.commands = [];\n this.initialized = false;\n }\n\n /**\n * Mark as initialized\n */\n markInitialized(): void {\n this.initialized = true;\n }\n\n /**\n * Check if initialized\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n}\n\nexport const decoratorStore = DecoratorStore.getInstance();\n","import \"reflect-metadata\";\nimport type { SimpleCommandOptions } from \"../types\";\nimport { METADATA_KEYS } from \"./keys\";\n\n/**\n * Stored simple command metadata from method decorator\n */\nexport interface SimpleCommandDefinition {\n methodName: string;\n options: SimpleCommandOptions;\n}\n\n/**\n * @SimpleCommand\n * Marks a method as a simple command within a @Stoat() decorated class.\n *\n * @example\n * ```ts\n * @Stoat()\n * class Example {\n * @SimpleCommand({ name: 'ping', description: 'Replies with Pong!' })\n * async ping(ctx: CommandContext) {\n * await ctx.reply('Pong!');\n * }\n *\n * @SimpleCommand({ aliases: ['perm'], name: 'permission' })\n * async permission(ctx: CommandContext) {\n * await ctx.reply('Access granted');\n * }\n * }\n * ```\n */\nexport function SimpleCommand(options: SimpleCommandOptions = {}): MethodDecorator {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n\n // Get existing simple commands or create new array\n const existingCommands: SimpleCommandDefinition[] =\n Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, constructor) || [];\n\n // Add this command definition\n existingCommands.push({\n methodName: String(propertyKey),\n options,\n });\n\n Reflect.defineMetadata(METADATA_KEYS.SIMPLE_COMMANDS, existingCommands, constructor);\n\n return descriptor;\n };\n}\n\n/**\n * Get all simple command definitions from a @Stoat class\n */\nexport function getSimpleCommands(target: Function): SimpleCommandDefinition[] {\n return Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, target) || [];\n}\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\n\n/**\n * @Guard\n * Runs before a command to check if it should execute.\n * Should return true to allow execution, false to block.\n * Applied on @Stoat classes to guard all contained @SimpleCommand methods.\n *\n * @example\n * ```ts\n * import { Guard, Stoat, SimpleCommand, CommandContext } from 'stoatx';\n *\n * // Define a guard\n * class NotBot implements StoatxGuard {\n * run(ctx: CommandContext): boolean {\n * return !ctx.message.author.bot;\n * }\n *\n * guardFail(ctx: CommandContext): void {\n * ctx.reply(\"Bots cannot use this command!\");\n * }\n * }\n *\n * @Stoat()\n * @Guard(NotBot)\n * class AdminCommands {\n * @SimpleCommand({ name: 'admin', description: 'Admin only command' })\n * async admin(ctx: CommandContext) {\n * ctx.reply(\"You passed the guard check!\");\n * }\n * }\n * ```\n */\nexport function Guard(guardClass: Function): ClassDecorator {\n return (target: Function) => {\n const existingGuards: Function[] = Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];\n existingGuards.push(guardClass);\n Reflect.defineMetadata(METADATA_KEYS.GUARDS, existingGuards, target);\n };\n}\n\n/**\n * Get all guards from a decorated class\n */\nexport function getGuards(target: Function): Function[] {\n return Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];\n}\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\n\nexport interface EventDefinition {\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\nfunction createEventDecorator(event: string, type: \"on\" | \"once\"): MethodDecorator {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n\n // Retrieve existing events or initialize a fresh array\n const existingEvents: EventDefinition[] = Reflect.getMetadata(METADATA_KEYS.EVENTS, constructor) || [];\n\n existingEvents.push({\n methodName: String(propertyKey),\n event,\n type,\n });\n\n Reflect.defineMetadata(METADATA_KEYS.EVENTS, existingEvents, constructor);\n\n return descriptor;\n };\n}\n\n/**\n * @On\n * Triggered on every occurrence of the event.\n * Marks a method to be executed whenever the specified client event is emitted.\n *\n * @example\n * ```ts\n * import { Stoat, On } from 'stoatx';\n * import { Message, Client } from 'stoat.js';\n *\n * @Stoat()\n * class BotEvents {\n * @On('messageCreate')\n * async onMessage(message: Message, client: Client) {\n * console.log('New message received:', message.content);\n * }\n * }\n * ```\n *\n * @param event The name of the client event to listen to\n */\nexport function On(event: string): MethodDecorator {\n return createEventDecorator(event, \"on\");\n}\n\n/**\n * @Once\n * Triggered only fully once.\n * Marks a method to be executed only the FIRST time the specified client event is emitted.\n *\n * @example\n * ```ts\n * import { Stoat, Once } from 'stoatx';\n * import { Client } from 'stoat.js';\n *\n * @Stoat()\n * class BotEvents {\n * @Once('ready')\n * async onReady(client: Client) {\n * console.log('Bot successfully started and logged in!');\n * }\n * }\n * ```\n *\n * @param event The name of the client event to listen to\n */\nexport function Once(event: string): MethodDecorator {\n return createEventDecorator(event, \"once\");\n}\n\n/**\n * Get all event definitions from a @Stoat class\n */\nexport function getEventsMetadata(target: Function): EventDefinition[] {\n return Reflect.getMetadata(METADATA_KEYS.EVENTS, target) || [];\n}\n","import type { CommandMetadata, SimpleCommandOptions } from \"../types\";\n\n/**\n * Build CommandMetadata from SimpleCommandOptions\n */\nexport function buildSimpleCommandMetadata(\n options: SimpleCommandOptions,\n methodName: string,\n category?: string,\n): CommandMetadata {\n return {\n name: options.name ?? methodName.toLowerCase(),\n description: options.description ?? \"No description provided\",\n aliases: options.aliases ?? [],\n permissions: options.permissions ?? [],\n category: options.category ?? category ?? \"uncategorized\",\n cooldown: options.cooldown ?? 0,\n nsfw: options.nsfw ?? false,\n ownerOnly: options.ownerOnly ?? false,\n };\n}\n","import * as path from \"node:path\";\nimport * as fs from \"node:fs/promises\";\nimport { pathToFileURL } from \"node:url\";\nimport { glob } from \"tinyglobby\";\nimport { buildSimpleCommandMetadata, getSimpleCommands, getEventsMetadata } from \"./decorators\";\nimport { decoratorStore } from \"./decorators/store\";\nimport type { CommandMetadata } from \"./types\";\n\ninterface AutoDiscoveryOptions {\n roots?: string[];\n include?: string[];\n ignore?: string[];\n}\n\n/**\n * Stored command entry from @Stoat/@SimpleCommand registration.\n */\nexport interface RegisteredCommand {\n /** Instance of the @Stoat class */\n instance: object;\n /** Command metadata */\n metadata: CommandMetadata;\n /** Method name to call */\n methodName: string;\n /** The original class constructor (for guard validation) */\n classConstructor: Function;\n}\n\n/**\n * Stored event entry from @On/@Once registration.\n */\nexport interface RegisteredEvent {\n instance: object;\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\n/**\n * CommandRegistry - Scans directories and stores commands in a Map\n *\n * @example\n * ```ts\n * const registry = new CommandRegistry();\n * await registry.loadFromDirectory('./src/commands');\n *\n * const ping = registry.get('ping');\n * const allCommands = registry.getAll();\n * ```\n */\nexport class CommandRegistry {\n private static readonly DEFAULT_AUTO_DISCOVERY_IGNORES = [\n \"**/node_modules/**\",\n \"**/.git/**\",\n \"**/*.d.ts\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n ];\n\n private readonly commands: Map<string, RegisteredCommand> = new Map();\n private readonly aliases: Map<string, string> = new Map();\n private readonly registeredEvents: RegisteredEvent[] = [];\n private readonly extensions: string[];\n private readonly processedStoatClasses: Set<Function> = new Set();\n\n constructor(extensions: string[] = [\".js\", \".mjs\", \".cjs\"]) {\n this.extensions = extensions;\n }\n\n /**\n * Get the number of registered commands\n */\n get size(): number {\n return this.commands.size;\n }\n\n /**\n * Load commands from a directory using glob pattern matching\n */\n async loadFromDirectory(directory: string): Promise<void> {\n const patterns = this.extensions.map((ext) => path.join(directory, \"**\", `*${ext}`).replace(/\\\\/g, \"/\"));\n\n for (const pattern of patterns) {\n const files = await glob(pattern, {\n ignore: [\"**/*.d.ts\", \"**/*.test.ts\", \"**/*.spec.ts\"],\n absolute: true,\n });\n\n for (const file of files) {\n await this.loadFile(file, directory);\n }\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n /**\n * Auto-discover command files across one or more roots.\n */\n async autoDiscover(options: AutoDiscoveryOptions = {}): Promise<void> {\n const roots = options.roots?.length ? options.roots : [process.cwd()];\n const includePatterns = options.include?.length ? options.include : this.getDefaultAutoDiscoveryPatterns();\n\n const patterns = roots.flatMap((root) =>\n includePatterns.map((pattern) => path.join(root, pattern).replace(/\\\\/g, \"/\")),\n );\n\n const files = await glob(patterns, {\n ignore: [...CommandRegistry.DEFAULT_AUTO_DISCOVERY_IGNORES, ...(options.ignore ?? [])],\n absolute: true,\n });\n\n const uniqueFiles = [...new Set(files)];\n let candidateFiles = 0;\n for (const file of uniqueFiles) {\n if (!(await this.isLikelyCommandModule(file))) {\n continue;\n }\n candidateFiles++;\n\n const baseDir =\n roots.find((root) => {\n const relative = path.relative(root, file);\n return relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n }) ?? roots[0]!;\n await this.loadFile(file, baseDir);\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n private getDefaultAutoDiscoveryPatterns(): string[] {\n // discordx-like default: scan broadly, then register only decorated classes\n return this.extensions.map((ext) => `**/*${ext}`);\n }\n\n private async isLikelyCommandModule(filePath: string): Promise<boolean> {\n try {\n const source = await fs.readFile(filePath, \"utf8\");\n return source.includes(\"Stoat\") || source.includes(\"SimpleCommand\") || source.includes(\"stoatx:command\");\n } catch {\n // If the file can't be pre-read, fall back to attempting import.\n return true;\n }\n }\n\n /**\n * Register a command instance\n */\n register(instance: object, metadata: CommandMetadata, classConstructor: Function, methodName: string): void {\n const name = metadata.name.toLowerCase();\n\n if (this.commands.has(name)) {\n console.warn(`[Stoatx] Duplicate command name: ${name}. Skipping...`);\n return;\n }\n\n this.validateGuards(classConstructor, metadata.name);\n\n this.commands.set(name, { instance, metadata, methodName, classConstructor });\n\n for (const alias of metadata.aliases) {\n const aliasLower = alias.toLowerCase();\n if (this.aliases.has(aliasLower) || this.commands.has(aliasLower)) {\n console.warn(`[Stoatx] Duplicate alias: ${aliasLower}. Skipping...`);\n continue;\n }\n this.aliases.set(aliasLower, name);\n }\n }\n\n /**\n * Get a command by name or alias\n */\n get(name: string): RegisteredCommand | undefined {\n const lowerName = name.toLowerCase();\n const resolvedName = this.aliases.get(lowerName) ?? lowerName;\n return this.commands.get(resolvedName);\n }\n\n /**\n * Check if a command exists\n */\n has(name: string): boolean {\n const lowerName = name.toLowerCase();\n return this.commands.has(lowerName) || this.aliases.has(lowerName);\n }\n\n /**\n * Get all registered commands\n */\n getAll(): RegisteredCommand[] {\n return Array.from(this.commands.values());\n }\n\n /**\n * Get all command metadata\n */\n getAllMetadata(): CommandMetadata[] {\n return this.getAll().map((c) => c.metadata);\n }\n\n /**\n * Get all registered events\n */\n getEvents(): RegisteredEvent[] {\n return this.registeredEvents;\n }\n\n /**\n * Get commands grouped by category\n */\n getByCategory(): Map<string, RegisteredCommand[]> {\n const categories = new Map<string, RegisteredCommand[]>();\n\n for (const cmd of this.commands.values()) {\n const category = cmd.metadata.category;\n const existing = categories.get(category) ?? [];\n existing.push(cmd);\n categories.set(category, existing);\n }\n\n return categories;\n }\n\n /**\n * Clear all commands\n */\n clear(): void {\n this.commands.clear();\n this.aliases.clear();\n this.registeredEvents.length = 0;\n this.processedStoatClasses.clear();\n }\n\n /**\n * Iterate over commands\n */\n [Symbol.iterator](): IterableIterator<[string, RegisteredCommand]> {\n return this.commands.entries();\n }\n\n /**\n * Iterate over command values\n */\n values(): IterableIterator<RegisteredCommand> {\n return this.commands.values();\n }\n\n /**\n * Iterate over command names\n */\n keys(): IterableIterator<string> {\n return this.commands.keys();\n }\n\n /**\n * Validate that all guards on a command implement the required methods\n * @param commandClass\n * @param commandName\n * @private\n */\n private validateGuards(commandClass: Function, commandName: string): void {\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", commandClass) || [];\n\n for (const GuardClass of guards) {\n const guardInstance = new (GuardClass as any)();\n\n if (typeof guardInstance.run !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a run() method.`,\n );\n process.exit(1);\n }\n\n if (typeof guardInstance.guardFail !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a guardFail() method.`,\n );\n console.error(`[Stoatx] All guards must implement guardFail() to handle failed checks.`);\n process.exit(1);\n }\n }\n }\n\n /**\n * Load commands from a single file\n */\n private async loadFile(filePath: string, baseDir: string): Promise<void> {\n try {\n const knownStoatClasses = new Set(decoratorStore.getStoatClasses().keys());\n const fileUrl = pathToFileURL(filePath).href;\n await import(fileUrl);\n\n const allStoatClasses = decoratorStore.getStoatClasses();\n for (const [stoatClass, stoatInstance] of allStoatClasses.entries()) {\n if (knownStoatClasses.has(stoatClass) || this.processedStoatClasses.has(stoatClass)) {\n continue;\n }\n this.registerStoatClassCommands(stoatClass, stoatInstance, filePath, baseDir);\n }\n } catch (error) {\n console.error(`[Stoatx] Failed to load command file: ${filePath}`, error);\n }\n }\n\n private registerStoatClassCommands(stoatClass: Function, instance: object, filePath: string, baseDir: string): void {\n const simpleCommands = getSimpleCommands(stoatClass);\n const events = getEventsMetadata(stoatClass);\n const category = this.getCategoryFromPath(filePath, baseDir);\n\n if (simpleCommands.length === 0 && events.length === 0) {\n console.warn(\n `[Stoatx] Class ${stoatClass.name} is decorated with @Stoat but has no @SimpleCommand, @On or @Once methods. Skipping...`,\n );\n this.processedStoatClasses.add(stoatClass);\n return;\n }\n\n for (const cmdDef of simpleCommands) {\n const method = (instance as any)[cmdDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${cmdDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n const metadata = buildSimpleCommandMetadata(cmdDef.options, cmdDef.methodName, category);\n this.register(instance, metadata, stoatClass, cmdDef.methodName);\n }\n\n for (const eventDef of events) {\n const method = (instance as any)[eventDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${eventDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n this.registeredEvents.push({\n instance,\n methodName: eventDef.methodName,\n event: eventDef.event,\n type: eventDef.type,\n });\n }\n\n this.processedStoatClasses.add(stoatClass);\n }\n\n /**\n * Derive category from file path relative to base directory\n */\n private getCategoryFromPath(filePath: string, baseDir: string): string | undefined {\n const relative = path.relative(baseDir, filePath);\n const parts = relative.split(path.sep);\n\n if (parts.length > 1) {\n return parts[0];\n }\n\n return undefined;\n }\n}\n","import \"reflect-metadata\";\nimport { CommandRegistry, RegisteredCommand } from \"./registry\";\nimport type { CommandContext, CommandMetadata, StoatxDiscoveryOptions, StoatxHandlerOptions } from \"./types\";\nimport { Client as StoatClient, ClientEvents, Message } from \"@stoatx/client\";\n\n/**\n * Client - An extended Client that integrates StoatxHandler directly\n *\n * @example\n * ```ts\n * import { Client } from 'stoatx';\n *\n * const client = new Client({\n * prefix: '!',\n * owners: ['owner-user-id'],\n * });\n *\n * await client.initCommands();\n * ```\n */\nexport class Client extends StoatClient {\n public readonly handler: StoatxHandler;\n\n constructor(options: Omit<StoatxHandlerOptions, \"client\">) {\n super();\n this.handler = new StoatxHandler({ ...options, client: this });\n\n // Automatically hook up the message handler\n this.on(\"messageCreate\", async (message) => {\n await this.handler.handle(message);\n });\n }\n\n /**\n * Initialize the StoatxHandler commands\n */\n async initCommands(): Promise<void> {\n await this.handler.init();\n }\n}\n\n/**\n * StoatxHandler - The execution engine for commands\n *\n * Handles message parsing, middleware execution, and command dispatching\n *\n * @internal This class is not intended to be instantiated directly. Use the `Client` from `stoatx` instead.\n */\nexport class StoatxHandler {\n private readonly commandsDir: string | undefined;\n private readonly discoveryOptions: StoatxDiscoveryOptions | undefined;\n private readonly prefixResolver: string | ((ctx: { serverId?: string | undefined }) => string | Promise<string>);\n private readonly owners: Set<string>;\n private readonly registry: CommandRegistry;\n private readonly cooldowns: Map<string, Map<string, number>> = new Map();\n private readonly disableMentionPrefix: boolean;\n private readonly client: StoatClient;\n constructor(options: StoatxHandlerOptions) {\n this.client = options.client;\n this.commandsDir = options.commandsDir;\n this.discoveryOptions = options.discovery;\n this.prefixResolver = options.prefix;\n this.owners = new Set(options.owners ?? []);\n this.registry = new CommandRegistry(options.extensions);\n this.disableMentionPrefix = options.disableMentionPrefix ?? false;\n }\n\n /**\n * Initialize the handler - load all commands\n */\n async init(): Promise<void> {\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n } else {\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n this.attachEvents();\n }\n\n /**\n * Attach registered events to the client\n */\n private attachEvents(): void {\n const events = this.registry.getEvents();\n\n for (const eventDef of events) {\n const handler = async (...args: any[]) => {\n try {\n await (eventDef.instance as any)[eventDef.methodName](...args, this.client);\n } catch (error) {\n console.error(\n `[Stoatx] Event Handler Error in @${eventDef.type === \"on\" ? \"On\" : \"Once\"}('${eventDef.event}'):`,\n error,\n );\n }\n };\n\n const eventName = eventDef.event as keyof ClientEvents;\n if (eventDef.type === \"once\") {\n this.client.once(eventName, handler);\n } else {\n this.client.on(eventName, handler);\n }\n }\n }\n\n /**\n * Parse a raw message into command context\n */\n async parseMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<CommandContext | null> {\n const prefix = await this.resolvePrefix(meta.serverId);\n let usedPrefix = prefix;\n let withoutPrefix = \"\";\n\n // Check for string prefix\n if (rawContent.startsWith(prefix)) {\n withoutPrefix = rawContent.slice(prefix.length).trim();\n usedPrefix = prefix;\n }\n // Check for mention prefix (e.g., \"<@bot-id> command\") - unless disabled\n else if (!this.disableMentionPrefix && rawContent.match(/^<@!?[\\w]+>/)) {\n const mentionMatch = rawContent.match(/^<@!?([\\w]+)>\\s*/);\n if (mentionMatch) {\n const mentionedId = mentionMatch[1];\n const botId = this.client.user?.id;\n\n // Only process if mentioned user is the bot\n if (botId && mentionedId === botId) {\n usedPrefix = mentionMatch[0];\n withoutPrefix = rawContent.slice(mentionMatch[0].length).trim();\n } else {\n }\n }\n }\n\n if (!withoutPrefix) {\n return null;\n }\n\n const [commandName, ...args] = withoutPrefix.split(/\\s+/);\n\n if (!commandName) {\n return null;\n }\n\n return {\n client: this.client,\n content: rawContent,\n authorId: meta.authorId,\n channelId: meta.channelId,\n serverId: meta.serverId,\n args,\n prefix: usedPrefix,\n commandName: commandName.toLowerCase(),\n reply: meta.reply,\n message,\n };\n }\n\n /**\n * Handle a message object using the configured message adapter\n *\n * @example\n * ```ts\n * // With message adapter configured\n * client.on('messageCreate', (message) => {\n * handler.handle(message);\n * });\n * ```\n */\n async handle(message: Message): Promise<boolean> {\n if (!message.channel || !message.author) {\n return false;\n }\n\n // Skip messages from bots\n if (message.author.bot) {\n return false;\n }\n\n const rawContent = message.content;\n const authorId = message.author.id;\n const channelId = message.channel.id;\n const serverId = message.server?.id;\n const reply = async (content: string) => {\n return await message.channel!.send(content);\n };\n\n // rawContent won't be null since a command will be invoked with a prefix\n await this.handleMessage(rawContent!, message, {\n authorId,\n channelId,\n serverId,\n reply,\n });\n\n return true;\n }\n\n /**\n * Handle a raw message string with metadata\n *\n * @example\n * ```ts\n * // Manual usage without message adapter\n * client.on('messageCreate', (message) => {\n * handler.handleMessage(message.content, message, {\n * authorId: message.author.id,\n * channelId: message.channel.id,\n * serverId: message.server?.id,\n * reply: (content) => message.channel.sendMessage(content),\n * });\n * });\n * ```\n */\n async handleMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<void> {\n const ctx = await this.parseMessage(rawContent, message, meta);\n\n if (!ctx) {\n return;\n }\n\n await this.execute(ctx);\n }\n\n /**\n * Execute a command with the given context\n */\n async execute(ctx: CommandContext): Promise<boolean> {\n const registered = this.registry.get(ctx.commandName);\n\n if (!registered) {\n return false;\n }\n\n const { instance, metadata, methodName, classConstructor } = registered;\n\n // Owner-only check\n if (metadata.ownerOnly && !this.owners.has(ctx.authorId)) {\n await ctx.reply(\"This command is owner-only.\");\n return false;\n }\n\n // Guard checks - use classConstructor for guard metadata\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", classConstructor) || [];\n for (const guardClass of guards) {\n const guardInstance = new (guardClass as any)();\n if (typeof guardInstance.run === \"function\") {\n const guardResult = await guardInstance.run(ctx);\n if (!guardResult) {\n if (typeof guardInstance.guardFail === \"function\") {\n await guardInstance.guardFail(ctx);\n } else {\n console.error(\"[Stoatx] Guard check failed but no guardFail method defined on\", guardClass.name);\n }\n return false;\n }\n }\n }\n\n // Cooldown check\n if (!this.checkCooldown(ctx.authorId, metadata)) {\n const remaining = this.getRemainingCooldown(ctx.authorId, metadata);\n\n // For method-based commands, check if instance has onCooldown\n if (typeof (instance as any).onCooldown === \"function\") {\n await (instance as any).onCooldown(ctx, remaining);\n } else {\n await ctx.reply(`Please wait ${(remaining / 1000).toFixed(1)} seconds before using this command again.`);\n }\n return false;\n }\n\n try {\n // Set cooldown before execution to prevent concurrent executions\n if (metadata.cooldown > 0) {\n this.setCooldown(ctx.authorId, metadata);\n }\n\n await (instance as any)[methodName](ctx);\n\n return true;\n } catch (error) {\n // Handle errors\n if (typeof (instance as any).onError === \"function\") {\n await (instance as any).onError(ctx, error as Error);\n } else {\n console.error(`[Stoatx] Error in command ${metadata.name}:`, error);\n }\n return false;\n }\n }\n\n /**\n * Get the command registry\n */\n getRegistry(): CommandRegistry {\n return this.registry;\n }\n\n /**\n * Get a command by name or alias\n */\n getCommand(name: string): RegisteredCommand | undefined {\n return this.registry.get(name);\n }\n\n /**\n * Get all commands\n */\n getCommands(): RegisteredCommand[] {\n return this.registry.getAll();\n }\n\n /**\n * Reload all commands\n */\n async reload(): Promise<void> {\n this.registry.clear();\n this.cooldowns.clear();\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n return;\n }\n\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n /**\n * Check if a user is an owner\n */\n isOwner(userId: string): boolean {\n return this.owners.has(userId);\n }\n\n /**\n * Add an owner\n */\n addOwner(userId: string): void {\n this.owners.add(userId);\n }\n\n /**\n * Remove an owner\n */\n removeOwner(userId: string): void {\n this.owners.delete(userId);\n }\n\n /**\n * Resolve the prefix for a context\n */\n private async resolvePrefix(serverId?: string | undefined): Promise<string> {\n if (typeof this.prefixResolver === \"function\") {\n return this.prefixResolver({ serverId });\n }\n return this.prefixResolver;\n }\n\n /**\n * Check if user is on cooldown\n */\n private checkCooldown(userId: string, metadata: CommandMetadata): boolean {\n if (metadata.cooldown <= 0) return true;\n\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return true;\n\n const expirationTime = commandCooldowns.get(userId);\n if (!expirationTime) return true;\n\n if (Date.now() > expirationTime) {\n commandCooldowns.delete(userId);\n return true;\n }\n\n return false;\n }\n\n /**\n * Get remaining cooldown time in ms\n */\n private getRemainingCooldown(userId: string, metadata: CommandMetadata): number {\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return 0;\n\n const userCooldown = commandCooldowns.get(userId);\n if (!userCooldown) return 0;\n\n return Math.max(0, userCooldown - Date.now());\n }\n\n /**\n * Set cooldown for a user\n */\n private setCooldown(userId: string, metadata: CommandMetadata): void {\n if (!this.cooldowns.has(metadata.name)) {\n this.cooldowns.set(metadata.name, new Map());\n }\n\n const commandCooldowns = this.cooldowns.get(metadata.name)!;\n commandCooldowns.set(userId, Date.now() + metadata.cooldown);\n }\n}\n"],"mappings":"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","names":["import_reflect_metadata","import_reflect_metadata","import_reflect_metadata","relative","import_reflect_metadata","StoatClient"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/decorators/Stoat.ts","../src/decorators/keys.ts","../src/decorators/store.ts","../src/decorators/SimpleCommand.ts","../src/decorators/Guard.ts","../src/decorators/Events.ts","../src/decorators/utils.ts","../src/registry.ts","../src/handler.ts"],"sourcesContent":["// Types\nexport * from \"./types\";\n\n// Decorators\nexport * from \"./decorators\";\n\n// Registry\nexport * from \"./registry\";\n\n// Handler\nexport { Client, DefaultCooldownManager } from \"./handler\";\nexport type { StoatxHandler } from \"./handler\";\nexport * from \"@stoatx/client\";\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\nimport { decoratorStore } from \"./store\";\n\n/**\n * @Stoat\n * Marks a class as a Stoat command container.\n * Use this decorator on classes that contain @SimpleCommand methods.\n *\n * @example\n * ```ts\n * import { Stoat, SimpleCommand, CommandContext } from 'stoatx';\n *\n * @Stoat()\n * class ModerationCommands {\n * @SimpleCommand({ name: 'ban', description: 'Ban a user' })\n * async ban(ctx: CommandContext) {\n * await ctx.reply('User banned!');\n * }\n *\n * @SimpleCommand({ name: 'kick', description: 'Kick a user' })\n * async kick(ctx: CommandContext) {\n * await ctx.reply('User kicked!');\n * }\n * }\n * ```\n */\nexport function Stoat(): ClassDecorator {\n return (target: Function) => {\n Reflect.defineMetadata(METADATA_KEYS.IS_STOAT_CLASS, true, target);\n decoratorStore.registerStoatClass(target);\n };\n}\n\n/**\n * Check if a class is decorated with @Stoat\n */\nexport function isStoatClass(target: Function): boolean {\n return Reflect.getMetadata(METADATA_KEYS.IS_STOAT_CLASS, target) === true;\n}\n","/**\n * Metadata keys used by decorators\n */\nexport const METADATA_KEYS = {\n IS_STOAT_CLASS: Symbol(\"stoatx:stoat:isClass\"),\n SIMPLE_COMMANDS: Symbol(\"stoatx:stoat:simpleCommands\"),\n GUARDS: \"stoatx:command:guards\",\n EVENTS: Symbol(\"stoatx:stoat:events\"),\n} as const;\n","import type { RegisteredCommand } from \"../registry\";\n\n/**\n * Global store for all decorated classes and commands\n * This allows automatic registration without directory scanning\n */\nexport class DecoratorStore {\n private static instance: DecoratorStore;\n\n /** Stoat classes with their SimpleCommand methods */\n private stoatClasses: Map<Function, object> = new Map();\n\n /** Registered commands from @Stoat/@SimpleCommand decorators */\n private commands: RegisteredCommand[] = [];\n\n /** Whether the store has been initialized */\n private initialized = false;\n\n private constructor() {}\n\n static getInstance(): DecoratorStore {\n if (!DecoratorStore.instance) {\n DecoratorStore.instance = new DecoratorStore();\n }\n return DecoratorStore.instance;\n }\n\n /**\n * Register a @Stoat decorated class\n */\n registerStoatClass(classConstructor: Function): void {\n if (!this.stoatClasses.has(classConstructor)) {\n // Create instance immediately when decorated\n const instance = new (classConstructor as new () => object)();\n this.stoatClasses.set(classConstructor, instance);\n }\n }\n\n /**\n * Get all registered Stoat classes with their instances\n */\n getStoatClasses(): Map<Function, object> {\n return this.stoatClasses;\n }\n\n /**\n * Add a registered command\n */\n addCommand(command: RegisteredCommand): void {\n this.commands.push(command);\n }\n\n /**\n * Get all registered commands\n */\n getCommands(): RegisteredCommand[] {\n return this.commands;\n }\n\n /**\n * Clear all registered classes (useful for testing)\n */\n clear(): void {\n this.stoatClasses.clear();\n this.commands = [];\n this.initialized = false;\n }\n\n /**\n * Mark as initialized\n */\n markInitialized(): void {\n this.initialized = true;\n }\n\n /**\n * Check if initialized\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n}\n\nexport const decoratorStore = DecoratorStore.getInstance();\n","import \"reflect-metadata\";\nimport type { SimpleCommandOptions } from \"../types\";\nimport { METADATA_KEYS } from \"./keys\";\n\n/**\n * Stored simple command metadata from method decorator\n */\nexport interface SimpleCommandDefinition {\n methodName: string;\n options: SimpleCommandOptions;\n}\n\n/**\n * @SimpleCommand\n * Marks a method as a simple command within a @Stoat() decorated class.\n *\n * @example\n * ```ts\n * @Stoat()\n * class Example {\n * @SimpleCommand({ name: 'ping', description: 'Replies with Pong!' })\n * async ping(ctx: CommandContext) {\n * await ctx.reply('Pong!');\n * }\n *\n * @SimpleCommand({ aliases: ['perm'], name: 'permission' })\n * async permission(ctx: CommandContext) {\n * await ctx.reply('Access granted');\n * }\n * }\n * ```\n */\nexport function SimpleCommand(options: SimpleCommandOptions = {}): MethodDecorator {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n\n // Get existing simple commands or create new array\n const existingCommands: SimpleCommandDefinition[] =\n Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, constructor) || [];\n\n // Add this command definition\n existingCommands.push({\n methodName: String(propertyKey),\n options,\n });\n\n Reflect.defineMetadata(METADATA_KEYS.SIMPLE_COMMANDS, existingCommands, constructor);\n\n return descriptor;\n };\n}\n\n/**\n * Get all simple command definitions from a @Stoat class\n */\nexport function getSimpleCommands(target: Function): SimpleCommandDefinition[] {\n return Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, target) || [];\n}\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\n\n/**\n * @Guard\n * Runs before a command to check if it should execute.\n * Should return true to allow execution, false to block.\n * Applied on @Stoat classes to guard all contained @SimpleCommand methods.\n *\n * @example\n * ```ts\n * import { Guard, Stoat, SimpleCommand, CommandContext } from 'stoatx';\n *\n * // Define a guard\n * class NotBot implements StoatxGuard {\n * run(ctx: CommandContext): boolean {\n * return !ctx.message.author.bot;\n * }\n *\n * guardFail(ctx: CommandContext): void {\n * ctx.reply(\"Bots cannot use this command!\");\n * }\n * }\n *\n * @Stoat()\n * @Guard(NotBot)\n * class AdminCommands {\n * @SimpleCommand({ name: 'admin', description: 'Admin only command' })\n * async admin(ctx: CommandContext) {\n * ctx.reply(\"You passed the guard check!\");\n * }\n * }\n * ```\n */\nexport function Guard(guardClass: Function): ClassDecorator {\n return (target: Function) => {\n const existingGuards: Function[] = Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];\n existingGuards.push(guardClass);\n Reflect.defineMetadata(METADATA_KEYS.GUARDS, existingGuards, target);\n };\n}\n\n/**\n * Get all guards from a decorated class\n */\nexport function getGuards(target: Function): Function[] {\n return Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];\n}\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\n\nexport interface EventDefinition {\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\nfunction createEventDecorator(event: string, type: \"on\" | \"once\"): MethodDecorator {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n\n // Retrieve existing events or initialize a fresh array\n const existingEvents: EventDefinition[] = Reflect.getMetadata(METADATA_KEYS.EVENTS, constructor) || [];\n\n existingEvents.push({\n methodName: String(propertyKey),\n event,\n type,\n });\n\n Reflect.defineMetadata(METADATA_KEYS.EVENTS, existingEvents, constructor);\n\n return descriptor;\n };\n}\n\n/**\n * @On\n * Triggered on every occurrence of the event.\n * Marks a method to be executed whenever the specified client event is emitted.\n *\n * @example\n * ```ts\n * import { Stoat, On } from 'stoatx';\n * import { Message, Client } from 'stoat.js';\n *\n * @Stoat()\n * class BotEvents {\n * @On('messageCreate')\n * async onMessage(message: Message, client: Client) {\n * console.log('New message received:', message.content);\n * }\n * }\n * ```\n *\n * @param event The name of the client event to listen to\n */\nexport function On(event: string): MethodDecorator {\n return createEventDecorator(event, \"on\");\n}\n\n/**\n * @Once\n * Triggered only fully once.\n * Marks a method to be executed only the FIRST time the specified client event is emitted.\n *\n * @example\n * ```ts\n * import { Stoat, Once } from 'stoatx';\n * import { Client } from 'stoat.js';\n *\n * @Stoat()\n * class BotEvents {\n * @Once('ready')\n * async onReady(client: Client) {\n * console.log('Bot successfully started and logged in!');\n * }\n * }\n * ```\n *\n * @param event The name of the client event to listen to\n */\nexport function Once(event: string): MethodDecorator {\n return createEventDecorator(event, \"once\");\n}\n\n/**\n * Get all event definitions from a @Stoat class\n */\nexport function getEventsMetadata(target: Function): EventDefinition[] {\n return Reflect.getMetadata(METADATA_KEYS.EVENTS, target) || [];\n}\n","import type { CommandMetadata, SimpleCommandOptions } from \"../types\";\n\n/**\n * Build CommandMetadata from SimpleCommandOptions\n */\nexport function buildSimpleCommandMetadata(\n options: SimpleCommandOptions,\n methodName: string,\n category?: string,\n): CommandMetadata {\n return {\n name: options.name ?? methodName.toLowerCase(),\n description: options.description ?? \"No description provided\",\n aliases: options.aliases ?? [],\n permissions: options.permissions ?? [],\n category: options.category ?? category ?? \"uncategorized\",\n cooldown: options.cooldown ?? 0,\n ...(options.cooldownStorage !== undefined ? { cooldownStorage: options.cooldownStorage } : {}),\n nsfw: options.nsfw ?? false,\n ownerOnly: options.ownerOnly ?? false,\n };\n}\n","import * as path from \"node:path\";\nimport * as fs from \"node:fs/promises\";\nimport { pathToFileURL } from \"node:url\";\nimport { glob } from \"tinyglobby\";\nimport { buildSimpleCommandMetadata, getSimpleCommands, getEventsMetadata } from \"./decorators\";\nimport { decoratorStore } from \"./decorators/store\";\nimport type { CommandMetadata } from \"./types\";\n\ninterface AutoDiscoveryOptions {\n roots?: string[];\n include?: string[];\n ignore?: string[];\n}\n\n/**\n * Stored command entry from @Stoat/@SimpleCommand registration.\n */\nexport interface RegisteredCommand {\n /** Instance of the @Stoat class */\n instance: object;\n /** Command metadata */\n metadata: CommandMetadata;\n /** Method name to call */\n methodName: string;\n /** The original class constructor (for guard validation) */\n classConstructor: Function;\n}\n\n/**\n * Stored event entry from @On/@Once registration.\n */\nexport interface RegisteredEvent {\n instance: object;\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\n/**\n * CommandRegistry - Scans directories and stores commands in a Map\n *\n * @example\n * ```ts\n * const registry = new CommandRegistry();\n * await registry.loadFromDirectory('./src/commands');\n *\n * const ping = registry.get('ping');\n * const allCommands = registry.getAll();\n * ```\n */\nexport class CommandRegistry {\n private static readonly DEFAULT_AUTO_DISCOVERY_IGNORES = [\n \"**/node_modules/**\",\n \"**/.git/**\",\n \"**/*.d.ts\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n ];\n\n private readonly commands: Map<string, RegisteredCommand> = new Map();\n private readonly aliases: Map<string, string> = new Map();\n private readonly registeredEvents: RegisteredEvent[] = [];\n private readonly extensions: string[];\n private readonly processedStoatClasses: Set<Function> = new Set();\n\n constructor(extensions: string[] = [\".js\", \".mjs\", \".cjs\"]) {\n this.extensions = extensions;\n }\n\n /**\n * Get the number of registered commands\n */\n get size(): number {\n return this.commands.size;\n }\n\n /**\n * Load commands from a directory using glob pattern matching\n */\n async loadFromDirectory(directory: string): Promise<void> {\n const patterns = this.extensions.map((ext) => path.join(directory, \"**\", `*${ext}`).replace(/\\\\/g, \"/\"));\n\n for (const pattern of patterns) {\n const files = await glob(pattern, {\n ignore: [\"**/*.d.ts\", \"**/*.test.ts\", \"**/*.spec.ts\"],\n absolute: true,\n });\n\n for (const file of files) {\n await this.loadFile(file, directory);\n }\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n /**\n * Auto-discover command files across one or more roots.\n */\n async autoDiscover(options: AutoDiscoveryOptions = {}): Promise<void> {\n const roots = options.roots?.length ? options.roots : [process.cwd()];\n const includePatterns = options.include?.length ? options.include : this.getDefaultAutoDiscoveryPatterns();\n\n const patterns = roots.flatMap((root) =>\n includePatterns.map((pattern) => path.join(root, pattern).replace(/\\\\/g, \"/\")),\n );\n\n const files = await glob(patterns, {\n ignore: [...CommandRegistry.DEFAULT_AUTO_DISCOVERY_IGNORES, ...(options.ignore ?? [])],\n absolute: true,\n });\n\n const uniqueFiles = [...new Set(files)];\n let candidateFiles = 0;\n for (const file of uniqueFiles) {\n if (!(await this.isLikelyCommandModule(file))) {\n continue;\n }\n candidateFiles++;\n\n const baseDir =\n roots.find((root) => {\n const relative = path.relative(root, file);\n return relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n }) ?? roots[0]!;\n await this.loadFile(file, baseDir);\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n private getDefaultAutoDiscoveryPatterns(): string[] {\n // discordx-like default: scan broadly, then register only decorated classes\n return this.extensions.map((ext) => `**/*${ext}`);\n }\n\n private async isLikelyCommandModule(filePath: string): Promise<boolean> {\n try {\n const source = await fs.readFile(filePath, \"utf8\");\n return source.includes(\"Stoat\") || source.includes(\"SimpleCommand\") || source.includes(\"stoatx:command\");\n } catch {\n // If the file can't be pre-read, fall back to attempting import.\n return true;\n }\n }\n\n /**\n * Register a command instance\n */\n register(instance: object, metadata: CommandMetadata, classConstructor: Function, methodName: string): void {\n const name = metadata.name.toLowerCase();\n\n if (this.commands.has(name)) {\n console.warn(`[Stoatx] Duplicate command name: ${name}. Skipping...`);\n return;\n }\n\n this.validateGuards(classConstructor, metadata.name);\n\n this.commands.set(name, { instance, metadata, methodName, classConstructor });\n\n for (const alias of metadata.aliases) {\n const aliasLower = alias.toLowerCase();\n if (this.aliases.has(aliasLower) || this.commands.has(aliasLower)) {\n console.warn(`[Stoatx] Duplicate alias: ${aliasLower}. Skipping...`);\n continue;\n }\n this.aliases.set(aliasLower, name);\n }\n }\n\n /**\n * Get a command by name or alias\n */\n get(name: string): RegisteredCommand | undefined {\n const lowerName = name.toLowerCase();\n const resolvedName = this.aliases.get(lowerName) ?? lowerName;\n return this.commands.get(resolvedName);\n }\n\n /**\n * Check if a command exists\n */\n has(name: string): boolean {\n const lowerName = name.toLowerCase();\n return this.commands.has(lowerName) || this.aliases.has(lowerName);\n }\n\n /**\n * Get all registered commands\n */\n getAll(): RegisteredCommand[] {\n return Array.from(this.commands.values());\n }\n\n /**\n * Get all command metadata\n */\n getAllMetadata(): CommandMetadata[] {\n return this.getAll().map((c) => c.metadata);\n }\n\n /**\n * Get all registered events\n */\n getEvents(): RegisteredEvent[] {\n return this.registeredEvents;\n }\n\n /**\n * Get commands grouped by category\n */\n getByCategory(): Map<string, RegisteredCommand[]> {\n const categories = new Map<string, RegisteredCommand[]>();\n\n for (const cmd of this.commands.values()) {\n const category = cmd.metadata.category;\n const existing = categories.get(category) ?? [];\n existing.push(cmd);\n categories.set(category, existing);\n }\n\n return categories;\n }\n\n /**\n * Clear all commands\n */\n clear(): void {\n this.commands.clear();\n this.aliases.clear();\n this.registeredEvents.length = 0;\n this.processedStoatClasses.clear();\n }\n\n /**\n * Iterate over commands\n */\n [Symbol.iterator](): IterableIterator<[string, RegisteredCommand]> {\n return this.commands.entries();\n }\n\n /**\n * Iterate over command values\n */\n values(): IterableIterator<RegisteredCommand> {\n return this.commands.values();\n }\n\n /**\n * Iterate over command names\n */\n keys(): IterableIterator<string> {\n return this.commands.keys();\n }\n\n /**\n * Validate that all guards on a command implement the required methods\n * @param commandClass\n * @param commandName\n * @private\n */\n private validateGuards(commandClass: Function, commandName: string): void {\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", commandClass) || [];\n\n for (const GuardClass of guards) {\n const guardInstance = new (GuardClass as any)();\n\n if (typeof guardInstance.run !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a run() method.`,\n );\n process.exit(1);\n }\n\n if (typeof guardInstance.guardFail !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a guardFail() method.`,\n );\n console.error(`[Stoatx] All guards must implement guardFail() to handle failed checks.`);\n process.exit(1);\n }\n }\n }\n\n /**\n * Load commands from a single file\n */\n private async loadFile(filePath: string, baseDir: string): Promise<void> {\n try {\n const knownStoatClasses = new Set(decoratorStore.getStoatClasses().keys());\n const fileUrl = pathToFileURL(filePath).href;\n await import(fileUrl);\n\n const allStoatClasses = decoratorStore.getStoatClasses();\n for (const [stoatClass, stoatInstance] of allStoatClasses.entries()) {\n if (knownStoatClasses.has(stoatClass) || this.processedStoatClasses.has(stoatClass)) {\n continue;\n }\n this.registerStoatClassCommands(stoatClass, stoatInstance, filePath, baseDir);\n }\n } catch (error) {\n console.error(`[Stoatx] Failed to load command file: ${filePath}`, error);\n }\n }\n\n private registerStoatClassCommands(stoatClass: Function, instance: object, filePath: string, baseDir: string): void {\n const simpleCommands = getSimpleCommands(stoatClass);\n const events = getEventsMetadata(stoatClass);\n const category = this.getCategoryFromPath(filePath, baseDir);\n\n if (simpleCommands.length === 0 && events.length === 0) {\n console.warn(\n `[Stoatx] Class ${stoatClass.name} is decorated with @Stoat but has no @SimpleCommand, @On or @Once methods. Skipping...`,\n );\n this.processedStoatClasses.add(stoatClass);\n return;\n }\n\n for (const cmdDef of simpleCommands) {\n const method = (instance as any)[cmdDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${cmdDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n const metadata = buildSimpleCommandMetadata(cmdDef.options, cmdDef.methodName, category);\n this.register(instance, metadata, stoatClass, cmdDef.methodName);\n }\n\n for (const eventDef of events) {\n const method = (instance as any)[eventDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${eventDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n this.registeredEvents.push({\n instance,\n methodName: eventDef.methodName,\n event: eventDef.event,\n type: eventDef.type,\n });\n }\n\n this.processedStoatClasses.add(stoatClass);\n }\n\n /**\n * Derive category from file path relative to base directory\n */\n private getCategoryFromPath(filePath: string, baseDir: string): string | undefined {\n const relative = path.relative(baseDir, filePath);\n const parts = relative.split(path.sep);\n\n if (parts.length > 1) {\n return parts[0];\n }\n\n return undefined;\n }\n}\n","import \"reflect-metadata\";\nimport { CommandRegistry, RegisteredCommand } from \"./registry\";\nimport type {\n CommandContext,\n CommandMetadata,\n StoatxDiscoveryOptions,\n StoatxHandlerOptions,\n CooldownManager,\n} from \"./types\";\nimport { Client as StoatClient, ClientEvents, Message } from \"@stoatx/client\";\n\n/**\n * Default in-memory cooldown manager\n */\nexport class DefaultCooldownManager implements CooldownManager {\n private readonly cooldowns: Map<string, Map<string, number>> = new Map();\n\n check(ctx: CommandContext, metadata: CommandMetadata): boolean {\n if (metadata.cooldown <= 0) return true;\n\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return true;\n\n const expirationTime = commandCooldowns.get(ctx.authorId);\n if (!expirationTime) return true;\n\n if (Date.now() > expirationTime) {\n commandCooldowns.delete(ctx.authorId);\n return true;\n }\n\n return false;\n }\n\n getRemaining(ctx: CommandContext, metadata: CommandMetadata): number {\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return 0;\n\n const userCooldown = commandCooldowns.get(ctx.authorId);\n if (!userCooldown) return 0;\n\n return Math.max(0, userCooldown - Date.now());\n }\n\n set(ctx: CommandContext, metadata: CommandMetadata): void {\n if (!this.cooldowns.has(metadata.name)) {\n this.cooldowns.set(metadata.name, new Map());\n }\n\n const commandCooldowns = this.cooldowns.get(metadata.name)!;\n commandCooldowns.set(ctx.authorId, Date.now() + metadata.cooldown);\n }\n\n clear(): void {\n this.cooldowns.clear();\n }\n}\n\n/**\n * Client - An extended Client that integrates StoatxHandler directly\n *\n * @example\n * ```ts\n * import { Client } from 'stoatx';\n *\n * const client = new Client({\n * prefix: '!',\n * owners: ['owner-user-id'],\n * });\n *\n * await client.initCommands();\n * ```\n */\nexport class Client extends StoatClient {\n public readonly handler: StoatxHandler;\n\n constructor(options: Omit<StoatxHandlerOptions, \"client\">) {\n super();\n this.handler = new StoatxHandler({ ...options, client: this });\n\n // Automatically hook up the message handler\n this.on(\"messageCreate\", async (message) => {\n await this.handler.handle(message);\n });\n }\n\n /**\n * Initialize the StoatxHandler commands\n */\n async initCommands(): Promise<void> {\n await this.handler.init();\n }\n}\n\n/**\n * StoatxHandler - The execution engine for commands\n *\n * Handles message parsing, middleware execution, and command dispatching\n *\n * @internal This class is not intended to be instantiated directly. Use the `Client` from `stoatx` instead.\n */\nexport class StoatxHandler {\n private readonly commandsDir: string | undefined;\n private readonly discoveryOptions: StoatxDiscoveryOptions | undefined;\n private readonly prefixResolver: string | ((ctx: { serverId?: string | undefined }) => string | Promise<string>);\n private readonly owners: Set<string>;\n private readonly registry: CommandRegistry;\n private readonly cooldownManager: CooldownManager;\n private readonly disableMentionPrefix: boolean;\n private readonly client: StoatClient;\n constructor(options: StoatxHandlerOptions) {\n this.client = options.client;\n this.commandsDir = options.commandsDir;\n this.discoveryOptions = options.discovery;\n this.prefixResolver = options.prefix;\n this.owners = new Set(options.owners ?? []);\n this.registry = new CommandRegistry(options.extensions);\n this.disableMentionPrefix = options.disableMentionPrefix ?? false;\n this.cooldownManager = options.cooldownManager ?? new DefaultCooldownManager();\n }\n\n /**\n * Initialize the handler - load all commands\n */\n async init(): Promise<void> {\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n } else {\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n this.attachEvents();\n }\n\n /**\n * Attach registered events to the client\n */\n private attachEvents(): void {\n const events = this.registry.getEvents();\n\n for (const eventDef of events) {\n const handler = async (...args: any[]) => {\n try {\n await (eventDef.instance as any)[eventDef.methodName](...args, this.client);\n } catch (error) {\n console.error(\n `[Stoatx] Event Handler Error in @${eventDef.type === \"on\" ? \"On\" : \"Once\"}('${eventDef.event}'):`,\n error,\n );\n }\n };\n\n const eventName = eventDef.event as keyof ClientEvents;\n if (eventDef.type === \"once\") {\n this.client.once(eventName, handler);\n } else {\n this.client.on(eventName, handler);\n }\n }\n }\n\n /**\n * Parse a raw message into command context\n */\n async parseMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<CommandContext | null> {\n const prefix = await this.resolvePrefix(meta.serverId);\n let usedPrefix = prefix;\n let withoutPrefix = \"\";\n\n // Check for string prefix\n if (rawContent.startsWith(prefix)) {\n withoutPrefix = rawContent.slice(prefix.length).trim();\n usedPrefix = prefix;\n }\n // Check for mention prefix (e.g., \"<@bot-id> command\") - unless disabled\n else if (!this.disableMentionPrefix && rawContent.match(/^<@!?[\\w]+>/)) {\n const mentionMatch = rawContent.match(/^<@!?([\\w]+)>\\s*/);\n if (mentionMatch) {\n const mentionedId = mentionMatch[1];\n const botId = this.client.user?.id;\n\n // Only process if mentioned user is the bot\n if (botId && mentionedId === botId) {\n usedPrefix = mentionMatch[0];\n withoutPrefix = rawContent.slice(mentionMatch[0].length).trim();\n } else {\n }\n }\n }\n\n if (!withoutPrefix) {\n return null;\n }\n\n const [commandName, ...args] = withoutPrefix.split(/\\s+/);\n\n if (!commandName) {\n return null;\n }\n\n return {\n client: this.client,\n content: rawContent,\n authorId: meta.authorId,\n channelId: meta.channelId,\n serverId: meta.serverId,\n args,\n prefix: usedPrefix,\n commandName: commandName.toLowerCase(),\n reply: meta.reply,\n message,\n };\n }\n\n /**\n * Handle a message object using the configured message adapter\n *\n * @example\n * ```ts\n * // With message adapter configured\n * client.on('messageCreate', (message) => {\n * handler.handle(message);\n * });\n * ```\n */\n async handle(message: Message): Promise<boolean> {\n if (!message.channel || !message.author) {\n return false;\n }\n\n // Skip messages from bots\n if (message.author.bot) {\n return false;\n }\n\n const rawContent = message.content;\n const authorId = message.author.id;\n const channelId = message.channel.id;\n const serverId = message.server?.id;\n const reply = async (content: string) => {\n return await message.channel!.send(content);\n };\n\n // rawContent won't be null since a command will be invoked with a prefix\n await this.handleMessage(rawContent!, message, {\n authorId,\n channelId,\n serverId,\n reply,\n });\n\n return true;\n }\n\n /**\n * Handle a raw message string with metadata\n *\n * @example\n * ```ts\n * // Manual usage without message adapter\n * client.on('messageCreate', (message) => {\n * handler.handleMessage(message.content, message, {\n * authorId: message.author.id,\n * channelId: message.channel.id,\n * serverId: message.server?.id,\n * reply: (content) => message.channel.sendMessage(content),\n * });\n * });\n * ```\n */\n async handleMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<void> {\n const ctx = await this.parseMessage(rawContent, message, meta);\n\n if (!ctx) {\n return;\n }\n\n await this.execute(ctx);\n }\n\n /**\n * Execute a command with the given context\n */\n async execute(ctx: CommandContext): Promise<boolean> {\n const registered = this.registry.get(ctx.commandName);\n\n if (!registered) {\n return false;\n }\n\n const { instance, metadata, methodName, classConstructor } = registered;\n\n // Owner-only check\n if (metadata.ownerOnly && !this.owners.has(ctx.authorId)) {\n await ctx.reply(\"This command is owner-only.\");\n return false;\n }\n\n // Guard checks - use classConstructor for guard metadata\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", classConstructor) || [];\n for (const guardClass of guards) {\n const guardInstance = new (guardClass as any)();\n if (typeof guardInstance.run === \"function\") {\n const guardResult = await guardInstance.run(ctx);\n if (!guardResult) {\n if (typeof guardInstance.guardFail === \"function\") {\n await guardInstance.guardFail(ctx);\n } else {\n console.error(\"[Stoatx] Guard check failed but no guardFail method defined on\", guardClass.name);\n }\n return false;\n }\n }\n }\n\n // Cooldown check\n if (!(await this.cooldownManager.check(ctx, metadata))) {\n const remaining = await this.cooldownManager.getRemaining(ctx, metadata);\n\n // For method-based commands, check if instance has onCooldown\n if (typeof (instance as any).onCooldown === \"function\") {\n await (instance as any).onCooldown(ctx, remaining);\n } else {\n await ctx.reply(`Please wait ${(remaining / 1000).toFixed(1)} seconds before using this command again.`);\n }\n return false;\n }\n\n try {\n // Set cooldown before execution to prevent concurrent executions\n if (metadata.cooldown > 0) {\n await this.cooldownManager.set(ctx, metadata);\n }\n\n await (instance as any)[methodName](ctx);\n\n return true;\n } catch (error) {\n // Handle errors\n if (typeof (instance as any).onError === \"function\") {\n await (instance as any).onError(ctx, error as Error);\n } else {\n console.error(`[Stoatx] Error in command ${metadata.name}:`, error);\n }\n return false;\n }\n }\n\n /**\n * Get the command registry\n */\n getRegistry(): CommandRegistry {\n return this.registry;\n }\n\n /**\n * Get a command by name or alias\n */\n getCommand(name: string): RegisteredCommand | undefined {\n return this.registry.get(name);\n }\n\n /**\n * Get all commands\n */\n getCommands(): RegisteredCommand[] {\n return this.registry.getAll();\n }\n\n /**\n * Reload all commands\n */\n async reload(): Promise<void> {\n this.registry.clear();\n if (this.cooldownManager.clear) {\n await this.cooldownManager.clear();\n }\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n return;\n }\n\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n /**\n * Check if a user is an owner\n */\n isOwner(userId: string): boolean {\n return this.owners.has(userId);\n }\n\n /**\n * Add an owner\n */\n addOwner(userId: string): void {\n this.owners.add(userId);\n }\n\n /**\n * Remove an owner\n */\n removeOwner(userId: string): void {\n this.owners.delete(userId);\n }\n\n /**\n * Resolve the prefix for a context\n */\n private async resolvePrefix(serverId?: string | undefined): Promise<string> {\n if (typeof this.prefixResolver === \"function\") {\n return this.prefixResolver({ serverId });\n }\n return this.prefixResolver;\n }\n}\n"],"mappings":"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","names":["import_reflect_metadata","import_reflect_metadata","import_reflect_metadata","relative","import_reflect_metadata","StoatClient"]}
package/dist/index.mjs CHANGED
@@ -152,6 +152,7 @@ function buildSimpleCommandMetadata(options, methodName, category) {
152
152
  permissions: options.permissions ?? [],
153
153
  category: options.category ?? category ?? "uncategorized",
154
154
  cooldown: options.cooldown ?? 0,
155
+ ...options.cooldownStorage !== void 0 ? { cooldownStorage: options.cooldownStorage } : {},
155
156
  nsfw: options.nsfw ?? false,
156
157
  ownerOnly: options.ownerOnly ?? false
157
158
  };
@@ -427,6 +428,38 @@ var CommandRegistry = class _CommandRegistry {
427
428
  // src/handler.ts
428
429
  import "reflect-metadata";
429
430
  import { Client as StoatClient } from "@stoatx/client";
431
+ var DefaultCooldownManager = class {
432
+ cooldowns = /* @__PURE__ */ new Map();
433
+ check(ctx, metadata) {
434
+ if (metadata.cooldown <= 0) return true;
435
+ const commandCooldowns = this.cooldowns.get(metadata.name);
436
+ if (!commandCooldowns) return true;
437
+ const expirationTime = commandCooldowns.get(ctx.authorId);
438
+ if (!expirationTime) return true;
439
+ if (Date.now() > expirationTime) {
440
+ commandCooldowns.delete(ctx.authorId);
441
+ return true;
442
+ }
443
+ return false;
444
+ }
445
+ getRemaining(ctx, metadata) {
446
+ const commandCooldowns = this.cooldowns.get(metadata.name);
447
+ if (!commandCooldowns) return 0;
448
+ const userCooldown = commandCooldowns.get(ctx.authorId);
449
+ if (!userCooldown) return 0;
450
+ return Math.max(0, userCooldown - Date.now());
451
+ }
452
+ set(ctx, metadata) {
453
+ if (!this.cooldowns.has(metadata.name)) {
454
+ this.cooldowns.set(metadata.name, /* @__PURE__ */ new Map());
455
+ }
456
+ const commandCooldowns = this.cooldowns.get(metadata.name);
457
+ commandCooldowns.set(ctx.authorId, Date.now() + metadata.cooldown);
458
+ }
459
+ clear() {
460
+ this.cooldowns.clear();
461
+ }
462
+ };
430
463
  var Client = class extends StoatClient {
431
464
  handler;
432
465
  constructor(options) {
@@ -449,7 +482,7 @@ var StoatxHandler = class {
449
482
  prefixResolver;
450
483
  owners;
451
484
  registry;
452
- cooldowns = /* @__PURE__ */ new Map();
485
+ cooldownManager;
453
486
  disableMentionPrefix;
454
487
  client;
455
488
  constructor(options) {
@@ -460,6 +493,7 @@ var StoatxHandler = class {
460
493
  this.owners = new Set(options.owners ?? []);
461
494
  this.registry = new CommandRegistry(options.extensions);
462
495
  this.disableMentionPrefix = options.disableMentionPrefix ?? false;
496
+ this.cooldownManager = options.cooldownManager ?? new DefaultCooldownManager();
463
497
  }
464
498
  /**
465
499
  * Initialize the handler - load all commands
@@ -622,8 +656,8 @@ var StoatxHandler = class {
622
656
  }
623
657
  }
624
658
  }
625
- if (!this.checkCooldown(ctx.authorId, metadata)) {
626
- const remaining = this.getRemainingCooldown(ctx.authorId, metadata);
659
+ if (!await this.cooldownManager.check(ctx, metadata)) {
660
+ const remaining = await this.cooldownManager.getRemaining(ctx, metadata);
627
661
  if (typeof instance.onCooldown === "function") {
628
662
  await instance.onCooldown(ctx, remaining);
629
663
  } else {
@@ -633,7 +667,7 @@ var StoatxHandler = class {
633
667
  }
634
668
  try {
635
669
  if (metadata.cooldown > 0) {
636
- this.setCooldown(ctx.authorId, metadata);
670
+ await this.cooldownManager.set(ctx, metadata);
637
671
  }
638
672
  await instance[methodName](ctx);
639
673
  return true;
@@ -669,7 +703,9 @@ var StoatxHandler = class {
669
703
  */
670
704
  async reload() {
671
705
  this.registry.clear();
672
- this.cooldowns.clear();
706
+ if (this.cooldownManager.clear) {
707
+ await this.cooldownManager.clear();
708
+ }
673
709
  if (this.commandsDir) {
674
710
  await this.registry.loadFromDirectory(this.commandsDir);
675
711
  return;
@@ -703,41 +739,6 @@ var StoatxHandler = class {
703
739
  }
704
740
  return this.prefixResolver;
705
741
  }
706
- /**
707
- * Check if user is on cooldown
708
- */
709
- checkCooldown(userId, metadata) {
710
- if (metadata.cooldown <= 0) return true;
711
- const commandCooldowns = this.cooldowns.get(metadata.name);
712
- if (!commandCooldowns) return true;
713
- const expirationTime = commandCooldowns.get(userId);
714
- if (!expirationTime) return true;
715
- if (Date.now() > expirationTime) {
716
- commandCooldowns.delete(userId);
717
- return true;
718
- }
719
- return false;
720
- }
721
- /**
722
- * Get remaining cooldown time in ms
723
- */
724
- getRemainingCooldown(userId, metadata) {
725
- const commandCooldowns = this.cooldowns.get(metadata.name);
726
- if (!commandCooldowns) return 0;
727
- const userCooldown = commandCooldowns.get(userId);
728
- if (!userCooldown) return 0;
729
- return Math.max(0, userCooldown - Date.now());
730
- }
731
- /**
732
- * Set cooldown for a user
733
- */
734
- setCooldown(userId, metadata) {
735
- if (!this.cooldowns.has(metadata.name)) {
736
- this.cooldowns.set(metadata.name, /* @__PURE__ */ new Map());
737
- }
738
- const commandCooldowns = this.cooldowns.get(metadata.name);
739
- commandCooldowns.set(userId, Date.now() + metadata.cooldown);
740
- }
741
742
  };
742
743
 
743
744
  // src/index.ts
@@ -745,6 +746,7 @@ export * from "@stoatx/client";
745
746
  export {
746
747
  Client,
747
748
  CommandRegistry,
749
+ DefaultCooldownManager,
748
750
  Guard,
749
751
  METADATA_KEYS,
750
752
  On,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/decorators/Stoat.ts","../src/decorators/keys.ts","../src/decorators/store.ts","../src/decorators/SimpleCommand.ts","../src/decorators/Guard.ts","../src/decorators/Events.ts","../src/decorators/utils.ts","../src/registry.ts","../src/handler.ts","../src/index.ts"],"sourcesContent":["import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\nimport { decoratorStore } from \"./store\";\n\n/**\n * @Stoat\n * Marks a class as a Stoat command container.\n * Use this decorator on classes that contain @SimpleCommand methods.\n *\n * @example\n * ```ts\n * import { Stoat, SimpleCommand, CommandContext } from 'stoatx';\n *\n * @Stoat()\n * class ModerationCommands {\n * @SimpleCommand({ name: 'ban', description: 'Ban a user' })\n * async ban(ctx: CommandContext) {\n * await ctx.reply('User banned!');\n * }\n *\n * @SimpleCommand({ name: 'kick', description: 'Kick a user' })\n * async kick(ctx: CommandContext) {\n * await ctx.reply('User kicked!');\n * }\n * }\n * ```\n */\nexport function Stoat(): ClassDecorator {\n return (target: Function) => {\n Reflect.defineMetadata(METADATA_KEYS.IS_STOAT_CLASS, true, target);\n decoratorStore.registerStoatClass(target);\n };\n}\n\n/**\n * Check if a class is decorated with @Stoat\n */\nexport function isStoatClass(target: Function): boolean {\n return Reflect.getMetadata(METADATA_KEYS.IS_STOAT_CLASS, target) === true;\n}\n","/**\n * Metadata keys used by decorators\n */\nexport const METADATA_KEYS = {\n IS_STOAT_CLASS: Symbol(\"stoatx:stoat:isClass\"),\n SIMPLE_COMMANDS: Symbol(\"stoatx:stoat:simpleCommands\"),\n GUARDS: \"stoatx:command:guards\",\n EVENTS: Symbol(\"stoatx:stoat:events\"),\n} as const;\n","import type { RegisteredCommand } from \"../registry\";\n\n/**\n * Global store for all decorated classes and commands\n * This allows automatic registration without directory scanning\n */\nexport class DecoratorStore {\n private static instance: DecoratorStore;\n\n /** Stoat classes with their SimpleCommand methods */\n private stoatClasses: Map<Function, object> = new Map();\n\n /** Registered commands from @Stoat/@SimpleCommand decorators */\n private commands: RegisteredCommand[] = [];\n\n /** Whether the store has been initialized */\n private initialized = false;\n\n private constructor() {}\n\n static getInstance(): DecoratorStore {\n if (!DecoratorStore.instance) {\n DecoratorStore.instance = new DecoratorStore();\n }\n return DecoratorStore.instance;\n }\n\n /**\n * Register a @Stoat decorated class\n */\n registerStoatClass(classConstructor: Function): void {\n if (!this.stoatClasses.has(classConstructor)) {\n // Create instance immediately when decorated\n const instance = new (classConstructor as new () => object)();\n this.stoatClasses.set(classConstructor, instance);\n }\n }\n\n /**\n * Get all registered Stoat classes with their instances\n */\n getStoatClasses(): Map<Function, object> {\n return this.stoatClasses;\n }\n\n /**\n * Add a registered command\n */\n addCommand(command: RegisteredCommand): void {\n this.commands.push(command);\n }\n\n /**\n * Get all registered commands\n */\n getCommands(): RegisteredCommand[] {\n return this.commands;\n }\n\n /**\n * Clear all registered classes (useful for testing)\n */\n clear(): void {\n this.stoatClasses.clear();\n this.commands = [];\n this.initialized = false;\n }\n\n /**\n * Mark as initialized\n */\n markInitialized(): void {\n this.initialized = true;\n }\n\n /**\n * Check if initialized\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n}\n\nexport const decoratorStore = DecoratorStore.getInstance();\n","import \"reflect-metadata\";\nimport type { SimpleCommandOptions } from \"../types\";\nimport { METADATA_KEYS } from \"./keys\";\n\n/**\n * Stored simple command metadata from method decorator\n */\nexport interface SimpleCommandDefinition {\n methodName: string;\n options: SimpleCommandOptions;\n}\n\n/**\n * @SimpleCommand\n * Marks a method as a simple command within a @Stoat() decorated class.\n *\n * @example\n * ```ts\n * @Stoat()\n * class Example {\n * @SimpleCommand({ name: 'ping', description: 'Replies with Pong!' })\n * async ping(ctx: CommandContext) {\n * await ctx.reply('Pong!');\n * }\n *\n * @SimpleCommand({ aliases: ['perm'], name: 'permission' })\n * async permission(ctx: CommandContext) {\n * await ctx.reply('Access granted');\n * }\n * }\n * ```\n */\nexport function SimpleCommand(options: SimpleCommandOptions = {}): MethodDecorator {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n\n // Get existing simple commands or create new array\n const existingCommands: SimpleCommandDefinition[] =\n Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, constructor) || [];\n\n // Add this command definition\n existingCommands.push({\n methodName: String(propertyKey),\n options,\n });\n\n Reflect.defineMetadata(METADATA_KEYS.SIMPLE_COMMANDS, existingCommands, constructor);\n\n return descriptor;\n };\n}\n\n/**\n * Get all simple command definitions from a @Stoat class\n */\nexport function getSimpleCommands(target: Function): SimpleCommandDefinition[] {\n return Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, target) || [];\n}\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\n\n/**\n * @Guard\n * Runs before a command to check if it should execute.\n * Should return true to allow execution, false to block.\n * Applied on @Stoat classes to guard all contained @SimpleCommand methods.\n *\n * @example\n * ```ts\n * import { Guard, Stoat, SimpleCommand, CommandContext } from 'stoatx';\n *\n * // Define a guard\n * class NotBot implements StoatxGuard {\n * run(ctx: CommandContext): boolean {\n * return !ctx.message.author.bot;\n * }\n *\n * guardFail(ctx: CommandContext): void {\n * ctx.reply(\"Bots cannot use this command!\");\n * }\n * }\n *\n * @Stoat()\n * @Guard(NotBot)\n * class AdminCommands {\n * @SimpleCommand({ name: 'admin', description: 'Admin only command' })\n * async admin(ctx: CommandContext) {\n * ctx.reply(\"You passed the guard check!\");\n * }\n * }\n * ```\n */\nexport function Guard(guardClass: Function): ClassDecorator {\n return (target: Function) => {\n const existingGuards: Function[] = Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];\n existingGuards.push(guardClass);\n Reflect.defineMetadata(METADATA_KEYS.GUARDS, existingGuards, target);\n };\n}\n\n/**\n * Get all guards from a decorated class\n */\nexport function getGuards(target: Function): Function[] {\n return Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];\n}\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\n\nexport interface EventDefinition {\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\nfunction createEventDecorator(event: string, type: \"on\" | \"once\"): MethodDecorator {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n\n // Retrieve existing events or initialize a fresh array\n const existingEvents: EventDefinition[] = Reflect.getMetadata(METADATA_KEYS.EVENTS, constructor) || [];\n\n existingEvents.push({\n methodName: String(propertyKey),\n event,\n type,\n });\n\n Reflect.defineMetadata(METADATA_KEYS.EVENTS, existingEvents, constructor);\n\n return descriptor;\n };\n}\n\n/**\n * @On\n * Triggered on every occurrence of the event.\n * Marks a method to be executed whenever the specified client event is emitted.\n *\n * @example\n * ```ts\n * import { Stoat, On } from 'stoatx';\n * import { Message, Client } from 'stoat.js';\n *\n * @Stoat()\n * class BotEvents {\n * @On('messageCreate')\n * async onMessage(message: Message, client: Client) {\n * console.log('New message received:', message.content);\n * }\n * }\n * ```\n *\n * @param event The name of the client event to listen to\n */\nexport function On(event: string): MethodDecorator {\n return createEventDecorator(event, \"on\");\n}\n\n/**\n * @Once\n * Triggered only fully once.\n * Marks a method to be executed only the FIRST time the specified client event is emitted.\n *\n * @example\n * ```ts\n * import { Stoat, Once } from 'stoatx';\n * import { Client } from 'stoat.js';\n *\n * @Stoat()\n * class BotEvents {\n * @Once('ready')\n * async onReady(client: Client) {\n * console.log('Bot successfully started and logged in!');\n * }\n * }\n * ```\n *\n * @param event The name of the client event to listen to\n */\nexport function Once(event: string): MethodDecorator {\n return createEventDecorator(event, \"once\");\n}\n\n/**\n * Get all event definitions from a @Stoat class\n */\nexport function getEventsMetadata(target: Function): EventDefinition[] {\n return Reflect.getMetadata(METADATA_KEYS.EVENTS, target) || [];\n}\n","import type { CommandMetadata, SimpleCommandOptions } from \"../types\";\n\n/**\n * Build CommandMetadata from SimpleCommandOptions\n */\nexport function buildSimpleCommandMetadata(\n options: SimpleCommandOptions,\n methodName: string,\n category?: string,\n): CommandMetadata {\n return {\n name: options.name ?? methodName.toLowerCase(),\n description: options.description ?? \"No description provided\",\n aliases: options.aliases ?? [],\n permissions: options.permissions ?? [],\n category: options.category ?? category ?? \"uncategorized\",\n cooldown: options.cooldown ?? 0,\n nsfw: options.nsfw ?? false,\n ownerOnly: options.ownerOnly ?? false,\n };\n}\n","import * as path from \"node:path\";\nimport * as fs from \"node:fs/promises\";\nimport { pathToFileURL } from \"node:url\";\nimport { glob } from \"tinyglobby\";\nimport { buildSimpleCommandMetadata, getSimpleCommands, getEventsMetadata } from \"./decorators\";\nimport { decoratorStore } from \"./decorators/store\";\nimport type { CommandMetadata } from \"./types\";\n\ninterface AutoDiscoveryOptions {\n roots?: string[];\n include?: string[];\n ignore?: string[];\n}\n\n/**\n * Stored command entry from @Stoat/@SimpleCommand registration.\n */\nexport interface RegisteredCommand {\n /** Instance of the @Stoat class */\n instance: object;\n /** Command metadata */\n metadata: CommandMetadata;\n /** Method name to call */\n methodName: string;\n /** The original class constructor (for guard validation) */\n classConstructor: Function;\n}\n\n/**\n * Stored event entry from @On/@Once registration.\n */\nexport interface RegisteredEvent {\n instance: object;\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\n/**\n * CommandRegistry - Scans directories and stores commands in a Map\n *\n * @example\n * ```ts\n * const registry = new CommandRegistry();\n * await registry.loadFromDirectory('./src/commands');\n *\n * const ping = registry.get('ping');\n * const allCommands = registry.getAll();\n * ```\n */\nexport class CommandRegistry {\n private static readonly DEFAULT_AUTO_DISCOVERY_IGNORES = [\n \"**/node_modules/**\",\n \"**/.git/**\",\n \"**/*.d.ts\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n ];\n\n private readonly commands: Map<string, RegisteredCommand> = new Map();\n private readonly aliases: Map<string, string> = new Map();\n private readonly registeredEvents: RegisteredEvent[] = [];\n private readonly extensions: string[];\n private readonly processedStoatClasses: Set<Function> = new Set();\n\n constructor(extensions: string[] = [\".js\", \".mjs\", \".cjs\"]) {\n this.extensions = extensions;\n }\n\n /**\n * Get the number of registered commands\n */\n get size(): number {\n return this.commands.size;\n }\n\n /**\n * Load commands from a directory using glob pattern matching\n */\n async loadFromDirectory(directory: string): Promise<void> {\n const patterns = this.extensions.map((ext) => path.join(directory, \"**\", `*${ext}`).replace(/\\\\/g, \"/\"));\n\n for (const pattern of patterns) {\n const files = await glob(pattern, {\n ignore: [\"**/*.d.ts\", \"**/*.test.ts\", \"**/*.spec.ts\"],\n absolute: true,\n });\n\n for (const file of files) {\n await this.loadFile(file, directory);\n }\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n /**\n * Auto-discover command files across one or more roots.\n */\n async autoDiscover(options: AutoDiscoveryOptions = {}): Promise<void> {\n const roots = options.roots?.length ? options.roots : [process.cwd()];\n const includePatterns = options.include?.length ? options.include : this.getDefaultAutoDiscoveryPatterns();\n\n const patterns = roots.flatMap((root) =>\n includePatterns.map((pattern) => path.join(root, pattern).replace(/\\\\/g, \"/\")),\n );\n\n const files = await glob(patterns, {\n ignore: [...CommandRegistry.DEFAULT_AUTO_DISCOVERY_IGNORES, ...(options.ignore ?? [])],\n absolute: true,\n });\n\n const uniqueFiles = [...new Set(files)];\n let candidateFiles = 0;\n for (const file of uniqueFiles) {\n if (!(await this.isLikelyCommandModule(file))) {\n continue;\n }\n candidateFiles++;\n\n const baseDir =\n roots.find((root) => {\n const relative = path.relative(root, file);\n return relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n }) ?? roots[0]!;\n await this.loadFile(file, baseDir);\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n private getDefaultAutoDiscoveryPatterns(): string[] {\n // discordx-like default: scan broadly, then register only decorated classes\n return this.extensions.map((ext) => `**/*${ext}`);\n }\n\n private async isLikelyCommandModule(filePath: string): Promise<boolean> {\n try {\n const source = await fs.readFile(filePath, \"utf8\");\n return source.includes(\"Stoat\") || source.includes(\"SimpleCommand\") || source.includes(\"stoatx:command\");\n } catch {\n // If the file can't be pre-read, fall back to attempting import.\n return true;\n }\n }\n\n /**\n * Register a command instance\n */\n register(instance: object, metadata: CommandMetadata, classConstructor: Function, methodName: string): void {\n const name = metadata.name.toLowerCase();\n\n if (this.commands.has(name)) {\n console.warn(`[Stoatx] Duplicate command name: ${name}. Skipping...`);\n return;\n }\n\n this.validateGuards(classConstructor, metadata.name);\n\n this.commands.set(name, { instance, metadata, methodName, classConstructor });\n\n for (const alias of metadata.aliases) {\n const aliasLower = alias.toLowerCase();\n if (this.aliases.has(aliasLower) || this.commands.has(aliasLower)) {\n console.warn(`[Stoatx] Duplicate alias: ${aliasLower}. Skipping...`);\n continue;\n }\n this.aliases.set(aliasLower, name);\n }\n }\n\n /**\n * Get a command by name or alias\n */\n get(name: string): RegisteredCommand | undefined {\n const lowerName = name.toLowerCase();\n const resolvedName = this.aliases.get(lowerName) ?? lowerName;\n return this.commands.get(resolvedName);\n }\n\n /**\n * Check if a command exists\n */\n has(name: string): boolean {\n const lowerName = name.toLowerCase();\n return this.commands.has(lowerName) || this.aliases.has(lowerName);\n }\n\n /**\n * Get all registered commands\n */\n getAll(): RegisteredCommand[] {\n return Array.from(this.commands.values());\n }\n\n /**\n * Get all command metadata\n */\n getAllMetadata(): CommandMetadata[] {\n return this.getAll().map((c) => c.metadata);\n }\n\n /**\n * Get all registered events\n */\n getEvents(): RegisteredEvent[] {\n return this.registeredEvents;\n }\n\n /**\n * Get commands grouped by category\n */\n getByCategory(): Map<string, RegisteredCommand[]> {\n const categories = new Map<string, RegisteredCommand[]>();\n\n for (const cmd of this.commands.values()) {\n const category = cmd.metadata.category;\n const existing = categories.get(category) ?? [];\n existing.push(cmd);\n categories.set(category, existing);\n }\n\n return categories;\n }\n\n /**\n * Clear all commands\n */\n clear(): void {\n this.commands.clear();\n this.aliases.clear();\n this.registeredEvents.length = 0;\n this.processedStoatClasses.clear();\n }\n\n /**\n * Iterate over commands\n */\n [Symbol.iterator](): IterableIterator<[string, RegisteredCommand]> {\n return this.commands.entries();\n }\n\n /**\n * Iterate over command values\n */\n values(): IterableIterator<RegisteredCommand> {\n return this.commands.values();\n }\n\n /**\n * Iterate over command names\n */\n keys(): IterableIterator<string> {\n return this.commands.keys();\n }\n\n /**\n * Validate that all guards on a command implement the required methods\n * @param commandClass\n * @param commandName\n * @private\n */\n private validateGuards(commandClass: Function, commandName: string): void {\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", commandClass) || [];\n\n for (const GuardClass of guards) {\n const guardInstance = new (GuardClass as any)();\n\n if (typeof guardInstance.run !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a run() method.`,\n );\n process.exit(1);\n }\n\n if (typeof guardInstance.guardFail !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a guardFail() method.`,\n );\n console.error(`[Stoatx] All guards must implement guardFail() to handle failed checks.`);\n process.exit(1);\n }\n }\n }\n\n /**\n * Load commands from a single file\n */\n private async loadFile(filePath: string, baseDir: string): Promise<void> {\n try {\n const knownStoatClasses = new Set(decoratorStore.getStoatClasses().keys());\n const fileUrl = pathToFileURL(filePath).href;\n await import(fileUrl);\n\n const allStoatClasses = decoratorStore.getStoatClasses();\n for (const [stoatClass, stoatInstance] of allStoatClasses.entries()) {\n if (knownStoatClasses.has(stoatClass) || this.processedStoatClasses.has(stoatClass)) {\n continue;\n }\n this.registerStoatClassCommands(stoatClass, stoatInstance, filePath, baseDir);\n }\n } catch (error) {\n console.error(`[Stoatx] Failed to load command file: ${filePath}`, error);\n }\n }\n\n private registerStoatClassCommands(stoatClass: Function, instance: object, filePath: string, baseDir: string): void {\n const simpleCommands = getSimpleCommands(stoatClass);\n const events = getEventsMetadata(stoatClass);\n const category = this.getCategoryFromPath(filePath, baseDir);\n\n if (simpleCommands.length === 0 && events.length === 0) {\n console.warn(\n `[Stoatx] Class ${stoatClass.name} is decorated with @Stoat but has no @SimpleCommand, @On or @Once methods. Skipping...`,\n );\n this.processedStoatClasses.add(stoatClass);\n return;\n }\n\n for (const cmdDef of simpleCommands) {\n const method = (instance as any)[cmdDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${cmdDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n const metadata = buildSimpleCommandMetadata(cmdDef.options, cmdDef.methodName, category);\n this.register(instance, metadata, stoatClass, cmdDef.methodName);\n }\n\n for (const eventDef of events) {\n const method = (instance as any)[eventDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${eventDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n this.registeredEvents.push({\n instance,\n methodName: eventDef.methodName,\n event: eventDef.event,\n type: eventDef.type,\n });\n }\n\n this.processedStoatClasses.add(stoatClass);\n }\n\n /**\n * Derive category from file path relative to base directory\n */\n private getCategoryFromPath(filePath: string, baseDir: string): string | undefined {\n const relative = path.relative(baseDir, filePath);\n const parts = relative.split(path.sep);\n\n if (parts.length > 1) {\n return parts[0];\n }\n\n return undefined;\n }\n}\n","import \"reflect-metadata\";\nimport { CommandRegistry, RegisteredCommand } from \"./registry\";\nimport type { CommandContext, CommandMetadata, StoatxDiscoveryOptions, StoatxHandlerOptions } from \"./types\";\nimport { Client as StoatClient, ClientEvents, Message } from \"@stoatx/client\";\n\n/**\n * Client - An extended Client that integrates StoatxHandler directly\n *\n * @example\n * ```ts\n * import { Client } from 'stoatx';\n *\n * const client = new Client({\n * prefix: '!',\n * owners: ['owner-user-id'],\n * });\n *\n * await client.initCommands();\n * ```\n */\nexport class Client extends StoatClient {\n public readonly handler: StoatxHandler;\n\n constructor(options: Omit<StoatxHandlerOptions, \"client\">) {\n super();\n this.handler = new StoatxHandler({ ...options, client: this });\n\n // Automatically hook up the message handler\n this.on(\"messageCreate\", async (message) => {\n await this.handler.handle(message);\n });\n }\n\n /**\n * Initialize the StoatxHandler commands\n */\n async initCommands(): Promise<void> {\n await this.handler.init();\n }\n}\n\n/**\n * StoatxHandler - The execution engine for commands\n *\n * Handles message parsing, middleware execution, and command dispatching\n *\n * @internal This class is not intended to be instantiated directly. Use the `Client` from `stoatx` instead.\n */\nexport class StoatxHandler {\n private readonly commandsDir: string | undefined;\n private readonly discoveryOptions: StoatxDiscoveryOptions | undefined;\n private readonly prefixResolver: string | ((ctx: { serverId?: string | undefined }) => string | Promise<string>);\n private readonly owners: Set<string>;\n private readonly registry: CommandRegistry;\n private readonly cooldowns: Map<string, Map<string, number>> = new Map();\n private readonly disableMentionPrefix: boolean;\n private readonly client: StoatClient;\n constructor(options: StoatxHandlerOptions) {\n this.client = options.client;\n this.commandsDir = options.commandsDir;\n this.discoveryOptions = options.discovery;\n this.prefixResolver = options.prefix;\n this.owners = new Set(options.owners ?? []);\n this.registry = new CommandRegistry(options.extensions);\n this.disableMentionPrefix = options.disableMentionPrefix ?? false;\n }\n\n /**\n * Initialize the handler - load all commands\n */\n async init(): Promise<void> {\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n } else {\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n this.attachEvents();\n }\n\n /**\n * Attach registered events to the client\n */\n private attachEvents(): void {\n const events = this.registry.getEvents();\n\n for (const eventDef of events) {\n const handler = async (...args: any[]) => {\n try {\n await (eventDef.instance as any)[eventDef.methodName](...args, this.client);\n } catch (error) {\n console.error(\n `[Stoatx] Event Handler Error in @${eventDef.type === \"on\" ? \"On\" : \"Once\"}('${eventDef.event}'):`,\n error,\n );\n }\n };\n\n const eventName = eventDef.event as keyof ClientEvents;\n if (eventDef.type === \"once\") {\n this.client.once(eventName, handler);\n } else {\n this.client.on(eventName, handler);\n }\n }\n }\n\n /**\n * Parse a raw message into command context\n */\n async parseMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<CommandContext | null> {\n const prefix = await this.resolvePrefix(meta.serverId);\n let usedPrefix = prefix;\n let withoutPrefix = \"\";\n\n // Check for string prefix\n if (rawContent.startsWith(prefix)) {\n withoutPrefix = rawContent.slice(prefix.length).trim();\n usedPrefix = prefix;\n }\n // Check for mention prefix (e.g., \"<@bot-id> command\") - unless disabled\n else if (!this.disableMentionPrefix && rawContent.match(/^<@!?[\\w]+>/)) {\n const mentionMatch = rawContent.match(/^<@!?([\\w]+)>\\s*/);\n if (mentionMatch) {\n const mentionedId = mentionMatch[1];\n const botId = this.client.user?.id;\n\n // Only process if mentioned user is the bot\n if (botId && mentionedId === botId) {\n usedPrefix = mentionMatch[0];\n withoutPrefix = rawContent.slice(mentionMatch[0].length).trim();\n } else {\n }\n }\n }\n\n if (!withoutPrefix) {\n return null;\n }\n\n const [commandName, ...args] = withoutPrefix.split(/\\s+/);\n\n if (!commandName) {\n return null;\n }\n\n return {\n client: this.client,\n content: rawContent,\n authorId: meta.authorId,\n channelId: meta.channelId,\n serverId: meta.serverId,\n args,\n prefix: usedPrefix,\n commandName: commandName.toLowerCase(),\n reply: meta.reply,\n message,\n };\n }\n\n /**\n * Handle a message object using the configured message adapter\n *\n * @example\n * ```ts\n * // With message adapter configured\n * client.on('messageCreate', (message) => {\n * handler.handle(message);\n * });\n * ```\n */\n async handle(message: Message): Promise<boolean> {\n if (!message.channel || !message.author) {\n return false;\n }\n\n // Skip messages from bots\n if (message.author.bot) {\n return false;\n }\n\n const rawContent = message.content;\n const authorId = message.author.id;\n const channelId = message.channel.id;\n const serverId = message.server?.id;\n const reply = async (content: string) => {\n return await message.channel!.send(content);\n };\n\n // rawContent won't be null since a command will be invoked with a prefix\n await this.handleMessage(rawContent!, message, {\n authorId,\n channelId,\n serverId,\n reply,\n });\n\n return true;\n }\n\n /**\n * Handle a raw message string with metadata\n *\n * @example\n * ```ts\n * // Manual usage without message adapter\n * client.on('messageCreate', (message) => {\n * handler.handleMessage(message.content, message, {\n * authorId: message.author.id,\n * channelId: message.channel.id,\n * serverId: message.server?.id,\n * reply: (content) => message.channel.sendMessage(content),\n * });\n * });\n * ```\n */\n async handleMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<void> {\n const ctx = await this.parseMessage(rawContent, message, meta);\n\n if (!ctx) {\n return;\n }\n\n await this.execute(ctx);\n }\n\n /**\n * Execute a command with the given context\n */\n async execute(ctx: CommandContext): Promise<boolean> {\n const registered = this.registry.get(ctx.commandName);\n\n if (!registered) {\n return false;\n }\n\n const { instance, metadata, methodName, classConstructor } = registered;\n\n // Owner-only check\n if (metadata.ownerOnly && !this.owners.has(ctx.authorId)) {\n await ctx.reply(\"This command is owner-only.\");\n return false;\n }\n\n // Guard checks - use classConstructor for guard metadata\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", classConstructor) || [];\n for (const guardClass of guards) {\n const guardInstance = new (guardClass as any)();\n if (typeof guardInstance.run === \"function\") {\n const guardResult = await guardInstance.run(ctx);\n if (!guardResult) {\n if (typeof guardInstance.guardFail === \"function\") {\n await guardInstance.guardFail(ctx);\n } else {\n console.error(\"[Stoatx] Guard check failed but no guardFail method defined on\", guardClass.name);\n }\n return false;\n }\n }\n }\n\n // Cooldown check\n if (!this.checkCooldown(ctx.authorId, metadata)) {\n const remaining = this.getRemainingCooldown(ctx.authorId, metadata);\n\n // For method-based commands, check if instance has onCooldown\n if (typeof (instance as any).onCooldown === \"function\") {\n await (instance as any).onCooldown(ctx, remaining);\n } else {\n await ctx.reply(`Please wait ${(remaining / 1000).toFixed(1)} seconds before using this command again.`);\n }\n return false;\n }\n\n try {\n // Set cooldown before execution to prevent concurrent executions\n if (metadata.cooldown > 0) {\n this.setCooldown(ctx.authorId, metadata);\n }\n\n await (instance as any)[methodName](ctx);\n\n return true;\n } catch (error) {\n // Handle errors\n if (typeof (instance as any).onError === \"function\") {\n await (instance as any).onError(ctx, error as Error);\n } else {\n console.error(`[Stoatx] Error in command ${metadata.name}:`, error);\n }\n return false;\n }\n }\n\n /**\n * Get the command registry\n */\n getRegistry(): CommandRegistry {\n return this.registry;\n }\n\n /**\n * Get a command by name or alias\n */\n getCommand(name: string): RegisteredCommand | undefined {\n return this.registry.get(name);\n }\n\n /**\n * Get all commands\n */\n getCommands(): RegisteredCommand[] {\n return this.registry.getAll();\n }\n\n /**\n * Reload all commands\n */\n async reload(): Promise<void> {\n this.registry.clear();\n this.cooldowns.clear();\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n return;\n }\n\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n /**\n * Check if a user is an owner\n */\n isOwner(userId: string): boolean {\n return this.owners.has(userId);\n }\n\n /**\n * Add an owner\n */\n addOwner(userId: string): void {\n this.owners.add(userId);\n }\n\n /**\n * Remove an owner\n */\n removeOwner(userId: string): void {\n this.owners.delete(userId);\n }\n\n /**\n * Resolve the prefix for a context\n */\n private async resolvePrefix(serverId?: string | undefined): Promise<string> {\n if (typeof this.prefixResolver === \"function\") {\n return this.prefixResolver({ serverId });\n }\n return this.prefixResolver;\n }\n\n /**\n * Check if user is on cooldown\n */\n private checkCooldown(userId: string, metadata: CommandMetadata): boolean {\n if (metadata.cooldown <= 0) return true;\n\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return true;\n\n const expirationTime = commandCooldowns.get(userId);\n if (!expirationTime) return true;\n\n if (Date.now() > expirationTime) {\n commandCooldowns.delete(userId);\n return true;\n }\n\n return false;\n }\n\n /**\n * Get remaining cooldown time in ms\n */\n private getRemainingCooldown(userId: string, metadata: CommandMetadata): number {\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return 0;\n\n const userCooldown = commandCooldowns.get(userId);\n if (!userCooldown) return 0;\n\n return Math.max(0, userCooldown - Date.now());\n }\n\n /**\n * Set cooldown for a user\n */\n private setCooldown(userId: string, metadata: CommandMetadata): void {\n if (!this.cooldowns.has(metadata.name)) {\n this.cooldowns.set(metadata.name, new Map());\n }\n\n const commandCooldowns = this.cooldowns.get(metadata.name)!;\n commandCooldowns.set(userId, Date.now() + metadata.cooldown);\n }\n}\n","// Types\nexport * from \"./types\";\n\n// Decorators\nexport * from \"./decorators\";\n\n// Registry\nexport * from \"./registry\";\n\n// Handler\nexport { Client } from \"./handler\";\nexport type { StoatxHandler } from \"./handler\";\nexport * from \"@stoatx/client\";\n"],"mappings":"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","names":["relative"]}
1
+ {"version":3,"sources":["../src/decorators/Stoat.ts","../src/decorators/keys.ts","../src/decorators/store.ts","../src/decorators/SimpleCommand.ts","../src/decorators/Guard.ts","../src/decorators/Events.ts","../src/decorators/utils.ts","../src/registry.ts","../src/handler.ts","../src/index.ts"],"sourcesContent":["import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\nimport { decoratorStore } from \"./store\";\n\n/**\n * @Stoat\n * Marks a class as a Stoat command container.\n * Use this decorator on classes that contain @SimpleCommand methods.\n *\n * @example\n * ```ts\n * import { Stoat, SimpleCommand, CommandContext } from 'stoatx';\n *\n * @Stoat()\n * class ModerationCommands {\n * @SimpleCommand({ name: 'ban', description: 'Ban a user' })\n * async ban(ctx: CommandContext) {\n * await ctx.reply('User banned!');\n * }\n *\n * @SimpleCommand({ name: 'kick', description: 'Kick a user' })\n * async kick(ctx: CommandContext) {\n * await ctx.reply('User kicked!');\n * }\n * }\n * ```\n */\nexport function Stoat(): ClassDecorator {\n return (target: Function) => {\n Reflect.defineMetadata(METADATA_KEYS.IS_STOAT_CLASS, true, target);\n decoratorStore.registerStoatClass(target);\n };\n}\n\n/**\n * Check if a class is decorated with @Stoat\n */\nexport function isStoatClass(target: Function): boolean {\n return Reflect.getMetadata(METADATA_KEYS.IS_STOAT_CLASS, target) === true;\n}\n","/**\n * Metadata keys used by decorators\n */\nexport const METADATA_KEYS = {\n IS_STOAT_CLASS: Symbol(\"stoatx:stoat:isClass\"),\n SIMPLE_COMMANDS: Symbol(\"stoatx:stoat:simpleCommands\"),\n GUARDS: \"stoatx:command:guards\",\n EVENTS: Symbol(\"stoatx:stoat:events\"),\n} as const;\n","import type { RegisteredCommand } from \"../registry\";\n\n/**\n * Global store for all decorated classes and commands\n * This allows automatic registration without directory scanning\n */\nexport class DecoratorStore {\n private static instance: DecoratorStore;\n\n /** Stoat classes with their SimpleCommand methods */\n private stoatClasses: Map<Function, object> = new Map();\n\n /** Registered commands from @Stoat/@SimpleCommand decorators */\n private commands: RegisteredCommand[] = [];\n\n /** Whether the store has been initialized */\n private initialized = false;\n\n private constructor() {}\n\n static getInstance(): DecoratorStore {\n if (!DecoratorStore.instance) {\n DecoratorStore.instance = new DecoratorStore();\n }\n return DecoratorStore.instance;\n }\n\n /**\n * Register a @Stoat decorated class\n */\n registerStoatClass(classConstructor: Function): void {\n if (!this.stoatClasses.has(classConstructor)) {\n // Create instance immediately when decorated\n const instance = new (classConstructor as new () => object)();\n this.stoatClasses.set(classConstructor, instance);\n }\n }\n\n /**\n * Get all registered Stoat classes with their instances\n */\n getStoatClasses(): Map<Function, object> {\n return this.stoatClasses;\n }\n\n /**\n * Add a registered command\n */\n addCommand(command: RegisteredCommand): void {\n this.commands.push(command);\n }\n\n /**\n * Get all registered commands\n */\n getCommands(): RegisteredCommand[] {\n return this.commands;\n }\n\n /**\n * Clear all registered classes (useful for testing)\n */\n clear(): void {\n this.stoatClasses.clear();\n this.commands = [];\n this.initialized = false;\n }\n\n /**\n * Mark as initialized\n */\n markInitialized(): void {\n this.initialized = true;\n }\n\n /**\n * Check if initialized\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n}\n\nexport const decoratorStore = DecoratorStore.getInstance();\n","import \"reflect-metadata\";\nimport type { SimpleCommandOptions } from \"../types\";\nimport { METADATA_KEYS } from \"./keys\";\n\n/**\n * Stored simple command metadata from method decorator\n */\nexport interface SimpleCommandDefinition {\n methodName: string;\n options: SimpleCommandOptions;\n}\n\n/**\n * @SimpleCommand\n * Marks a method as a simple command within a @Stoat() decorated class.\n *\n * @example\n * ```ts\n * @Stoat()\n * class Example {\n * @SimpleCommand({ name: 'ping', description: 'Replies with Pong!' })\n * async ping(ctx: CommandContext) {\n * await ctx.reply('Pong!');\n * }\n *\n * @SimpleCommand({ aliases: ['perm'], name: 'permission' })\n * async permission(ctx: CommandContext) {\n * await ctx.reply('Access granted');\n * }\n * }\n * ```\n */\nexport function SimpleCommand(options: SimpleCommandOptions = {}): MethodDecorator {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n\n // Get existing simple commands or create new array\n const existingCommands: SimpleCommandDefinition[] =\n Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, constructor) || [];\n\n // Add this command definition\n existingCommands.push({\n methodName: String(propertyKey),\n options,\n });\n\n Reflect.defineMetadata(METADATA_KEYS.SIMPLE_COMMANDS, existingCommands, constructor);\n\n return descriptor;\n };\n}\n\n/**\n * Get all simple command definitions from a @Stoat class\n */\nexport function getSimpleCommands(target: Function): SimpleCommandDefinition[] {\n return Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, target) || [];\n}\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\n\n/**\n * @Guard\n * Runs before a command to check if it should execute.\n * Should return true to allow execution, false to block.\n * Applied on @Stoat classes to guard all contained @SimpleCommand methods.\n *\n * @example\n * ```ts\n * import { Guard, Stoat, SimpleCommand, CommandContext } from 'stoatx';\n *\n * // Define a guard\n * class NotBot implements StoatxGuard {\n * run(ctx: CommandContext): boolean {\n * return !ctx.message.author.bot;\n * }\n *\n * guardFail(ctx: CommandContext): void {\n * ctx.reply(\"Bots cannot use this command!\");\n * }\n * }\n *\n * @Stoat()\n * @Guard(NotBot)\n * class AdminCommands {\n * @SimpleCommand({ name: 'admin', description: 'Admin only command' })\n * async admin(ctx: CommandContext) {\n * ctx.reply(\"You passed the guard check!\");\n * }\n * }\n * ```\n */\nexport function Guard(guardClass: Function): ClassDecorator {\n return (target: Function) => {\n const existingGuards: Function[] = Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];\n existingGuards.push(guardClass);\n Reflect.defineMetadata(METADATA_KEYS.GUARDS, existingGuards, target);\n };\n}\n\n/**\n * Get all guards from a decorated class\n */\nexport function getGuards(target: Function): Function[] {\n return Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];\n}\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\n\nexport interface EventDefinition {\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\nfunction createEventDecorator(event: string, type: \"on\" | \"once\"): MethodDecorator {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n\n // Retrieve existing events or initialize a fresh array\n const existingEvents: EventDefinition[] = Reflect.getMetadata(METADATA_KEYS.EVENTS, constructor) || [];\n\n existingEvents.push({\n methodName: String(propertyKey),\n event,\n type,\n });\n\n Reflect.defineMetadata(METADATA_KEYS.EVENTS, existingEvents, constructor);\n\n return descriptor;\n };\n}\n\n/**\n * @On\n * Triggered on every occurrence of the event.\n * Marks a method to be executed whenever the specified client event is emitted.\n *\n * @example\n * ```ts\n * import { Stoat, On } from 'stoatx';\n * import { Message, Client } from 'stoat.js';\n *\n * @Stoat()\n * class BotEvents {\n * @On('messageCreate')\n * async onMessage(message: Message, client: Client) {\n * console.log('New message received:', message.content);\n * }\n * }\n * ```\n *\n * @param event The name of the client event to listen to\n */\nexport function On(event: string): MethodDecorator {\n return createEventDecorator(event, \"on\");\n}\n\n/**\n * @Once\n * Triggered only fully once.\n * Marks a method to be executed only the FIRST time the specified client event is emitted.\n *\n * @example\n * ```ts\n * import { Stoat, Once } from 'stoatx';\n * import { Client } from 'stoat.js';\n *\n * @Stoat()\n * class BotEvents {\n * @Once('ready')\n * async onReady(client: Client) {\n * console.log('Bot successfully started and logged in!');\n * }\n * }\n * ```\n *\n * @param event The name of the client event to listen to\n */\nexport function Once(event: string): MethodDecorator {\n return createEventDecorator(event, \"once\");\n}\n\n/**\n * Get all event definitions from a @Stoat class\n */\nexport function getEventsMetadata(target: Function): EventDefinition[] {\n return Reflect.getMetadata(METADATA_KEYS.EVENTS, target) || [];\n}\n","import type { CommandMetadata, SimpleCommandOptions } from \"../types\";\n\n/**\n * Build CommandMetadata from SimpleCommandOptions\n */\nexport function buildSimpleCommandMetadata(\n options: SimpleCommandOptions,\n methodName: string,\n category?: string,\n): CommandMetadata {\n return {\n name: options.name ?? methodName.toLowerCase(),\n description: options.description ?? \"No description provided\",\n aliases: options.aliases ?? [],\n permissions: options.permissions ?? [],\n category: options.category ?? category ?? \"uncategorized\",\n cooldown: options.cooldown ?? 0,\n ...(options.cooldownStorage !== undefined ? { cooldownStorage: options.cooldownStorage } : {}),\n nsfw: options.nsfw ?? false,\n ownerOnly: options.ownerOnly ?? false,\n };\n}\n","import * as path from \"node:path\";\nimport * as fs from \"node:fs/promises\";\nimport { pathToFileURL } from \"node:url\";\nimport { glob } from \"tinyglobby\";\nimport { buildSimpleCommandMetadata, getSimpleCommands, getEventsMetadata } from \"./decorators\";\nimport { decoratorStore } from \"./decorators/store\";\nimport type { CommandMetadata } from \"./types\";\n\ninterface AutoDiscoveryOptions {\n roots?: string[];\n include?: string[];\n ignore?: string[];\n}\n\n/**\n * Stored command entry from @Stoat/@SimpleCommand registration.\n */\nexport interface RegisteredCommand {\n /** Instance of the @Stoat class */\n instance: object;\n /** Command metadata */\n metadata: CommandMetadata;\n /** Method name to call */\n methodName: string;\n /** The original class constructor (for guard validation) */\n classConstructor: Function;\n}\n\n/**\n * Stored event entry from @On/@Once registration.\n */\nexport interface RegisteredEvent {\n instance: object;\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\n/**\n * CommandRegistry - Scans directories and stores commands in a Map\n *\n * @example\n * ```ts\n * const registry = new CommandRegistry();\n * await registry.loadFromDirectory('./src/commands');\n *\n * const ping = registry.get('ping');\n * const allCommands = registry.getAll();\n * ```\n */\nexport class CommandRegistry {\n private static readonly DEFAULT_AUTO_DISCOVERY_IGNORES = [\n \"**/node_modules/**\",\n \"**/.git/**\",\n \"**/*.d.ts\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n ];\n\n private readonly commands: Map<string, RegisteredCommand> = new Map();\n private readonly aliases: Map<string, string> = new Map();\n private readonly registeredEvents: RegisteredEvent[] = [];\n private readonly extensions: string[];\n private readonly processedStoatClasses: Set<Function> = new Set();\n\n constructor(extensions: string[] = [\".js\", \".mjs\", \".cjs\"]) {\n this.extensions = extensions;\n }\n\n /**\n * Get the number of registered commands\n */\n get size(): number {\n return this.commands.size;\n }\n\n /**\n * Load commands from a directory using glob pattern matching\n */\n async loadFromDirectory(directory: string): Promise<void> {\n const patterns = this.extensions.map((ext) => path.join(directory, \"**\", `*${ext}`).replace(/\\\\/g, \"/\"));\n\n for (const pattern of patterns) {\n const files = await glob(pattern, {\n ignore: [\"**/*.d.ts\", \"**/*.test.ts\", \"**/*.spec.ts\"],\n absolute: true,\n });\n\n for (const file of files) {\n await this.loadFile(file, directory);\n }\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n /**\n * Auto-discover command files across one or more roots.\n */\n async autoDiscover(options: AutoDiscoveryOptions = {}): Promise<void> {\n const roots = options.roots?.length ? options.roots : [process.cwd()];\n const includePatterns = options.include?.length ? options.include : this.getDefaultAutoDiscoveryPatterns();\n\n const patterns = roots.flatMap((root) =>\n includePatterns.map((pattern) => path.join(root, pattern).replace(/\\\\/g, \"/\")),\n );\n\n const files = await glob(patterns, {\n ignore: [...CommandRegistry.DEFAULT_AUTO_DISCOVERY_IGNORES, ...(options.ignore ?? [])],\n absolute: true,\n });\n\n const uniqueFiles = [...new Set(files)];\n let candidateFiles = 0;\n for (const file of uniqueFiles) {\n if (!(await this.isLikelyCommandModule(file))) {\n continue;\n }\n candidateFiles++;\n\n const baseDir =\n roots.find((root) => {\n const relative = path.relative(root, file);\n return relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n }) ?? roots[0]!;\n await this.loadFile(file, baseDir);\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n private getDefaultAutoDiscoveryPatterns(): string[] {\n // discordx-like default: scan broadly, then register only decorated classes\n return this.extensions.map((ext) => `**/*${ext}`);\n }\n\n private async isLikelyCommandModule(filePath: string): Promise<boolean> {\n try {\n const source = await fs.readFile(filePath, \"utf8\");\n return source.includes(\"Stoat\") || source.includes(\"SimpleCommand\") || source.includes(\"stoatx:command\");\n } catch {\n // If the file can't be pre-read, fall back to attempting import.\n return true;\n }\n }\n\n /**\n * Register a command instance\n */\n register(instance: object, metadata: CommandMetadata, classConstructor: Function, methodName: string): void {\n const name = metadata.name.toLowerCase();\n\n if (this.commands.has(name)) {\n console.warn(`[Stoatx] Duplicate command name: ${name}. Skipping...`);\n return;\n }\n\n this.validateGuards(classConstructor, metadata.name);\n\n this.commands.set(name, { instance, metadata, methodName, classConstructor });\n\n for (const alias of metadata.aliases) {\n const aliasLower = alias.toLowerCase();\n if (this.aliases.has(aliasLower) || this.commands.has(aliasLower)) {\n console.warn(`[Stoatx] Duplicate alias: ${aliasLower}. Skipping...`);\n continue;\n }\n this.aliases.set(aliasLower, name);\n }\n }\n\n /**\n * Get a command by name or alias\n */\n get(name: string): RegisteredCommand | undefined {\n const lowerName = name.toLowerCase();\n const resolvedName = this.aliases.get(lowerName) ?? lowerName;\n return this.commands.get(resolvedName);\n }\n\n /**\n * Check if a command exists\n */\n has(name: string): boolean {\n const lowerName = name.toLowerCase();\n return this.commands.has(lowerName) || this.aliases.has(lowerName);\n }\n\n /**\n * Get all registered commands\n */\n getAll(): RegisteredCommand[] {\n return Array.from(this.commands.values());\n }\n\n /**\n * Get all command metadata\n */\n getAllMetadata(): CommandMetadata[] {\n return this.getAll().map((c) => c.metadata);\n }\n\n /**\n * Get all registered events\n */\n getEvents(): RegisteredEvent[] {\n return this.registeredEvents;\n }\n\n /**\n * Get commands grouped by category\n */\n getByCategory(): Map<string, RegisteredCommand[]> {\n const categories = new Map<string, RegisteredCommand[]>();\n\n for (const cmd of this.commands.values()) {\n const category = cmd.metadata.category;\n const existing = categories.get(category) ?? [];\n existing.push(cmd);\n categories.set(category, existing);\n }\n\n return categories;\n }\n\n /**\n * Clear all commands\n */\n clear(): void {\n this.commands.clear();\n this.aliases.clear();\n this.registeredEvents.length = 0;\n this.processedStoatClasses.clear();\n }\n\n /**\n * Iterate over commands\n */\n [Symbol.iterator](): IterableIterator<[string, RegisteredCommand]> {\n return this.commands.entries();\n }\n\n /**\n * Iterate over command values\n */\n values(): IterableIterator<RegisteredCommand> {\n return this.commands.values();\n }\n\n /**\n * Iterate over command names\n */\n keys(): IterableIterator<string> {\n return this.commands.keys();\n }\n\n /**\n * Validate that all guards on a command implement the required methods\n * @param commandClass\n * @param commandName\n * @private\n */\n private validateGuards(commandClass: Function, commandName: string): void {\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", commandClass) || [];\n\n for (const GuardClass of guards) {\n const guardInstance = new (GuardClass as any)();\n\n if (typeof guardInstance.run !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a run() method.`,\n );\n process.exit(1);\n }\n\n if (typeof guardInstance.guardFail !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a guardFail() method.`,\n );\n console.error(`[Stoatx] All guards must implement guardFail() to handle failed checks.`);\n process.exit(1);\n }\n }\n }\n\n /**\n * Load commands from a single file\n */\n private async loadFile(filePath: string, baseDir: string): Promise<void> {\n try {\n const knownStoatClasses = new Set(decoratorStore.getStoatClasses().keys());\n const fileUrl = pathToFileURL(filePath).href;\n await import(fileUrl);\n\n const allStoatClasses = decoratorStore.getStoatClasses();\n for (const [stoatClass, stoatInstance] of allStoatClasses.entries()) {\n if (knownStoatClasses.has(stoatClass) || this.processedStoatClasses.has(stoatClass)) {\n continue;\n }\n this.registerStoatClassCommands(stoatClass, stoatInstance, filePath, baseDir);\n }\n } catch (error) {\n console.error(`[Stoatx] Failed to load command file: ${filePath}`, error);\n }\n }\n\n private registerStoatClassCommands(stoatClass: Function, instance: object, filePath: string, baseDir: string): void {\n const simpleCommands = getSimpleCommands(stoatClass);\n const events = getEventsMetadata(stoatClass);\n const category = this.getCategoryFromPath(filePath, baseDir);\n\n if (simpleCommands.length === 0 && events.length === 0) {\n console.warn(\n `[Stoatx] Class ${stoatClass.name} is decorated with @Stoat but has no @SimpleCommand, @On or @Once methods. Skipping...`,\n );\n this.processedStoatClasses.add(stoatClass);\n return;\n }\n\n for (const cmdDef of simpleCommands) {\n const method = (instance as any)[cmdDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${cmdDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n const metadata = buildSimpleCommandMetadata(cmdDef.options, cmdDef.methodName, category);\n this.register(instance, metadata, stoatClass, cmdDef.methodName);\n }\n\n for (const eventDef of events) {\n const method = (instance as any)[eventDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${eventDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n this.registeredEvents.push({\n instance,\n methodName: eventDef.methodName,\n event: eventDef.event,\n type: eventDef.type,\n });\n }\n\n this.processedStoatClasses.add(stoatClass);\n }\n\n /**\n * Derive category from file path relative to base directory\n */\n private getCategoryFromPath(filePath: string, baseDir: string): string | undefined {\n const relative = path.relative(baseDir, filePath);\n const parts = relative.split(path.sep);\n\n if (parts.length > 1) {\n return parts[0];\n }\n\n return undefined;\n }\n}\n","import \"reflect-metadata\";\nimport { CommandRegistry, RegisteredCommand } from \"./registry\";\nimport type {\n CommandContext,\n CommandMetadata,\n StoatxDiscoveryOptions,\n StoatxHandlerOptions,\n CooldownManager,\n} from \"./types\";\nimport { Client as StoatClient, ClientEvents, Message } from \"@stoatx/client\";\n\n/**\n * Default in-memory cooldown manager\n */\nexport class DefaultCooldownManager implements CooldownManager {\n private readonly cooldowns: Map<string, Map<string, number>> = new Map();\n\n check(ctx: CommandContext, metadata: CommandMetadata): boolean {\n if (metadata.cooldown <= 0) return true;\n\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return true;\n\n const expirationTime = commandCooldowns.get(ctx.authorId);\n if (!expirationTime) return true;\n\n if (Date.now() > expirationTime) {\n commandCooldowns.delete(ctx.authorId);\n return true;\n }\n\n return false;\n }\n\n getRemaining(ctx: CommandContext, metadata: CommandMetadata): number {\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return 0;\n\n const userCooldown = commandCooldowns.get(ctx.authorId);\n if (!userCooldown) return 0;\n\n return Math.max(0, userCooldown - Date.now());\n }\n\n set(ctx: CommandContext, metadata: CommandMetadata): void {\n if (!this.cooldowns.has(metadata.name)) {\n this.cooldowns.set(metadata.name, new Map());\n }\n\n const commandCooldowns = this.cooldowns.get(metadata.name)!;\n commandCooldowns.set(ctx.authorId, Date.now() + metadata.cooldown);\n }\n\n clear(): void {\n this.cooldowns.clear();\n }\n}\n\n/**\n * Client - An extended Client that integrates StoatxHandler directly\n *\n * @example\n * ```ts\n * import { Client } from 'stoatx';\n *\n * const client = new Client({\n * prefix: '!',\n * owners: ['owner-user-id'],\n * });\n *\n * await client.initCommands();\n * ```\n */\nexport class Client extends StoatClient {\n public readonly handler: StoatxHandler;\n\n constructor(options: Omit<StoatxHandlerOptions, \"client\">) {\n super();\n this.handler = new StoatxHandler({ ...options, client: this });\n\n // Automatically hook up the message handler\n this.on(\"messageCreate\", async (message) => {\n await this.handler.handle(message);\n });\n }\n\n /**\n * Initialize the StoatxHandler commands\n */\n async initCommands(): Promise<void> {\n await this.handler.init();\n }\n}\n\n/**\n * StoatxHandler - The execution engine for commands\n *\n * Handles message parsing, middleware execution, and command dispatching\n *\n * @internal This class is not intended to be instantiated directly. Use the `Client` from `stoatx` instead.\n */\nexport class StoatxHandler {\n private readonly commandsDir: string | undefined;\n private readonly discoveryOptions: StoatxDiscoveryOptions | undefined;\n private readonly prefixResolver: string | ((ctx: { serverId?: string | undefined }) => string | Promise<string>);\n private readonly owners: Set<string>;\n private readonly registry: CommandRegistry;\n private readonly cooldownManager: CooldownManager;\n private readonly disableMentionPrefix: boolean;\n private readonly client: StoatClient;\n constructor(options: StoatxHandlerOptions) {\n this.client = options.client;\n this.commandsDir = options.commandsDir;\n this.discoveryOptions = options.discovery;\n this.prefixResolver = options.prefix;\n this.owners = new Set(options.owners ?? []);\n this.registry = new CommandRegistry(options.extensions);\n this.disableMentionPrefix = options.disableMentionPrefix ?? false;\n this.cooldownManager = options.cooldownManager ?? new DefaultCooldownManager();\n }\n\n /**\n * Initialize the handler - load all commands\n */\n async init(): Promise<void> {\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n } else {\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n this.attachEvents();\n }\n\n /**\n * Attach registered events to the client\n */\n private attachEvents(): void {\n const events = this.registry.getEvents();\n\n for (const eventDef of events) {\n const handler = async (...args: any[]) => {\n try {\n await (eventDef.instance as any)[eventDef.methodName](...args, this.client);\n } catch (error) {\n console.error(\n `[Stoatx] Event Handler Error in @${eventDef.type === \"on\" ? \"On\" : \"Once\"}('${eventDef.event}'):`,\n error,\n );\n }\n };\n\n const eventName = eventDef.event as keyof ClientEvents;\n if (eventDef.type === \"once\") {\n this.client.once(eventName, handler);\n } else {\n this.client.on(eventName, handler);\n }\n }\n }\n\n /**\n * Parse a raw message into command context\n */\n async parseMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<CommandContext | null> {\n const prefix = await this.resolvePrefix(meta.serverId);\n let usedPrefix = prefix;\n let withoutPrefix = \"\";\n\n // Check for string prefix\n if (rawContent.startsWith(prefix)) {\n withoutPrefix = rawContent.slice(prefix.length).trim();\n usedPrefix = prefix;\n }\n // Check for mention prefix (e.g., \"<@bot-id> command\") - unless disabled\n else if (!this.disableMentionPrefix && rawContent.match(/^<@!?[\\w]+>/)) {\n const mentionMatch = rawContent.match(/^<@!?([\\w]+)>\\s*/);\n if (mentionMatch) {\n const mentionedId = mentionMatch[1];\n const botId = this.client.user?.id;\n\n // Only process if mentioned user is the bot\n if (botId && mentionedId === botId) {\n usedPrefix = mentionMatch[0];\n withoutPrefix = rawContent.slice(mentionMatch[0].length).trim();\n } else {\n }\n }\n }\n\n if (!withoutPrefix) {\n return null;\n }\n\n const [commandName, ...args] = withoutPrefix.split(/\\s+/);\n\n if (!commandName) {\n return null;\n }\n\n return {\n client: this.client,\n content: rawContent,\n authorId: meta.authorId,\n channelId: meta.channelId,\n serverId: meta.serverId,\n args,\n prefix: usedPrefix,\n commandName: commandName.toLowerCase(),\n reply: meta.reply,\n message,\n };\n }\n\n /**\n * Handle a message object using the configured message adapter\n *\n * @example\n * ```ts\n * // With message adapter configured\n * client.on('messageCreate', (message) => {\n * handler.handle(message);\n * });\n * ```\n */\n async handle(message: Message): Promise<boolean> {\n if (!message.channel || !message.author) {\n return false;\n }\n\n // Skip messages from bots\n if (message.author.bot) {\n return false;\n }\n\n const rawContent = message.content;\n const authorId = message.author.id;\n const channelId = message.channel.id;\n const serverId = message.server?.id;\n const reply = async (content: string) => {\n return await message.channel!.send(content);\n };\n\n // rawContent won't be null since a command will be invoked with a prefix\n await this.handleMessage(rawContent!, message, {\n authorId,\n channelId,\n serverId,\n reply,\n });\n\n return true;\n }\n\n /**\n * Handle a raw message string with metadata\n *\n * @example\n * ```ts\n * // Manual usage without message adapter\n * client.on('messageCreate', (message) => {\n * handler.handleMessage(message.content, message, {\n * authorId: message.author.id,\n * channelId: message.channel.id,\n * serverId: message.server?.id,\n * reply: (content) => message.channel.sendMessage(content),\n * });\n * });\n * ```\n */\n async handleMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<void> {\n const ctx = await this.parseMessage(rawContent, message, meta);\n\n if (!ctx) {\n return;\n }\n\n await this.execute(ctx);\n }\n\n /**\n * Execute a command with the given context\n */\n async execute(ctx: CommandContext): Promise<boolean> {\n const registered = this.registry.get(ctx.commandName);\n\n if (!registered) {\n return false;\n }\n\n const { instance, metadata, methodName, classConstructor } = registered;\n\n // Owner-only check\n if (metadata.ownerOnly && !this.owners.has(ctx.authorId)) {\n await ctx.reply(\"This command is owner-only.\");\n return false;\n }\n\n // Guard checks - use classConstructor for guard metadata\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", classConstructor) || [];\n for (const guardClass of guards) {\n const guardInstance = new (guardClass as any)();\n if (typeof guardInstance.run === \"function\") {\n const guardResult = await guardInstance.run(ctx);\n if (!guardResult) {\n if (typeof guardInstance.guardFail === \"function\") {\n await guardInstance.guardFail(ctx);\n } else {\n console.error(\"[Stoatx] Guard check failed but no guardFail method defined on\", guardClass.name);\n }\n return false;\n }\n }\n }\n\n // Cooldown check\n if (!(await this.cooldownManager.check(ctx, metadata))) {\n const remaining = await this.cooldownManager.getRemaining(ctx, metadata);\n\n // For method-based commands, check if instance has onCooldown\n if (typeof (instance as any).onCooldown === \"function\") {\n await (instance as any).onCooldown(ctx, remaining);\n } else {\n await ctx.reply(`Please wait ${(remaining / 1000).toFixed(1)} seconds before using this command again.`);\n }\n return false;\n }\n\n try {\n // Set cooldown before execution to prevent concurrent executions\n if (metadata.cooldown > 0) {\n await this.cooldownManager.set(ctx, metadata);\n }\n\n await (instance as any)[methodName](ctx);\n\n return true;\n } catch (error) {\n // Handle errors\n if (typeof (instance as any).onError === \"function\") {\n await (instance as any).onError(ctx, error as Error);\n } else {\n console.error(`[Stoatx] Error in command ${metadata.name}:`, error);\n }\n return false;\n }\n }\n\n /**\n * Get the command registry\n */\n getRegistry(): CommandRegistry {\n return this.registry;\n }\n\n /**\n * Get a command by name or alias\n */\n getCommand(name: string): RegisteredCommand | undefined {\n return this.registry.get(name);\n }\n\n /**\n * Get all commands\n */\n getCommands(): RegisteredCommand[] {\n return this.registry.getAll();\n }\n\n /**\n * Reload all commands\n */\n async reload(): Promise<void> {\n this.registry.clear();\n if (this.cooldownManager.clear) {\n await this.cooldownManager.clear();\n }\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n return;\n }\n\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n /**\n * Check if a user is an owner\n */\n isOwner(userId: string): boolean {\n return this.owners.has(userId);\n }\n\n /**\n * Add an owner\n */\n addOwner(userId: string): void {\n this.owners.add(userId);\n }\n\n /**\n * Remove an owner\n */\n removeOwner(userId: string): void {\n this.owners.delete(userId);\n }\n\n /**\n * Resolve the prefix for a context\n */\n private async resolvePrefix(serverId?: string | undefined): Promise<string> {\n if (typeof this.prefixResolver === \"function\") {\n return this.prefixResolver({ serverId });\n }\n return this.prefixResolver;\n }\n}\n","// Types\nexport * from \"./types\";\n\n// Decorators\nexport * from \"./decorators\";\n\n// Registry\nexport * from \"./registry\";\n\n// Handler\nexport { Client, DefaultCooldownManager } from \"./handler\";\nexport type { StoatxHandler } from \"./handler\";\nexport * from \"@stoatx/client\";\n"],"mappings":"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","names":["relative"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stoatx",
3
- "version": "0.5.5",
3
+ "version": "0.6.0",
4
4
  "description": "A high-performance, decorator-based command handler for the Stoat ecosystem.",
5
5
  "repository": {
6
6
  "type": "git",