stoatx 0.5.4 → 0.5.5
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 +30 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,10 +98,39 @@ Marks a method as a command.
|
|
|
98
98
|
nsfw: false,
|
|
99
99
|
})
|
|
100
100
|
async ban(ctx: Context) {
|
|
101
|
-
//
|
|
101
|
+
// logic
|
|
102
102
|
}
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
### StoatLifecycle Interface
|
|
106
|
+
|
|
107
|
+
Provides intellisense for lifecycle hooks like `onError` and `onCooldown` on your `@Stoat()` classes.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { Stoat, SimpleCommand, CommandContext, StoatLifecycle } from "stoatx";
|
|
111
|
+
|
|
112
|
+
@Stoat()
|
|
113
|
+
export class MyCommands implements StoatLifecycle {
|
|
114
|
+
@SimpleCommand({ cooldown: 5000 })
|
|
115
|
+
async ping(ctx: CommandContext) {
|
|
116
|
+
await ctx.reply(`Pong! 🏓`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Called when the command is placed on cooldown
|
|
120
|
+
async onCooldown(ctx: CommandContext, remaining: number) {
|
|
121
|
+
await ctx.reply(`You are in cooldown, wait ${(remaining / 1000).toFixed(1)} seconds!`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Called when an error occurs during execution
|
|
125
|
+
async onError(ctx: CommandContext, error: Error) {
|
|
126
|
+
console.error(error);
|
|
127
|
+
await ctx.reply("An error occurred");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Guards
|
|
133
|
+
|
|
105
134
|
### @Guard(GuardClass)
|
|
106
135
|
|
|
107
136
|
Adds a guard check before command execution.
|
package/dist/index.d.mts
CHANGED
|
@@ -70,9 +70,11 @@ interface CommandContext {
|
|
|
70
70
|
*/
|
|
71
71
|
interface StoatLifecycle {
|
|
72
72
|
/** Optional: Called when an error occurs during command execution */
|
|
73
|
-
onError?(ctx: CommandContext, error: Error): Promise<void
|
|
73
|
+
onError?(ctx: CommandContext, error: Error): Promise<void> | void;
|
|
74
74
|
/** Optional: Called when a cooldown is active */
|
|
75
|
-
onCooldown?(ctx: CommandContext, remaining: number): Promise<void
|
|
75
|
+
onCooldown?(ctx: CommandContext, remaining: number): Promise<void> | void;
|
|
76
|
+
/** Allows the class to contain other methods (such as your commands) */
|
|
77
|
+
[key: string]: any;
|
|
76
78
|
}
|
|
77
79
|
interface StoatxGuard {
|
|
78
80
|
run(ctx: CommandContext): Promise<boolean> | boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -70,9 +70,11 @@ interface CommandContext {
|
|
|
70
70
|
*/
|
|
71
71
|
interface StoatLifecycle {
|
|
72
72
|
/** Optional: Called when an error occurs during command execution */
|
|
73
|
-
onError?(ctx: CommandContext, error: Error): Promise<void
|
|
73
|
+
onError?(ctx: CommandContext, error: Error): Promise<void> | void;
|
|
74
74
|
/** Optional: Called when a cooldown is active */
|
|
75
|
-
onCooldown?(ctx: CommandContext, remaining: number): Promise<void
|
|
75
|
+
onCooldown?(ctx: CommandContext, remaining: number): Promise<void> | void;
|
|
76
|
+
/** Allows the class to contain other methods (such as your commands) */
|
|
77
|
+
[key: string]: any;
|
|
76
78
|
}
|
|
77
79
|
interface StoatxGuard {
|
|
78
80
|
run(ctx: CommandContext): Promise<boolean> | boolean;
|
package/dist/index.js
CHANGED
|
@@ -681,10 +681,10 @@ var StoatxHandler = class {
|
|
|
681
681
|
return false;
|
|
682
682
|
}
|
|
683
683
|
try {
|
|
684
|
-
await instance[methodName](ctx);
|
|
685
684
|
if (metadata.cooldown > 0) {
|
|
686
685
|
this.setCooldown(ctx.authorId, metadata);
|
|
687
686
|
}
|
|
687
|
+
await instance[methodName](ctx);
|
|
688
688
|
return true;
|
|
689
689
|
} catch (error) {
|
|
690
690
|
if (typeof instance.onError === "function") {
|
|
@@ -759,9 +759,13 @@ var StoatxHandler = class {
|
|
|
759
759
|
if (metadata.cooldown <= 0) return true;
|
|
760
760
|
const commandCooldowns = this.cooldowns.get(metadata.name);
|
|
761
761
|
if (!commandCooldowns) return true;
|
|
762
|
-
const
|
|
763
|
-
if (!
|
|
764
|
-
|
|
762
|
+
const expirationTime = commandCooldowns.get(userId);
|
|
763
|
+
if (!expirationTime) return true;
|
|
764
|
+
if (Date.now() > expirationTime) {
|
|
765
|
+
commandCooldowns.delete(userId);
|
|
766
|
+
return true;
|
|
767
|
+
}
|
|
768
|
+
return false;
|
|
765
769
|
}
|
|
766
770
|
/**
|
|
767
771
|
* Get remaining cooldown time in ms
|
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 } from \"./handler\";\nexport type { StoatxHandler } from \"./handler\";\nexport * from \"@stoatx/client\";\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\nimport { decoratorStore } from \"./store\";\n\n/**\n * @Stoat\n * Marks a class as a Stoat command container.\n * Use this decorator on classes that contain @SimpleCommand methods.\n *\n * @example\n * ```ts\n * import { Stoat, SimpleCommand, CommandContext } from 'stoatx';\n *\n * @Stoat()\n * class ModerationCommands {\n * @SimpleCommand({ name: 'ban', description: 'Ban a user' })\n * async ban(ctx: CommandContext) {\n * await ctx.reply('User banned!');\n * }\n *\n * @SimpleCommand({ name: 'kick', description: 'Kick a user' })\n * async kick(ctx: CommandContext) {\n * await ctx.reply('User kicked!');\n * }\n * }\n * ```\n */\nexport function Stoat(): ClassDecorator {\n return (target: Function) => {\n Reflect.defineMetadata(METADATA_KEYS.IS_STOAT_CLASS, true, target);\n decoratorStore.registerStoatClass(target);\n };\n}\n\n/**\n * Check if a class is decorated with @Stoat\n */\nexport function isStoatClass(target: Function): boolean {\n return Reflect.getMetadata(METADATA_KEYS.IS_STOAT_CLASS, target) === true;\n}\n","/**\n * Metadata keys used by decorators\n */\nexport const METADATA_KEYS = {\n IS_STOAT_CLASS: Symbol(\"stoatx:stoat:isClass\"),\n SIMPLE_COMMANDS: Symbol(\"stoatx:stoat:simpleCommands\"),\n GUARDS: \"stoatx:command:guards\",\n EVENTS: Symbol(\"stoatx:stoat:events\"),\n} as const;\n","import type { RegisteredCommand } from \"../registry\";\n\n/**\n * Global store for all decorated classes and commands\n * This allows automatic registration without directory scanning\n */\nexport class DecoratorStore {\n private static instance: DecoratorStore;\n\n /** Stoat classes with their SimpleCommand methods */\n private stoatClasses: Map<Function, object> = new Map();\n\n /** Registered commands from @Stoat/@SimpleCommand decorators */\n private commands: RegisteredCommand[] = [];\n\n /** Whether the store has been initialized */\n private initialized = false;\n\n private constructor() {}\n\n static getInstance(): DecoratorStore {\n if (!DecoratorStore.instance) {\n DecoratorStore.instance = new DecoratorStore();\n }\n return DecoratorStore.instance;\n }\n\n /**\n * Register a @Stoat decorated class\n */\n registerStoatClass(classConstructor: Function): void {\n if (!this.stoatClasses.has(classConstructor)) {\n // Create instance immediately when decorated\n const instance = new (classConstructor as new () => object)();\n this.stoatClasses.set(classConstructor, instance);\n }\n }\n\n /**\n * Get all registered Stoat classes with their instances\n */\n getStoatClasses(): Map<Function, object> {\n return this.stoatClasses;\n }\n\n /**\n * Add a registered command\n */\n addCommand(command: RegisteredCommand): void {\n this.commands.push(command);\n }\n\n /**\n * Get all registered commands\n */\n getCommands(): RegisteredCommand[] {\n return this.commands;\n }\n\n /**\n * Clear all registered classes (useful for testing)\n */\n clear(): void {\n this.stoatClasses.clear();\n this.commands = [];\n this.initialized = false;\n }\n\n /**\n * Mark as initialized\n */\n markInitialized(): void {\n this.initialized = true;\n }\n\n /**\n * Check if initialized\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n}\n\nexport const decoratorStore = DecoratorStore.getInstance();\n","import \"reflect-metadata\";\nimport type { SimpleCommandOptions } from \"../types\";\nimport { METADATA_KEYS } from \"./keys\";\n\n/**\n * Stored simple command metadata from method decorator\n */\nexport interface SimpleCommandDefinition {\n methodName: string;\n options: SimpleCommandOptions;\n}\n\n/**\n * @SimpleCommand\n * Marks a method as a simple command within a @Stoat() decorated class.\n *\n * @example\n * ```ts\n * @Stoat()\n * class Example {\n * @SimpleCommand({ name: 'ping', description: 'Replies with Pong!' })\n * async ping(ctx: CommandContext) {\n * await ctx.reply('Pong!');\n * }\n *\n * @SimpleCommand({ aliases: ['perm'], name: 'permission' })\n * async permission(ctx: CommandContext) {\n * await ctx.reply('Access granted');\n * }\n * }\n * ```\n */\nexport function SimpleCommand(options: SimpleCommandOptions = {}): MethodDecorator {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n\n // Get existing simple commands or create new array\n const existingCommands: SimpleCommandDefinition[] =\n Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, constructor) || [];\n\n // Add this command definition\n existingCommands.push({\n methodName: String(propertyKey),\n options,\n });\n\n Reflect.defineMetadata(METADATA_KEYS.SIMPLE_COMMANDS, existingCommands, constructor);\n\n return descriptor;\n };\n}\n\n/**\n * Get all simple command definitions from a @Stoat class\n */\nexport function getSimpleCommands(target: Function): SimpleCommandDefinition[] {\n return Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, target) || [];\n}\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\n\n/**\n * @Guard\n * Runs before a command to check if it should execute.\n * Should return true to allow execution, false to block.\n * Applied on @Stoat classes to guard all contained @SimpleCommand methods.\n *\n * @example\n * ```ts\n * import { Guard, Stoat, SimpleCommand, CommandContext } from 'stoatx';\n *\n * // Define a guard\n * class NotBot implements StoatxGuard {\n * run(ctx: CommandContext): boolean {\n * return !ctx.message.author.bot;\n * }\n *\n * guardFail(ctx: CommandContext): void {\n * ctx.reply(\"Bots cannot use this command!\");\n * }\n * }\n *\n * @Stoat()\n * @Guard(NotBot)\n * class AdminCommands {\n * @SimpleCommand({ name: 'admin', description: 'Admin only command' })\n * async admin(ctx: CommandContext) {\n * ctx.reply(\"You passed the guard check!\");\n * }\n * }\n * ```\n */\nexport function Guard(guardClass: Function): ClassDecorator {\n return (target: Function) => {\n const existingGuards: Function[] = Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];\n existingGuards.push(guardClass);\n Reflect.defineMetadata(METADATA_KEYS.GUARDS, existingGuards, target);\n };\n}\n\n/**\n * Get all guards from a decorated class\n */\nexport function getGuards(target: Function): Function[] {\n return Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];\n}\n","import \"reflect-metadata\";\nimport { METADATA_KEYS } from \"./keys\";\n\nexport interface EventDefinition {\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\nfunction createEventDecorator(event: string, type: \"on\" | \"once\"): MethodDecorator {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n\n // Retrieve existing events or initialize a fresh array\n const existingEvents: EventDefinition[] = Reflect.getMetadata(METADATA_KEYS.EVENTS, constructor) || [];\n\n existingEvents.push({\n methodName: String(propertyKey),\n event,\n type,\n });\n\n Reflect.defineMetadata(METADATA_KEYS.EVENTS, existingEvents, constructor);\n\n return descriptor;\n };\n}\n\n/**\n * @On\n * Triggered on every occurrence of the event.\n * Marks a method to be executed whenever the specified client event is emitted.\n *\n * @example\n * ```ts\n * import { Stoat, On } from 'stoatx';\n * import { Message, Client } from 'stoat.js';\n *\n * @Stoat()\n * class BotEvents {\n * @On('messageCreate')\n * async onMessage(message: Message, client: Client) {\n * console.log('New message received:', message.content);\n * }\n * }\n * ```\n *\n * @param event The name of the client event to listen to\n */\nexport function On(event: string): MethodDecorator {\n return createEventDecorator(event, \"on\");\n}\n\n/**\n * @Once\n * Triggered only fully once.\n * Marks a method to be executed only the FIRST time the specified client event is emitted.\n *\n * @example\n * ```ts\n * import { Stoat, Once } from 'stoatx';\n * import { Client } from 'stoat.js';\n *\n * @Stoat()\n * class BotEvents {\n * @Once('ready')\n * async onReady(client: Client) {\n * console.log('Bot successfully started and logged in!');\n * }\n * }\n * ```\n *\n * @param event The name of the client event to listen to\n */\nexport function Once(event: string): MethodDecorator {\n return createEventDecorator(event, \"once\");\n}\n\n/**\n * Get all event definitions from a @Stoat class\n */\nexport function getEventsMetadata(target: Function): EventDefinition[] {\n return Reflect.getMetadata(METADATA_KEYS.EVENTS, target) || [];\n}\n","import type { CommandMetadata, SimpleCommandOptions } from \"../types\";\n\n/**\n * Build CommandMetadata from SimpleCommandOptions\n */\nexport function buildSimpleCommandMetadata(\n options: SimpleCommandOptions,\n methodName: string,\n category?: string,\n): CommandMetadata {\n return {\n name: options.name ?? methodName.toLowerCase(),\n description: options.description ?? \"No description provided\",\n aliases: options.aliases ?? [],\n permissions: options.permissions ?? [],\n category: options.category ?? category ?? \"uncategorized\",\n cooldown: options.cooldown ?? 0,\n nsfw: options.nsfw ?? false,\n ownerOnly: options.ownerOnly ?? false,\n };\n}\n","import * as path from \"node:path\";\nimport * as fs from \"node:fs/promises\";\nimport { pathToFileURL } from \"node:url\";\nimport { glob } from \"tinyglobby\";\nimport { buildSimpleCommandMetadata, getSimpleCommands, getEventsMetadata } from \"./decorators\";\nimport { decoratorStore } from \"./decorators/store\";\nimport type { CommandMetadata } from \"./types\";\n\ninterface AutoDiscoveryOptions {\n roots?: string[];\n include?: string[];\n ignore?: string[];\n}\n\n/**\n * Stored command entry from @Stoat/@SimpleCommand registration.\n */\nexport interface RegisteredCommand {\n /** Instance of the @Stoat class */\n instance: object;\n /** Command metadata */\n metadata: CommandMetadata;\n /** Method name to call */\n methodName: string;\n /** The original class constructor (for guard validation) */\n classConstructor: Function;\n}\n\n/**\n * Stored event entry from @On/@Once registration.\n */\nexport interface RegisteredEvent {\n instance: object;\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\n/**\n * CommandRegistry - Scans directories and stores commands in a Map\n *\n * @example\n * ```ts\n * const registry = new CommandRegistry();\n * await registry.loadFromDirectory('./src/commands');\n *\n * const ping = registry.get('ping');\n * const allCommands = registry.getAll();\n * ```\n */\nexport class CommandRegistry {\n private static readonly DEFAULT_AUTO_DISCOVERY_IGNORES = [\n \"**/node_modules/**\",\n \"**/.git/**\",\n \"**/*.d.ts\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n ];\n\n private readonly commands: Map<string, RegisteredCommand> = new Map();\n private readonly aliases: Map<string, string> = new Map();\n private readonly registeredEvents: RegisteredEvent[] = [];\n private readonly extensions: string[];\n private readonly processedStoatClasses: Set<Function> = new Set();\n\n constructor(extensions: string[] = [\".js\", \".mjs\", \".cjs\"]) {\n this.extensions = extensions;\n }\n\n /**\n * Get the number of registered commands\n */\n get size(): number {\n return this.commands.size;\n }\n\n /**\n * Load commands from a directory using glob pattern matching\n */\n async loadFromDirectory(directory: string): Promise<void> {\n const patterns = this.extensions.map((ext) => path.join(directory, \"**\", `*${ext}`).replace(/\\\\/g, \"/\"));\n\n for (const pattern of patterns) {\n const files = await glob(pattern, {\n ignore: [\"**/*.d.ts\", \"**/*.test.ts\", \"**/*.spec.ts\"],\n absolute: true,\n });\n\n for (const file of files) {\n await this.loadFile(file, directory);\n }\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n /**\n * Auto-discover command files across one or more roots.\n */\n async autoDiscover(options: AutoDiscoveryOptions = {}): Promise<void> {\n const roots = options.roots?.length ? options.roots : [process.cwd()];\n const includePatterns = options.include?.length ? options.include : this.getDefaultAutoDiscoveryPatterns();\n\n const patterns = roots.flatMap((root) =>\n includePatterns.map((pattern) => path.join(root, pattern).replace(/\\\\/g, \"/\")),\n );\n\n const files = await glob(patterns, {\n ignore: [...CommandRegistry.DEFAULT_AUTO_DISCOVERY_IGNORES, ...(options.ignore ?? [])],\n absolute: true,\n });\n\n const uniqueFiles = [...new Set(files)];\n let candidateFiles = 0;\n for (const file of uniqueFiles) {\n if (!(await this.isLikelyCommandModule(file))) {\n continue;\n }\n candidateFiles++;\n\n const baseDir =\n roots.find((root) => {\n const relative = path.relative(root, file);\n return relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n }) ?? roots[0]!;\n await this.loadFile(file, baseDir);\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n private getDefaultAutoDiscoveryPatterns(): string[] {\n // discordx-like default: scan broadly, then register only decorated classes\n return this.extensions.map((ext) => `**/*${ext}`);\n }\n\n private async isLikelyCommandModule(filePath: string): Promise<boolean> {\n try {\n const source = await fs.readFile(filePath, \"utf8\");\n return source.includes(\"Stoat\") || source.includes(\"SimpleCommand\") || source.includes(\"stoatx:command\");\n } catch {\n // If the file can't be pre-read, fall back to attempting import.\n return true;\n }\n }\n\n /**\n * Register a command instance\n */\n register(instance: object, metadata: CommandMetadata, classConstructor: Function, methodName: string): void {\n const name = metadata.name.toLowerCase();\n\n if (this.commands.has(name)) {\n console.warn(`[Stoatx] Duplicate command name: ${name}. Skipping...`);\n return;\n }\n\n this.validateGuards(classConstructor, metadata.name);\n\n this.commands.set(name, { instance, metadata, methodName, classConstructor });\n\n for (const alias of metadata.aliases) {\n const aliasLower = alias.toLowerCase();\n if (this.aliases.has(aliasLower) || this.commands.has(aliasLower)) {\n console.warn(`[Stoatx] Duplicate alias: ${aliasLower}. Skipping...`);\n continue;\n }\n this.aliases.set(aliasLower, name);\n }\n }\n\n /**\n * Get a command by name or alias\n */\n get(name: string): RegisteredCommand | undefined {\n const lowerName = name.toLowerCase();\n const resolvedName = this.aliases.get(lowerName) ?? lowerName;\n return this.commands.get(resolvedName);\n }\n\n /**\n * Check if a command exists\n */\n has(name: string): boolean {\n const lowerName = name.toLowerCase();\n return this.commands.has(lowerName) || this.aliases.has(lowerName);\n }\n\n /**\n * Get all registered commands\n */\n getAll(): RegisteredCommand[] {\n return Array.from(this.commands.values());\n }\n\n /**\n * Get all command metadata\n */\n getAllMetadata(): CommandMetadata[] {\n return this.getAll().map((c) => c.metadata);\n }\n\n /**\n * Get all registered events\n */\n getEvents(): RegisteredEvent[] {\n return this.registeredEvents;\n }\n\n /**\n * Get commands grouped by category\n */\n getByCategory(): Map<string, RegisteredCommand[]> {\n const categories = new Map<string, RegisteredCommand[]>();\n\n for (const cmd of this.commands.values()) {\n const category = cmd.metadata.category;\n const existing = categories.get(category) ?? [];\n existing.push(cmd);\n categories.set(category, existing);\n }\n\n return categories;\n }\n\n /**\n * Clear all commands\n */\n clear(): void {\n this.commands.clear();\n this.aliases.clear();\n this.registeredEvents.length = 0;\n this.processedStoatClasses.clear();\n }\n\n /**\n * Iterate over commands\n */\n [Symbol.iterator](): IterableIterator<[string, RegisteredCommand]> {\n return this.commands.entries();\n }\n\n /**\n * Iterate over command values\n */\n values(): IterableIterator<RegisteredCommand> {\n return this.commands.values();\n }\n\n /**\n * Iterate over command names\n */\n keys(): IterableIterator<string> {\n return this.commands.keys();\n }\n\n /**\n * Validate that all guards on a command implement the required methods\n * @param commandClass\n * @param commandName\n * @private\n */\n private validateGuards(commandClass: Function, commandName: string): void {\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", commandClass) || [];\n\n for (const GuardClass of guards) {\n const guardInstance = new (GuardClass as any)();\n\n if (typeof guardInstance.run !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a run() method.`,\n );\n process.exit(1);\n }\n\n if (typeof guardInstance.guardFail !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a guardFail() method.`,\n );\n console.error(`[Stoatx] All guards must implement guardFail() to handle failed checks.`);\n process.exit(1);\n }\n }\n }\n\n /**\n * Load commands from a single file\n */\n private async loadFile(filePath: string, baseDir: string): Promise<void> {\n try {\n const knownStoatClasses = new Set(decoratorStore.getStoatClasses().keys());\n const fileUrl = pathToFileURL(filePath).href;\n await import(fileUrl);\n\n const allStoatClasses = decoratorStore.getStoatClasses();\n for (const [stoatClass, stoatInstance] of allStoatClasses.entries()) {\n if (knownStoatClasses.has(stoatClass) || this.processedStoatClasses.has(stoatClass)) {\n continue;\n }\n this.registerStoatClassCommands(stoatClass, stoatInstance, filePath, baseDir);\n }\n } catch (error) {\n console.error(`[Stoatx] Failed to load command file: ${filePath}`, error);\n }\n }\n\n private registerStoatClassCommands(stoatClass: Function, instance: object, filePath: string, baseDir: string): void {\n const simpleCommands = getSimpleCommands(stoatClass);\n const events = getEventsMetadata(stoatClass);\n const category = this.getCategoryFromPath(filePath, baseDir);\n\n if (simpleCommands.length === 0 && events.length === 0) {\n console.warn(\n `[Stoatx] Class ${stoatClass.name} is decorated with @Stoat but has no @SimpleCommand, @On or @Once methods. Skipping...`,\n );\n this.processedStoatClasses.add(stoatClass);\n return;\n }\n\n for (const cmdDef of simpleCommands) {\n const method = (instance as any)[cmdDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${cmdDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n const metadata = buildSimpleCommandMetadata(cmdDef.options, cmdDef.methodName, category);\n this.register(instance, metadata, stoatClass, cmdDef.methodName);\n }\n\n for (const eventDef of events) {\n const method = (instance as any)[eventDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${eventDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n this.registeredEvents.push({\n instance,\n methodName: eventDef.methodName,\n event: eventDef.event,\n type: eventDef.type,\n });\n }\n\n this.processedStoatClasses.add(stoatClass);\n }\n\n /**\n * Derive category from file path relative to base directory\n */\n private getCategoryFromPath(filePath: string, baseDir: string): string | undefined {\n const relative = path.relative(baseDir, filePath);\n const parts = relative.split(path.sep);\n\n if (parts.length > 1) {\n return parts[0];\n }\n\n return undefined;\n }\n}\n","import \"reflect-metadata\";\nimport { CommandRegistry, RegisteredCommand } from \"./registry\";\nimport type { CommandContext, CommandMetadata, StoatxDiscoveryOptions, StoatxHandlerOptions } from \"./types\";\nimport { Client as StoatClient, ClientEvents, Message } from \"@stoatx/client\";\n\n/**\n * Client - An extended Client that integrates StoatxHandler directly\n *\n * @example\n * ```ts\n * import { Client } from 'stoatx';\n *\n * const client = new Client({\n * prefix: '!',\n * owners: ['owner-user-id'],\n * });\n *\n * await client.initCommands();\n * ```\n */\nexport class Client extends StoatClient {\n public readonly handler: StoatxHandler;\n\n constructor(options: Omit<StoatxHandlerOptions, \"client\">) {\n super();\n this.handler = new StoatxHandler({ ...options, client: this });\n\n // Automatically hook up the message handler\n this.on(\"messageCreate\", async (message) => {\n await this.handler.handle(message);\n });\n }\n\n /**\n * Initialize the StoatxHandler commands\n */\n async initCommands(): Promise<void> {\n await this.handler.init();\n }\n}\n\n/**\n * StoatxHandler - The execution engine for commands\n *\n * Handles message parsing, middleware execution, and command dispatching\n *\n * @internal This class is not intended to be instantiated directly. Use the `Client` from `stoatx` instead.\n */\nexport class StoatxHandler {\n private readonly commandsDir: string | undefined;\n private readonly discoveryOptions: StoatxDiscoveryOptions | undefined;\n private readonly prefixResolver: string | ((ctx: { serverId?: string | undefined }) => string | Promise<string>);\n private readonly owners: Set<string>;\n private readonly registry: CommandRegistry;\n private readonly cooldowns: Map<string, Map<string, number>> = new Map();\n private readonly disableMentionPrefix: boolean;\n private readonly client: StoatClient;\n constructor(options: StoatxHandlerOptions) {\n this.client = options.client;\n this.commandsDir = options.commandsDir;\n this.discoveryOptions = options.discovery;\n this.prefixResolver = options.prefix;\n this.owners = new Set(options.owners ?? []);\n this.registry = new CommandRegistry(options.extensions);\n this.disableMentionPrefix = options.disableMentionPrefix ?? false;\n }\n\n /**\n * Initialize the handler - load all commands\n */\n async init(): Promise<void> {\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n } else {\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n this.attachEvents();\n }\n\n /**\n * Attach registered events to the client\n */\n private attachEvents(): void {\n const events = this.registry.getEvents();\n\n for (const eventDef of events) {\n const handler = async (...args: any[]) => {\n try {\n await (eventDef.instance as any)[eventDef.methodName](...args, this.client);\n } catch (error) {\n console.error(\n `[Stoatx] Event Handler Error in @${eventDef.type === \"on\" ? \"On\" : \"Once\"}('${eventDef.event}'):`,\n error,\n );\n }\n };\n\n const eventName = eventDef.event as keyof ClientEvents;\n if (eventDef.type === \"once\") {\n this.client.once(eventName, handler);\n } else {\n this.client.on(eventName, handler);\n }\n }\n }\n\n /**\n * Parse a raw message into command context\n */\n async parseMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<CommandContext | null> {\n const prefix = await this.resolvePrefix(meta.serverId);\n let usedPrefix = prefix;\n let withoutPrefix = \"\";\n\n // Check for string prefix\n if (rawContent.startsWith(prefix)) {\n withoutPrefix = rawContent.slice(prefix.length).trim();\n usedPrefix = prefix;\n }\n // Check for mention prefix (e.g., \"<@bot-id> command\") - unless disabled\n else if (!this.disableMentionPrefix && rawContent.match(/^<@!?[\\w]+>/)) {\n const mentionMatch = rawContent.match(/^<@!?([\\w]+)>\\s*/);\n if (mentionMatch) {\n const mentionedId = mentionMatch[1];\n const botId = this.client.user?.id;\n\n // Only process if mentioned user is the bot\n if (botId && mentionedId === botId) {\n usedPrefix = mentionMatch[0];\n withoutPrefix = rawContent.slice(mentionMatch[0].length).trim();\n } else {\n }\n }\n }\n\n if (!withoutPrefix) {\n return null;\n }\n\n const [commandName, ...args] = withoutPrefix.split(/\\s+/);\n\n if (!commandName) {\n return null;\n }\n\n return {\n client: this.client,\n content: rawContent,\n authorId: meta.authorId,\n channelId: meta.channelId,\n serverId: meta.serverId,\n args,\n prefix: usedPrefix,\n commandName: commandName.toLowerCase(),\n reply: meta.reply,\n message,\n };\n }\n\n /**\n * Handle a message object using the configured message adapter\n *\n * @example\n * ```ts\n * // With message adapter configured\n * client.on('messageCreate', (message) => {\n * handler.handle(message);\n * });\n * ```\n */\n async handle(message: Message): Promise<boolean> {\n if (!message.channel || !message.author) {\n return false;\n }\n\n // Skip messages from bots\n if (message.author.bot) {\n return false;\n }\n\n const rawContent = message.content;\n const authorId = message.author.id;\n const channelId = message.channel.id;\n const serverId = message.server?.id;\n const reply = async (content: string) => {\n return await message.channel!.send(content);\n };\n\n // rawContent won't be null since a command will be invoked with a prefix\n await this.handleMessage(rawContent!, message, {\n authorId,\n channelId,\n serverId,\n reply,\n });\n\n return true;\n }\n\n /**\n * Handle a raw message string with metadata\n *\n * @example\n * ```ts\n * // Manual usage without message adapter\n * client.on('messageCreate', (message) => {\n * handler.handleMessage(message.content, message, {\n * authorId: message.author.id,\n * channelId: message.channel.id,\n * serverId: message.server?.id,\n * reply: (content) => message.channel.sendMessage(content),\n * });\n * });\n * ```\n */\n async handleMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<void> {\n const ctx = await this.parseMessage(rawContent, message, meta);\n\n if (!ctx) {\n return;\n }\n\n await this.execute(ctx);\n }\n\n /**\n * Execute a command with the given context\n */\n async execute(ctx: CommandContext): Promise<boolean> {\n const registered = this.registry.get(ctx.commandName);\n\n if (!registered) {\n return false;\n }\n\n const { instance, metadata, methodName, classConstructor } = registered;\n\n // Owner-only check\n if (metadata.ownerOnly && !this.owners.has(ctx.authorId)) {\n await ctx.reply(\"This command is owner-only.\");\n return false;\n }\n\n // Guard checks - use classConstructor for guard metadata\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", classConstructor) || [];\n for (const guardClass of guards) {\n const guardInstance = new (guardClass as any)();\n if (typeof guardInstance.run === \"function\") {\n const guardResult = await guardInstance.run(ctx);\n if (!guardResult) {\n if (typeof guardInstance.guardFail === \"function\") {\n await guardInstance.guardFail(ctx);\n } else {\n console.error(\"[Stoatx] Guard check failed but no guardFail method defined on\", guardClass.name);\n }\n return false;\n }\n }\n }\n\n // Cooldown check\n if (!this.checkCooldown(ctx.authorId, metadata)) {\n const remaining = this.getRemainingCooldown(ctx.authorId, metadata);\n\n // For method-based commands, check if instance has onCooldown\n if (typeof (instance as any).onCooldown === \"function\") {\n await (instance as any).onCooldown(ctx, remaining);\n } else {\n await ctx.reply(`Please wait ${(remaining / 1000).toFixed(1)} seconds before using this command again.`);\n }\n return false;\n }\n\n try {\n // Set cooldown before execution to prevent concurrent executions\n if (metadata.cooldown > 0) {\n this.setCooldown(ctx.authorId, metadata);\n }\n\n await (instance as any)[methodName](ctx);\n\n return true;\n } catch (error) {\n // Handle errors\n if (typeof (instance as any).onError === \"function\") {\n await (instance as any).onError(ctx, error as Error);\n } else {\n console.error(`[Stoatx] Error in command ${metadata.name}:`, error);\n }\n return false;\n }\n }\n\n /**\n * Get the command registry\n */\n getRegistry(): CommandRegistry {\n return this.registry;\n }\n\n /**\n * Get a command by name or alias\n */\n getCommand(name: string): RegisteredCommand | undefined {\n return this.registry.get(name);\n }\n\n /**\n * Get all commands\n */\n getCommands(): RegisteredCommand[] {\n return this.registry.getAll();\n }\n\n /**\n * Reload all commands\n */\n async reload(): Promise<void> {\n this.registry.clear();\n this.cooldowns.clear();\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n return;\n }\n\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n /**\n * Check if a user is an owner\n */\n isOwner(userId: string): boolean {\n return this.owners.has(userId);\n }\n\n /**\n * Add an owner\n */\n addOwner(userId: string): void {\n this.owners.add(userId);\n }\n\n /**\n * Remove an owner\n */\n removeOwner(userId: string): void {\n this.owners.delete(userId);\n }\n\n /**\n * Resolve the prefix for a context\n */\n private async resolvePrefix(serverId?: string | undefined): Promise<string> {\n if (typeof this.prefixResolver === \"function\") {\n return this.prefixResolver({ serverId });\n }\n return this.prefixResolver;\n }\n\n /**\n * Check if user is on cooldown\n */\n private checkCooldown(userId: string, metadata: CommandMetadata): boolean {\n if (metadata.cooldown <= 0) return true;\n\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return true;\n\n const expirationTime = commandCooldowns.get(userId);\n if (!expirationTime) return true;\n\n if (Date.now() > expirationTime) {\n commandCooldowns.delete(userId);\n return true;\n }\n\n return false;\n }\n\n /**\n * Get remaining cooldown time in ms\n */\n private getRemainingCooldown(userId: string, metadata: CommandMetadata): number {\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return 0;\n\n const userCooldown = commandCooldowns.get(userId);\n if (!userCooldown) return 0;\n\n return Math.max(0, userCooldown - Date.now());\n }\n\n /**\n * Set cooldown for a user\n */\n private setCooldown(userId: string, metadata: CommandMetadata): void {\n if (!this.cooldowns.has(metadata.name)) {\n this.cooldowns.set(metadata.name, new Map());\n }\n\n const commandCooldowns = this.cooldowns.get(metadata.name)!;\n commandCooldowns.set(userId, Date.now() + metadata.cooldown);\n }\n}\n"],"mappings":"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","names":["import_reflect_metadata","import_reflect_metadata","import_reflect_metadata","relative","import_reflect_metadata","StoatClient"]}
|
package/dist/index.mjs
CHANGED
|
@@ -632,10 +632,10 @@ var StoatxHandler = class {
|
|
|
632
632
|
return false;
|
|
633
633
|
}
|
|
634
634
|
try {
|
|
635
|
-
await instance[methodName](ctx);
|
|
636
635
|
if (metadata.cooldown > 0) {
|
|
637
636
|
this.setCooldown(ctx.authorId, metadata);
|
|
638
637
|
}
|
|
638
|
+
await instance[methodName](ctx);
|
|
639
639
|
return true;
|
|
640
640
|
} catch (error) {
|
|
641
641
|
if (typeof instance.onError === "function") {
|
|
@@ -710,9 +710,13 @@ var StoatxHandler = class {
|
|
|
710
710
|
if (metadata.cooldown <= 0) return true;
|
|
711
711
|
const commandCooldowns = this.cooldowns.get(metadata.name);
|
|
712
712
|
if (!commandCooldowns) return true;
|
|
713
|
-
const
|
|
714
|
-
if (!
|
|
715
|
-
|
|
713
|
+
const expirationTime = commandCooldowns.get(userId);
|
|
714
|
+
if (!expirationTime) return true;
|
|
715
|
+
if (Date.now() > expirationTime) {
|
|
716
|
+
commandCooldowns.delete(userId);
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
719
|
+
return false;
|
|
716
720
|
}
|
|
717
721
|
/**
|
|
718
722
|
* Get remaining cooldown time in ms
|
package/dist/index.mjs.map
CHANGED
|
@@ -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 nsfw: options.nsfw ?? false,\n ownerOnly: options.ownerOnly ?? false,\n };\n}\n","import * as path from \"node:path\";\nimport * as fs from \"node:fs/promises\";\nimport { pathToFileURL } from \"node:url\";\nimport { glob } from \"tinyglobby\";\nimport { buildSimpleCommandMetadata, getSimpleCommands, getEventsMetadata } from \"./decorators\";\nimport { decoratorStore } from \"./decorators/store\";\nimport type { CommandMetadata } from \"./types\";\n\ninterface AutoDiscoveryOptions {\n roots?: string[];\n include?: string[];\n ignore?: string[];\n}\n\n/**\n * Stored command entry from @Stoat/@SimpleCommand registration.\n */\nexport interface RegisteredCommand {\n /** Instance of the @Stoat class */\n instance: object;\n /** Command metadata */\n metadata: CommandMetadata;\n /** Method name to call */\n methodName: string;\n /** The original class constructor (for guard validation) */\n classConstructor: Function;\n}\n\n/**\n * Stored event entry from @On/@Once registration.\n */\nexport interface RegisteredEvent {\n instance: object;\n methodName: string;\n event: string;\n type: \"on\" | \"once\";\n}\n\n/**\n * CommandRegistry - Scans directories and stores commands in a Map\n *\n * @example\n * ```ts\n * const registry = new CommandRegistry();\n * await registry.loadFromDirectory('./src/commands');\n *\n * const ping = registry.get('ping');\n * const allCommands = registry.getAll();\n * ```\n */\nexport class CommandRegistry {\n private static readonly DEFAULT_AUTO_DISCOVERY_IGNORES = [\n \"**/node_modules/**\",\n \"**/.git/**\",\n \"**/*.d.ts\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n ];\n\n private readonly commands: Map<string, RegisteredCommand> = new Map();\n private readonly aliases: Map<string, string> = new Map();\n private readonly registeredEvents: RegisteredEvent[] = [];\n private readonly extensions: string[];\n private readonly processedStoatClasses: Set<Function> = new Set();\n\n constructor(extensions: string[] = [\".js\", \".mjs\", \".cjs\"]) {\n this.extensions = extensions;\n }\n\n /**\n * Get the number of registered commands\n */\n get size(): number {\n return this.commands.size;\n }\n\n /**\n * Load commands from a directory using glob pattern matching\n */\n async loadFromDirectory(directory: string): Promise<void> {\n const patterns = this.extensions.map((ext) => path.join(directory, \"**\", `*${ext}`).replace(/\\\\/g, \"/\"));\n\n for (const pattern of patterns) {\n const files = await glob(pattern, {\n ignore: [\"**/*.d.ts\", \"**/*.test.ts\", \"**/*.spec.ts\"],\n absolute: true,\n });\n\n for (const file of files) {\n await this.loadFile(file, directory);\n }\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n /**\n * Auto-discover command files across one or more roots.\n */\n async autoDiscover(options: AutoDiscoveryOptions = {}): Promise<void> {\n const roots = options.roots?.length ? options.roots : [process.cwd()];\n const includePatterns = options.include?.length ? options.include : this.getDefaultAutoDiscoveryPatterns();\n\n const patterns = roots.flatMap((root) =>\n includePatterns.map((pattern) => path.join(root, pattern).replace(/\\\\/g, \"/\")),\n );\n\n const files = await glob(patterns, {\n ignore: [...CommandRegistry.DEFAULT_AUTO_DISCOVERY_IGNORES, ...(options.ignore ?? [])],\n absolute: true,\n });\n\n const uniqueFiles = [...new Set(files)];\n let candidateFiles = 0;\n for (const file of uniqueFiles) {\n if (!(await this.isLikelyCommandModule(file))) {\n continue;\n }\n candidateFiles++;\n\n const baseDir =\n roots.find((root) => {\n const relative = path.relative(root, file);\n return relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n }) ?? roots[0]!;\n await this.loadFile(file, baseDir);\n }\n\n console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);\n }\n\n private getDefaultAutoDiscoveryPatterns(): string[] {\n // discordx-like default: scan broadly, then register only decorated classes\n return this.extensions.map((ext) => `**/*${ext}`);\n }\n\n private async isLikelyCommandModule(filePath: string): Promise<boolean> {\n try {\n const source = await fs.readFile(filePath, \"utf8\");\n return source.includes(\"Stoat\") || source.includes(\"SimpleCommand\") || source.includes(\"stoatx:command\");\n } catch {\n // If the file can't be pre-read, fall back to attempting import.\n return true;\n }\n }\n\n /**\n * Register a command instance\n */\n register(instance: object, metadata: CommandMetadata, classConstructor: Function, methodName: string): void {\n const name = metadata.name.toLowerCase();\n\n if (this.commands.has(name)) {\n console.warn(`[Stoatx] Duplicate command name: ${name}. Skipping...`);\n return;\n }\n\n this.validateGuards(classConstructor, metadata.name);\n\n this.commands.set(name, { instance, metadata, methodName, classConstructor });\n\n for (const alias of metadata.aliases) {\n const aliasLower = alias.toLowerCase();\n if (this.aliases.has(aliasLower) || this.commands.has(aliasLower)) {\n console.warn(`[Stoatx] Duplicate alias: ${aliasLower}. Skipping...`);\n continue;\n }\n this.aliases.set(aliasLower, name);\n }\n }\n\n /**\n * Get a command by name or alias\n */\n get(name: string): RegisteredCommand | undefined {\n const lowerName = name.toLowerCase();\n const resolvedName = this.aliases.get(lowerName) ?? lowerName;\n return this.commands.get(resolvedName);\n }\n\n /**\n * Check if a command exists\n */\n has(name: string): boolean {\n const lowerName = name.toLowerCase();\n return this.commands.has(lowerName) || this.aliases.has(lowerName);\n }\n\n /**\n * Get all registered commands\n */\n getAll(): RegisteredCommand[] {\n return Array.from(this.commands.values());\n }\n\n /**\n * Get all command metadata\n */\n getAllMetadata(): CommandMetadata[] {\n return this.getAll().map((c) => c.metadata);\n }\n\n /**\n * Get all registered events\n */\n getEvents(): RegisteredEvent[] {\n return this.registeredEvents;\n }\n\n /**\n * Get commands grouped by category\n */\n getByCategory(): Map<string, RegisteredCommand[]> {\n const categories = new Map<string, RegisteredCommand[]>();\n\n for (const cmd of this.commands.values()) {\n const category = cmd.metadata.category;\n const existing = categories.get(category) ?? [];\n existing.push(cmd);\n categories.set(category, existing);\n }\n\n return categories;\n }\n\n /**\n * Clear all commands\n */\n clear(): void {\n this.commands.clear();\n this.aliases.clear();\n this.registeredEvents.length = 0;\n this.processedStoatClasses.clear();\n }\n\n /**\n * Iterate over commands\n */\n [Symbol.iterator](): IterableIterator<[string, RegisteredCommand]> {\n return this.commands.entries();\n }\n\n /**\n * Iterate over command values\n */\n values(): IterableIterator<RegisteredCommand> {\n return this.commands.values();\n }\n\n /**\n * Iterate over command names\n */\n keys(): IterableIterator<string> {\n return this.commands.keys();\n }\n\n /**\n * Validate that all guards on a command implement the required methods\n * @param commandClass\n * @param commandName\n * @private\n */\n private validateGuards(commandClass: Function, commandName: string): void {\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", commandClass) || [];\n\n for (const GuardClass of guards) {\n const guardInstance = new (GuardClass as any)();\n\n if (typeof guardInstance.run !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a run() method.`,\n );\n process.exit(1);\n }\n\n if (typeof guardInstance.guardFail !== \"function\") {\n console.error(\n `[Stoatx] FATAL: Guard \"${GuardClass.name}\" on command \"${commandName}\" does not have a guardFail() method.`,\n );\n console.error(`[Stoatx] All guards must implement guardFail() to handle failed checks.`);\n process.exit(1);\n }\n }\n }\n\n /**\n * Load commands from a single file\n */\n private async loadFile(filePath: string, baseDir: string): Promise<void> {\n try {\n const knownStoatClasses = new Set(decoratorStore.getStoatClasses().keys());\n const fileUrl = pathToFileURL(filePath).href;\n await import(fileUrl);\n\n const allStoatClasses = decoratorStore.getStoatClasses();\n for (const [stoatClass, stoatInstance] of allStoatClasses.entries()) {\n if (knownStoatClasses.has(stoatClass) || this.processedStoatClasses.has(stoatClass)) {\n continue;\n }\n this.registerStoatClassCommands(stoatClass, stoatInstance, filePath, baseDir);\n }\n } catch (error) {\n console.error(`[Stoatx] Failed to load command file: ${filePath}`, error);\n }\n }\n\n private registerStoatClassCommands(stoatClass: Function, instance: object, filePath: string, baseDir: string): void {\n const simpleCommands = getSimpleCommands(stoatClass);\n const events = getEventsMetadata(stoatClass);\n const category = this.getCategoryFromPath(filePath, baseDir);\n\n if (simpleCommands.length === 0 && events.length === 0) {\n console.warn(\n `[Stoatx] Class ${stoatClass.name} is decorated with @Stoat but has no @SimpleCommand, @On or @Once methods. Skipping...`,\n );\n this.processedStoatClasses.add(stoatClass);\n return;\n }\n\n for (const cmdDef of simpleCommands) {\n const method = (instance as any)[cmdDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${cmdDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n const metadata = buildSimpleCommandMetadata(cmdDef.options, cmdDef.methodName, category);\n this.register(instance, metadata, stoatClass, cmdDef.methodName);\n }\n\n for (const eventDef of events) {\n const method = (instance as any)[eventDef.methodName];\n if (typeof method !== \"function\") {\n console.warn(`[Stoatx] Method ${eventDef.methodName} not found on ${stoatClass.name}. Skipping...`);\n continue;\n }\n\n this.registeredEvents.push({\n instance,\n methodName: eventDef.methodName,\n event: eventDef.event,\n type: eventDef.type,\n });\n }\n\n this.processedStoatClasses.add(stoatClass);\n }\n\n /**\n * Derive category from file path relative to base directory\n */\n private getCategoryFromPath(filePath: string, baseDir: string): string | undefined {\n const relative = path.relative(baseDir, filePath);\n const parts = relative.split(path.sep);\n\n if (parts.length > 1) {\n return parts[0];\n }\n\n return undefined;\n }\n}\n","import \"reflect-metadata\";\nimport { CommandRegistry, RegisteredCommand } from \"./registry\";\nimport type { CommandContext, CommandMetadata, StoatxDiscoveryOptions, StoatxHandlerOptions } from \"./types\";\nimport { Client as StoatClient, ClientEvents, Message } from \"@stoatx/client\";\n\n/**\n * Client - An extended Client that integrates StoatxHandler directly\n *\n * @example\n * ```ts\n * import { Client } from 'stoatx';\n *\n * const client = new Client({\n * prefix: '!',\n * owners: ['owner-user-id'],\n * });\n *\n * await client.initCommands();\n * ```\n */\nexport class Client extends StoatClient {\n public readonly handler: StoatxHandler;\n\n constructor(options: Omit<StoatxHandlerOptions, \"client\">) {\n super();\n this.handler = new StoatxHandler({ ...options, client: this });\n\n // Automatically hook up the message handler\n this.on(\"messageCreate\", async (message) => {\n await this.handler.handle(message);\n });\n }\n\n /**\n * Initialize the StoatxHandler commands\n */\n async initCommands(): Promise<void> {\n await this.handler.init();\n }\n}\n\n/**\n * StoatxHandler - The execution engine for commands\n *\n * Handles message parsing, middleware execution, and command dispatching\n *\n * @internal This class is not intended to be instantiated directly. Use the `Client` from `stoatx` instead.\n */\nexport class StoatxHandler {\n private readonly commandsDir: string | undefined;\n private readonly discoveryOptions: StoatxDiscoveryOptions | undefined;\n private readonly prefixResolver: string | ((ctx: { serverId?: string | undefined }) => string | Promise<string>);\n private readonly owners: Set<string>;\n private readonly registry: CommandRegistry;\n private readonly cooldowns: Map<string, Map<string, number>> = new Map();\n private readonly disableMentionPrefix: boolean;\n private readonly client: StoatClient;\n constructor(options: StoatxHandlerOptions) {\n this.client = options.client;\n this.commandsDir = options.commandsDir;\n this.discoveryOptions = options.discovery;\n this.prefixResolver = options.prefix;\n this.owners = new Set(options.owners ?? []);\n this.registry = new CommandRegistry(options.extensions);\n this.disableMentionPrefix = options.disableMentionPrefix ?? false;\n }\n\n /**\n * Initialize the handler - load all commands\n */\n async init(): Promise<void> {\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n } else {\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n this.attachEvents();\n }\n\n /**\n * Attach registered events to the client\n */\n private attachEvents(): void {\n const events = this.registry.getEvents();\n\n for (const eventDef of events) {\n const handler = async (...args: any[]) => {\n try {\n await (eventDef.instance as any)[eventDef.methodName](...args, this.client);\n } catch (error) {\n console.error(\n `[Stoatx] Event Handler Error in @${eventDef.type === \"on\" ? \"On\" : \"Once\"}('${eventDef.event}'):`,\n error,\n );\n }\n };\n\n const eventName = eventDef.event as keyof ClientEvents;\n if (eventDef.type === \"once\") {\n this.client.once(eventName, handler);\n } else {\n this.client.on(eventName, handler);\n }\n }\n }\n\n /**\n * Parse a raw message into command context\n */\n async parseMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<CommandContext | null> {\n const prefix = await this.resolvePrefix(meta.serverId);\n let usedPrefix = prefix;\n let withoutPrefix = \"\";\n\n // Check for string prefix\n if (rawContent.startsWith(prefix)) {\n withoutPrefix = rawContent.slice(prefix.length).trim();\n usedPrefix = prefix;\n }\n // Check for mention prefix (e.g., \"<@bot-id> command\") - unless disabled\n else if (!this.disableMentionPrefix && rawContent.match(/^<@!?[\\w]+>/)) {\n const mentionMatch = rawContent.match(/^<@!?([\\w]+)>\\s*/);\n if (mentionMatch) {\n const mentionedId = mentionMatch[1];\n const botId = this.client.user?.id;\n\n // Only process if mentioned user is the bot\n if (botId && mentionedId === botId) {\n usedPrefix = mentionMatch[0];\n withoutPrefix = rawContent.slice(mentionMatch[0].length).trim();\n } else {\n }\n }\n }\n\n if (!withoutPrefix) {\n return null;\n }\n\n const [commandName, ...args] = withoutPrefix.split(/\\s+/);\n\n if (!commandName) {\n return null;\n }\n\n return {\n client: this.client,\n content: rawContent,\n authorId: meta.authorId,\n channelId: meta.channelId,\n serverId: meta.serverId,\n args,\n prefix: usedPrefix,\n commandName: commandName.toLowerCase(),\n reply: meta.reply,\n message,\n };\n }\n\n /**\n * Handle a message object using the configured message adapter\n *\n * @example\n * ```ts\n * // With message adapter configured\n * client.on('messageCreate', (message) => {\n * handler.handle(message);\n * });\n * ```\n */\n async handle(message: Message): Promise<boolean> {\n if (!message.channel || !message.author) {\n return false;\n }\n\n // Skip messages from bots\n if (message.author.bot) {\n return false;\n }\n\n const rawContent = message.content;\n const authorId = message.author.id;\n const channelId = message.channel.id;\n const serverId = message.server?.id;\n const reply = async (content: string) => {\n return await message.channel!.send(content);\n };\n\n // rawContent won't be null since a command will be invoked with a prefix\n await this.handleMessage(rawContent!, message, {\n authorId,\n channelId,\n serverId,\n reply,\n });\n\n return true;\n }\n\n /**\n * Handle a raw message string with metadata\n *\n * @example\n * ```ts\n * // Manual usage without message adapter\n * client.on('messageCreate', (message) => {\n * handler.handleMessage(message.content, message, {\n * authorId: message.author.id,\n * channelId: message.channel.id,\n * serverId: message.server?.id,\n * reply: (content) => message.channel.sendMessage(content),\n * });\n * });\n * ```\n */\n async handleMessage(\n rawContent: string,\n message: Message,\n meta: {\n authorId: string;\n channelId: string;\n serverId?: string | undefined;\n reply: (content: string) => Promise<Message>;\n },\n ): Promise<void> {\n const ctx = await this.parseMessage(rawContent, message, meta);\n\n if (!ctx) {\n return;\n }\n\n await this.execute(ctx);\n }\n\n /**\n * Execute a command with the given context\n */\n async execute(ctx: CommandContext): Promise<boolean> {\n const registered = this.registry.get(ctx.commandName);\n\n if (!registered) {\n return false;\n }\n\n const { instance, metadata, methodName, classConstructor } = registered;\n\n // Owner-only check\n if (metadata.ownerOnly && !this.owners.has(ctx.authorId)) {\n await ctx.reply(\"This command is owner-only.\");\n return false;\n }\n\n // Guard checks - use classConstructor for guard metadata\n const guards: Function[] = Reflect.getMetadata(\"stoatx:command:guards\", classConstructor) || [];\n for (const guardClass of guards) {\n const guardInstance = new (guardClass as any)();\n if (typeof guardInstance.run === \"function\") {\n const guardResult = await guardInstance.run(ctx);\n if (!guardResult) {\n if (typeof guardInstance.guardFail === \"function\") {\n await guardInstance.guardFail(ctx);\n } else {\n console.error(\"[Stoatx] Guard check failed but no guardFail method defined on\", guardClass.name);\n }\n return false;\n }\n }\n }\n\n // Cooldown check\n if (!this.checkCooldown(ctx.authorId, metadata)) {\n const remaining = this.getRemainingCooldown(ctx.authorId, metadata);\n\n // For method-based commands, check if instance has onCooldown\n if (typeof (instance as any).onCooldown === \"function\") {\n await (instance as any).onCooldown(ctx, remaining);\n } else {\n await ctx.reply(`Please wait ${(remaining / 1000).toFixed(1)} seconds before using this command again.`);\n }\n return false;\n }\n\n try {\n // Set cooldown before execution to prevent concurrent executions\n if (metadata.cooldown > 0) {\n this.setCooldown(ctx.authorId, metadata);\n }\n\n await (instance as any)[methodName](ctx);\n\n return true;\n } catch (error) {\n // Handle errors\n if (typeof (instance as any).onError === \"function\") {\n await (instance as any).onError(ctx, error as Error);\n } else {\n console.error(`[Stoatx] Error in command ${metadata.name}:`, error);\n }\n return false;\n }\n }\n\n /**\n * Get the command registry\n */\n getRegistry(): CommandRegistry {\n return this.registry;\n }\n\n /**\n * Get a command by name or alias\n */\n getCommand(name: string): RegisteredCommand | undefined {\n return this.registry.get(name);\n }\n\n /**\n * Get all commands\n */\n getCommands(): RegisteredCommand[] {\n return this.registry.getAll();\n }\n\n /**\n * Reload all commands\n */\n async reload(): Promise<void> {\n this.registry.clear();\n this.cooldowns.clear();\n if (this.commandsDir) {\n await this.registry.loadFromDirectory(this.commandsDir);\n return;\n }\n\n await this.registry.autoDiscover(this.discoveryOptions);\n }\n\n /**\n * Check if a user is an owner\n */\n isOwner(userId: string): boolean {\n return this.owners.has(userId);\n }\n\n /**\n * Add an owner\n */\n addOwner(userId: string): void {\n this.owners.add(userId);\n }\n\n /**\n * Remove an owner\n */\n removeOwner(userId: string): void {\n this.owners.delete(userId);\n }\n\n /**\n * Resolve the prefix for a context\n */\n private async resolvePrefix(serverId?: string | undefined): Promise<string> {\n if (typeof this.prefixResolver === \"function\") {\n return this.prefixResolver({ serverId });\n }\n return this.prefixResolver;\n }\n\n /**\n * Check if user is on cooldown\n */\n private checkCooldown(userId: string, metadata: CommandMetadata): boolean {\n if (metadata.cooldown <= 0) return true;\n\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return true;\n\n const expirationTime = commandCooldowns.get(userId);\n if (!expirationTime) return true;\n\n if (Date.now() > expirationTime) {\n commandCooldowns.delete(userId);\n return true;\n }\n\n return false;\n }\n\n /**\n * Get remaining cooldown time in ms\n */\n private getRemainingCooldown(userId: string, metadata: CommandMetadata): number {\n const commandCooldowns = this.cooldowns.get(metadata.name);\n if (!commandCooldowns) return 0;\n\n const userCooldown = commandCooldowns.get(userId);\n if (!userCooldown) return 0;\n\n return Math.max(0, userCooldown - Date.now());\n }\n\n /**\n * Set cooldown for a user\n */\n private setCooldown(userId: string, metadata: CommandMetadata): void {\n if (!this.cooldowns.has(metadata.name)) {\n this.cooldowns.set(metadata.name, new Map());\n }\n\n const commandCooldowns = this.cooldowns.get(metadata.name)!;\n commandCooldowns.set(userId, Date.now() + metadata.cooldown);\n }\n}\n","// Types\nexport * from \"./types\";\n\n// Decorators\nexport * from \"./decorators\";\n\n// Registry\nexport * from \"./registry\";\n\n// Handler\nexport { Client } from \"./handler\";\nexport type { StoatxHandler } from \"./handler\";\nexport * from \"@stoatx/client\";\n"],"mappings":"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","names":["relative"]}
|