stoatx 0.5.4 → 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,14 +94,85 @@ 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
  })
100
101
  async ban(ctx: Context) {
101
- // ...
102
+ // logic
102
103
  }
103
104
  ```
104
105
 
106
+ ### StoatLifecycle Interface
107
+
108
+ Provides intellisense for lifecycle hooks like `onError` and `onCooldown` on your `@Stoat()` classes.
109
+
110
+ ```typescript
111
+ import { Stoat, SimpleCommand, CommandContext, StoatLifecycle } from "stoatx";
112
+
113
+ @Stoat()
114
+ export class MyCommands implements StoatLifecycle {
115
+ @SimpleCommand({ cooldown: 5000 })
116
+ async ping(ctx: CommandContext) {
117
+ await ctx.reply(`Pong! 🏓`);
118
+ }
119
+
120
+ // Called when the command is placed on cooldown
121
+ async onCooldown(ctx: CommandContext, remaining: number) {
122
+ await ctx.reply(`You are in cooldown, wait ${(remaining / 1000).toFixed(1)} seconds!`);
123
+ }
124
+
125
+ // Called when an error occurs during execution
126
+ async onError(ctx: CommandContext, error: Error) {
127
+ console.error(error);
128
+ await ctx.reply("An error occurred");
129
+ }
130
+ }
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
+
174
+ ## Guards
175
+
105
176
  ### @Guard(GuardClass)
106
177
 
107
178
  Adds a guard check before command execution.
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
  }
@@ -70,9 +73,20 @@ interface CommandContext {
70
73
  */
71
74
  interface StoatLifecycle {
72
75
  /** Optional: Called when an error occurs during command execution */
73
- onError?(ctx: CommandContext, error: Error): Promise<void>;
76
+ onError?(ctx: CommandContext, error: Error): Promise<void> | void;
74
77
  /** Optional: Called when a cooldown is active */
75
- onCooldown?(ctx: CommandContext, remaining: number): Promise<void>;
78
+ onCooldown?(ctx: CommandContext, remaining: number): Promise<void> | void;
79
+ /** Allows the class to contain other methods (such as your commands) */
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>;
76
90
  }
77
91
  interface StoatxGuard {
78
92
  run(ctx: CommandContext): Promise<boolean> | boolean;
@@ -109,6 +123,8 @@ interface StoatxHandlerOptions {
109
123
  extensions?: string[];
110
124
  /** Disable mention prefix support (default: false) */
111
125
  disableMentionPrefix?: boolean;
126
+ /** Custom cooldown manager */
127
+ cooldownManager?: CooldownManager;
112
128
  }
113
129
 
114
130
  /**
@@ -402,6 +418,16 @@ declare class CommandRegistry {
402
418
  private getCategoryFromPath;
403
419
  }
404
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
+ }
405
431
  /**
406
432
  * Client - An extended Client that integrates StoatxHandler directly
407
433
  *
@@ -438,7 +464,7 @@ declare class StoatxHandler {
438
464
  private readonly prefixResolver;
439
465
  private readonly owners;
440
466
  private readonly registry;
441
- private readonly cooldowns;
467
+ private readonly cooldownManager;
442
468
  private readonly disableMentionPrefix;
443
469
  private readonly client;
444
470
  constructor(options: StoatxHandlerOptions);
@@ -529,18 +555,6 @@ declare class StoatxHandler {
529
555
  * Resolve the prefix for a context
530
556
  */
531
557
  private resolvePrefix;
532
- /**
533
- * Check if user is on cooldown
534
- */
535
- private checkCooldown;
536
- /**
537
- * Get remaining cooldown time in ms
538
- */
539
- private getRemainingCooldown;
540
- /**
541
- * Set cooldown for a user
542
- */
543
- private setCooldown;
544
558
  }
545
559
 
546
- 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
  }
