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 +3 -264
- package/dist/index.d.mts +204 -183
- package/dist/index.d.ts +204 -183
- package/dist/index.js +635 -236
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +621 -234
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
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
|
-
|
|
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]
|