stoatx 0.7.7 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,273 +6,12 @@ A high-performance, decorator-based command handler for Stoat bots. Inspired by
6
6
 
7
7
  - **Decorator-based** - Use `@Stoat()` and `@SimpleCommand()` decorators like discordx
8
8
  - **Guards** - Built-in guard system for permissions and checks
9
- - **Cooldowns** - Per-command cooldown support
9
+ - **Cooldowns** - Per-command cooldown support with custom storage support
10
10
  - **Organized** - Group multiple commands in a single class
11
11
  - **Type-safe** - Full TypeScript support
12
12
 
13
- ## Installation
14
-
15
- ```bash
16
- npm install stoatx reflect-metadata
17
- # or
18
- pnpm add stoatx reflect-metadata
19
- ```
20
-
21
- Make sure to enable decorators in your `tsconfig.json`:
22
-
23
- ```json
24
- {
25
- "compilerOptions": {
26
- "experimentalDecorators": true,
27
- "emitDecoratorMetadata": true
28
- }
29
- }
30
- ```
31
-
32
- ## Quick Start
33
-
34
- ### 1. Create your handler
35
-
36
- ```typescript
37
- // index.ts
38
- import "reflect-metadata";
39
- import { Client } from "stoatx";
40
-
41
- const client = new Client({
42
- prefix: "!",
43
- owners: ["your-user-id"],
44
- });
45
-
46
- await client.initCommands();
47
-
48
- client.login("your-token");
49
- ```
50
-
51
- ### 2. Create commands
52
-
53
- ```typescript
54
- // commands/general.ts
55
- import { Stoat, SimpleCommand, Context } from "stoatx";
56
-
57
- @Stoat()
58
- export class GeneralCommands {
59
- @SimpleCommand({ name: "ping", description: "Check bot latency" })
60
- async ping(ctx: Context) {
61
- await ctx.reply(`Pong! 🏓`);
62
- }
63
-
64
- @SimpleCommand({ name: "hello", aliases: ["hi", "hey"] })
65
- async hello(ctx: Context) {
66
- await ctx.reply(`Hello, <@${ctx.authorId}>!`);
67
- }
68
- }
69
- ```
70
-
71
- That's it! No manual imports needed - decorated command classes are auto-discovered.
72
-
73
- ## Decorators
74
-
75
- ### @Stoat()
76
-
77
- Marks a class as a command container. All `@SimpleCommand()` methods inside will be registered.
78
-
79
- ```typescript
80
- @Stoat()
81
- export class MyCommands {
82
- // commands go here
83
- }
84
- ```
85
-
86
- ### @SimpleCommand(options)
87
-
88
- Marks a method as a command.
89
-
90
- ```typescript
91
- @SimpleCommand({
92
- name: 'ban', // Command name (defaults to method name)
93
- description: 'Ban a user',
94
- aliases: ['b'], // Alternative names
95
- permissions: ['BanMembers'], // This is currently not implemented, but will be in the future
96
- cooldown: 5000, // 5 seconds
97
- cooldownStorage: "database", // A custom flag you can use in your CustomCooldownManager
98
- ownerOnly: false,
99
- nsfw: false,
100
- })
101
- async ban(ctx: Context) {
102
- // logic
103
- }
104
- ```
105
-
106
- ### StoatLifecycle Interface
107
-
108
- Provides intellisense for lifecycle hooks like `onError` and `onCooldown` on your `@Stoat()` classes.
109
-
110
- ```typescript
111
- import { Stoat, SimpleCommand, CommandContext, StoatLifecycle } from "stoatx";
112
-
113
- @Stoat()
114
- export class MyCommands implements StoatLifecycle {
115
- @SimpleCommand({ cooldown: 5000 })
116
- async ping(ctx: CommandContext) {
117
- await ctx.reply(`Pong! 🏓`);
118
- }
119
-
120
- // Called when the command is placed on cooldown
121
- async onCooldown(ctx: CommandContext, remaining: number) {
122
- await ctx.reply(`You are in cooldown, wait ${(remaining / 1000).toFixed(1)} seconds!`);
123
- }
124
-
125
- // Called when an error occurs during execution
126
- async onError(ctx: CommandContext, error: Error) {
127
- console.error(error);
128
- await ctx.reply("An error occurred");
129
- }
130
- }
131
- ```
132
-
133
- ## Custom Cooldowns
134
-
135
- By default, cooldowns are stored in memory. For persistent or distributed setups, you can implement the `CooldownManager` interface to store cooldowns in a database such as Redis, PostgreSQL or MongoDB.
136
-
137
- ```typescript
138
- import { Client, CooldownManager, CommandContext, CommandMetadata, DefaultCooldownManager } from "stoatx";
139
-
140
- class MixedCooldownManager implements CooldownManager {
141
- private memory = new DefaultCooldownManager();
142
-
143
- async check(ctx: CommandContext, metadata: CommandMetadata): Promise<boolean> {
144
- if (metadata.cooldownStorage === "database") {
145
- // Return true if action is allowed in DB
146
- return true;
147
- }
148
- return this.memory.check(ctx, metadata);
149
- }
150
-
151
- async getRemaining(ctx: CommandContext, metadata: CommandMetadata): Promise<number> {
152
- if (metadata.cooldownStorage === "database") {
153
- // Query remaining from DB
154
- return 0;
155
- }
156
- return this.memory.getRemaining(ctx, metadata);
157
- }
158
-
159
- async set(ctx: CommandContext, metadata: CommandMetadata): Promise<void> {
160
- if (metadata.cooldownStorage === "database") {
161
- // Store cooldown expiration in your database
162
- return;
163
- }
164
- this.memory.set(ctx, metadata);
165
- }
166
- }
167
-
168
- const client = new Client({
169
- prefix: "!",
170
- cooldownManager: new MixedCooldownManager(),
171
- });
172
- ```
173
-
174
- ## Guards
175
-
176
- ### @Guard(GuardClass)
177
-
178
- Adds a guard check before command execution.
179
-
180
- ```typescript
181
- import { Stoat, SimpleCommand, Guard, MallyGuard, Context } from "stoatx";
182
-
183
- // Define a guard
184
- class IsAdmin implements MallyGuard {
185
- run(ctx: Context): boolean {
186
- return ctx.message.member?.hasPermission("Administrator") ?? false;
187
- }
188
-
189
- guardFail(ctx: Context): void {
190
- ctx.reply("You need Administrator permission!");
191
- }
192
- }
193
-
194
- @Stoat()
195
- @Guard(IsAdmin)
196
- export class AdminCommands {
197
- @SimpleCommand({ name: "shutdown" })
198
- async shutdown(ctx: Context) {
199
- await ctx.reply("Shutting down...");
200
- }
201
- }
202
- ```
203
-
204
- ## Context
205
-
206
- The `Context` object provides:
207
-
208
- ```typescript
209
- interface Context {
210
- client: Client; // Stoat client instance
211
- message: Message; // Original message
212
- content: string; // Raw message content
213
- authorId: string; // Author's user ID
214
- channelId: string; // Channel ID
215
- serverId?: string; // Server/Guild ID
216
- args: string[]; // Parsed arguments
217
- prefix: string; // Prefix used
218
- commandName: string; // Command name used
219
-
220
- reply(content: string): Promise<void>;
221
- }
222
- ```
223
-
224
- ## Handler Options
225
-
226
- ```typescript
227
- interface StoatxHandlerOptions {
228
- client: Client;
229
- commandsDir?: string; // Legacy mode: explicitly scan this directory
230
- discovery?: {
231
- roots?: string[]; // Default: [process.cwd()]
232
- include?: string[]; // Glob patterns per root
233
- ignore?: string[]; // Additional ignore globs
234
- };
235
- prefix: string ((ctx: { serverId?: string }) => string Promise<string>);
236
- owners?: string[]; // Owner user IDs
237
- extensions?: string[]; // File extensions (default: ['.js', '.mjs', '.cjs'])
238
- disableMentionPrefix?: boolean; // Disable @bot prefix
239
- }
240
-
241
- // Default auto-discovery is discordx-like: scans broadly under process.cwd(),
242
- // then registers only files that look like decorated command modules.
243
- ```
244
-
245
- ## Dynamic Prefix
246
-
247
- ```typescript
248
- const client = new Client({
249
- prefix: async ({ serverId }) => {
250
- // Fetch from database, etc.
251
- return serverId ? await getServerPrefix(serverId) : "!";
252
- },
253
- });
254
-
255
- // Optional: constrain auto-discovery to specific roots/patterns
256
- const scopedClient = new Client({
257
- prefix: "!",
258
- discovery: {
259
- roots: [process.cwd()],
260
- include: ["apps/bot/dist/commands/**/*.js"],
261
- },
262
- });
263
-
264
- // TypeScript source discovery is opt-in and requires a TS runtime loader (tsx/ts-node)
265
- const tsRuntimeClient = new Client({
266
- prefix: "!",
267
- extensions: [".ts"],
268
- discovery: {
269
- include: ["apps/bot/src/commands/**/*.ts"],
270
- },
271
- });
272
- ```
273
-
274
- All commands are defined through `@Stoat()` classes and `@SimpleCommand()` methods.
13
+ For installation instructions, guides, and API references, visit the **[Stoatx Documentation](https://stoatx-ts.github.io/stoatx/)**.
275
14
 
276
15
  ## License
277
16
 
278
- MIT © [Stoatx / Stoatx Team]
17
+ MIT © [Stoatx / Stoatx Team]