@@ -70,9 +73,20 @@ interface CommandContext {
70
73
  */
71
74
  interface StoatLifecycle {
72
75
  /** Optional: Called when an error occurs during command execution */
73
- onError?(ctx: CommandContext, error: Error): Promise<void>;
76
+ onError?(ctx: CommandContext, error: Error): Promise<void> | void;
74
77
  /** Optional: Called when a cooldown is active */
75
- onCooldown?(ctx: CommandContext, remaining: number): Promise<void>;
78
+ onCooldown?(ctx: CommandContext, remaining: number): Promise<void> | void;
79
+ /** Allows the class to contain other methods (such as your commands) */
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>;
76
90
  }
77
91
  interface StoatxGuard {
78
92
  run(ctx: CommandContext): Promise<boolean> | boolean;
@@ -109,6 +123,8 @@ interface StoatxHandlerOptions {
109
123
  extensions?: string[];
110
124
  /** Disable mention prefix support (default: false) */
111
125
  disableMentionPrefix?: boolean;
126
+ /** Custom cooldown manager */
127
+ cooldownManager?: CooldownManager;
112
128
  }
113
129
 
114
130
  /**
@@ -402,6 +418,16 @@ declare class CommandRegistry {
402
418
  private getCategoryFromPath;
403
419
  }
404
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
+ }
405
431
  /**
406
432
  * Client - An extended Client that integrates StoatxHandler directly
407
433
  *
@@ -438,7 +464,7 @@ declare class StoatxHandler {
438
464
  private readonly prefixResolver;
439
465
  private readonly owners;
440
466
  private readonly registry;
441
- private readonly cooldowns;
467
+ private readonly cooldownManager;
442
468
  private readonly disableMentionPrefix;
443
469
  private readonly client;
444
470
  constructor(options: StoatxHandlerOptions);
@@ -529,18 +555,6 @@ declare class StoatxHandler {
529
555
  * Resolve the prefix for a context
530
556
  */
531
557
  private resolvePrefix;
532
- /**
533
- * Check if user is on cooldown
534
- */
535
- private checkCooldown;
536
- /**
537
- * Get remaining cooldown time in ms
538
- */
539
- private getRemainingCooldown;
540
- /**
541
- * Set cooldown for a user
542
- */
543
- private setCooldown;
544
558
  }
545
559
 
546
- 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 {
@@ -681,10 +716,10 @@ var StoatxHandler = class {
681
716
  return false;
682
717
  }
683
718
  try {
684
- await instance[methodName](ctx);
685
719
  if (metadata.cooldown > 0) {
686
- this.setCooldown(ctx.authorId, metadata);
720
+ await this.cooldownManager.set(ctx, metadata);
687
721
  }
722
+ await instance[methodName](ctx);
688
723
  return true;
689
724
  } catch (error) {
690
725
  if (typeof instance.onError === "function") {
@@ -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,37 +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 userCooldown = commandCooldowns.get(userId);
763
- if (!userCooldown) return true;
764
- return Date.now() >= userCooldown;
765
- }
766
- /**
767
- * Get remaining cooldown time in ms
768
- */
769
- getRemainingCooldown(userId, metadata) {
770
- const commandCooldowns = this.cooldowns.get(metadata.name);
771
- if (!commandCooldowns) return 0;
772
- const userCooldown = commandCooldowns.get(userId);
773
- if (!userCooldown) return 0;
774
- return Math.max(0, userCooldown - Date.now());
775
- }
776
- /**
777
- * Set cooldown for a user
778
- */
779
- setCooldown(userId, metadata) {
780
- if (!this.cooldowns.has(metadata.name)) {
781
- this.cooldowns.set(metadata.name, /* @__PURE__ */ new Map());
782
- }
783
- const commandCooldowns = this.cooldowns.get(metadata.name);
784
- commandCooldowns.set(userId, Date.now() + metadata.cooldown);
785
- }
786
792
  };
787
793
 
788
794
  // src/index.ts
@@ -791,6 +797,7 @@ __reExport(index_exports, require("@stoatx/client"), module.exports);
791
797
  0 && (module.exports = {
792
798
  Client,
793
799
  CommandRegistry,
800
+ DefaultCooldownManager,
794
801
  Guard,
795
802
  METADATA_KEYS,
796
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 await (instance as any)[methodName](ctx);\n\n // Set cooldown after successful execution\n if (metadata.cooldown > 0) {\n this.setCooldown(ctx.authorId, metadata);\n }\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 userCooldown = commandCooldowns.get(userId);\n if (!userCooldown) return true;\n\n return Date.now() >= userCooldown;\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 {
@@ -632,10 +666,10 @@ var StoatxHandler = class {
632
666
  return false;
633
667
  }
634
668
  try {
635
- await instance[methodName](ctx);
636
669
  if (metadata.cooldown > 0) {
637
- this.setCooldown(ctx.authorId, metadata);
670
+ await this.cooldownManager.set(ctx, metadata);
638
671
  }
672
+ await instance[methodName](ctx);
639
673
  return true;
640
674
  } catch (error) {
641
675
  if (typeof instance.onError === "function") {
@@ -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,37 +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 userCooldown = commandCooldowns.get(userId);
714
- if (!userCooldown) return true;
715
- return Date.now() >= userCooldown;
716
- }
717
- /**
718
- * Get remaining cooldown time in ms
719
- */
720
- getRemainingCooldown(userId, metadata) {
721
- const commandCooldowns = this.cooldowns.get(metadata.name);
722
- if (!commandCooldowns) return 0;
723
- const userCooldown = commandCooldowns.get(userId);
724
- if (!userCooldown) return 0;
725
- return Math.max(0, userCooldown - Date.now());
726
- }
727
- /**
728
- * Set cooldown for a user
729
- */
730
- setCooldown(userId, metadata) {
731
- if (!this.cooldowns.has(metadata.name)) {
732
- this.cooldowns.set(metadata.name, /* @__PURE__ */ new Map());
733
- }
734
- const commandCooldowns = this.cooldowns.get(metadata.name);
735
- commandCooldowns.set(userId, Date.now() + metadata.cooldown);
736
- }
737
742
  };
738
743
 
739
744
  // src/index.ts
@@ -741,6 +746,7 @@ export * from "@stoatx/client";
741
746
  export {
742
747
  Client,
743
748
  CommandRegistry,
749
+ DefaultCooldownManager,
744
750
  Guard,
745
751
  METADATA_KEYS,
746
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 await (instance as any)[methodName](ctx);\n\n // Set cooldown after successful execution\n if (metadata.cooldown > 0) {\n this.setCooldown(ctx.authorId, metadata);\n }\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 userCooldown = commandCooldowns.get(userId);\n if (!userCooldown) return true;\n\n return Date.now() >= userCooldown;\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.4",
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",