stoatx 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +221 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# stoatx
|
|
2
|
+
|
|
3
|
+
A high-performance, decorator-based command handler for the [Stoat](https://github.com/stoatchat/javascript-client-sdk) ecosystem. Inspired by [discordx](https://github.com/discordx-ts/discordx).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Decorator-based** - Use `@Stoat()` and `@SimpleCommand()` decorators like discordx
|
|
8
|
+
- **Guards** - Built-in guard system for permissions and checks
|
|
9
|
+
- **Cooldowns** - Per-command cooldown support
|
|
10
|
+
- **Organized** - Group multiple commands in a single class
|
|
11
|
+
- **Type-safe** - Full TypeScript support
|
|
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 'stoat.js';
|
|
40
|
+
import { MallyHandler } from 'stoatx';
|
|
41
|
+
|
|
42
|
+
const client = new Client();
|
|
43
|
+
|
|
44
|
+
const handler = new MallyHandler({
|
|
45
|
+
client,
|
|
46
|
+
prefix: '!',
|
|
47
|
+
owners: ['your-user-id']
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await handler.init();
|
|
51
|
+
|
|
52
|
+
client.on('messageCreate', (message) => {
|
|
53
|
+
handler.handleMessage(message);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
client.login('your-token');
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. Create commands
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// commands/general.ts
|
|
63
|
+
import { Stoat, SimpleCommand, Context } from 'stoatx';
|
|
64
|
+
|
|
65
|
+
@Stoat()
|
|
66
|
+
export class GeneralCommands {
|
|
67
|
+
@SimpleCommand({ name: 'ping', description: 'Check bot latency' })
|
|
68
|
+
async ping(ctx: Context) {
|
|
69
|
+
await ctx.reply(`Pong! 🏓`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@SimpleCommand({ name: 'hello', aliases: ['hi', 'hey'] })
|
|
73
|
+
async hello(ctx: Context) {
|
|
74
|
+
await ctx.reply(`Hello, <@${ctx.authorId}>!`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
That's it! No manual imports needed - decorated command classes are auto-discovered.
|
|
80
|
+
|
|
81
|
+
## Decorators
|
|
82
|
+
|
|
83
|
+
### @Stoat()
|
|
84
|
+
|
|
85
|
+
Marks a class as a command container. All `@SimpleCommand()` methods inside will be registered.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
@Stoat()
|
|
89
|
+
export class MyCommands {
|
|
90
|
+
// commands go here
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### @SimpleCommand(options)
|
|
95
|
+
|
|
96
|
+
Marks a method as a command.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
@SimpleCommand({
|
|
100
|
+
name: 'ban', // Command name (defaults to method name)
|
|
101
|
+
description: 'Ban a user',
|
|
102
|
+
aliases: ['b'], // Alternative names
|
|
103
|
+
permissions: ['BanMembers'], // This is currently not implemented, but will be in the future
|
|
104
|
+
cooldown: 5000, // 5 seconds
|
|
105
|
+
ownerOnly: false,
|
|
106
|
+
nsfw: false,
|
|
107
|
+
})
|
|
108
|
+
async ban(ctx: Context) {
|
|
109
|
+
// ...
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### @Guard(GuardClass)
|
|
114
|
+
|
|
115
|
+
Adds a guard check before command execution.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { Stoat, SimpleCommand, Guard, MallyGuard, Context } from 'stoatx';
|
|
119
|
+
|
|
120
|
+
// Define a guard
|
|
121
|
+
class IsAdmin implements MallyGuard {
|
|
122
|
+
run(ctx: Context): boolean {
|
|
123
|
+
return ctx.message.member?.hasPermission('Administrator') ?? false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
guardFail(ctx: Context): void {
|
|
127
|
+
ctx.reply('You need Administrator permission!');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@Stoat()
|
|
132
|
+
@Guard(IsAdmin)
|
|
133
|
+
export class AdminCommands {
|
|
134
|
+
@SimpleCommand({ name: 'shutdown' })
|
|
135
|
+
async shutdown(ctx: Context) {
|
|
136
|
+
await ctx.reply('Shutting down...');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Context
|
|
142
|
+
|
|
143
|
+
The `Context` object provides:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
interface Context {
|
|
147
|
+
client: Client; // Stoat client instance
|
|
148
|
+
message: Message; // Original message
|
|
149
|
+
content: string; // Raw message content
|
|
150
|
+
authorId: string; // Author's user ID
|
|
151
|
+
channelId: string; // Channel ID
|
|
152
|
+
serverId?: string; // Server/Guild ID
|
|
153
|
+
args: string[]; // Parsed arguments
|
|
154
|
+
prefix: string; // Prefix used
|
|
155
|
+
commandName: string; // Command name used
|
|
156
|
+
|
|
157
|
+
reply(content: string): Promise<void>;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Handler Options
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
interface MallyHandlerOptions {
|
|
165
|
+
client: Client;
|
|
166
|
+
commandsDir?: string; // Legacy mode: explicitly scan this directory
|
|
167
|
+
discovery?: {
|
|
168
|
+
roots?: string[]; // Default: [process.cwd()]
|
|
169
|
+
include?: string[]; // Glob patterns per root
|
|
170
|
+
ignore?: string[]; // Additional ignore globs
|
|
171
|
+
};
|
|
172
|
+
prefix: string | ((ctx: { serverId?: string }) => string | Promise<string>);
|
|
173
|
+
owners?: string[]; // Owner user IDs
|
|
174
|
+
extensions?: string[]; // File extensions (default: ['.js', '.mjs', '.cjs'])
|
|
175
|
+
disableMentionPrefix?: boolean; // Disable @bot prefix
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Default auto-discovery is discordx-like: scans broadly under process.cwd(),
|
|
179
|
+
// then registers only files that look like decorated command modules.
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Dynamic Prefix
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const handler = new MallyHandler({
|
|
186
|
+
client,
|
|
187
|
+
prefix: async ({ serverId }) => {
|
|
188
|
+
// Fetch from database, etc.
|
|
189
|
+
return serverId ? await getServerPrefix(serverId) : '!';
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Optional: constrain auto-discovery to specific roots/patterns
|
|
194
|
+
const scopedHandler = new MallyHandler({
|
|
195
|
+
client,
|
|
196
|
+
prefix: '!',
|
|
197
|
+
discovery: {
|
|
198
|
+
roots: [process.cwd()],
|
|
199
|
+
include: ['apps/bot/dist/commands/**/*.js'],
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// TypeScript source discovery is opt-in and requires a TS runtime loader (tsx/ts-node)
|
|
204
|
+
const tsRuntimeHandler = new MallyHandler({
|
|
205
|
+
client,
|
|
206
|
+
prefix: '!',
|
|
207
|
+
extensions: ['.ts'],
|
|
208
|
+
discovery: {
|
|
209
|
+
include: ['apps/bot/src/commands/**/*.ts'],
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
All commands are defined through `@Stoat()` classes and `@SimpleCommand()` methods.
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
AGPL-3.0-or-later
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stoatx",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "A high-performance, decorator-based command handler for the Stoat ecosystem.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/Arsabutispik/stoatx"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"module": "./dist/index.mjs",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.mjs",
|
|
16
|
+
"require": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"license": "AGPL-3.0-or-later",
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
28
|
+
"dev": "tsup src/index.ts --format cjs,esm --watch --dts",
|
|
29
|
+
"lint": "eslint src/**/*.ts",
|
|
30
|
+
"format": "prettier --write src/**/*.ts"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"reflect-metadata": "^0.2.2",
|
|
34
|
+
"stoat.js": "^7.3.6",
|
|
35
|
+
"tinyglobby": "^0.2.10"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.0.0",
|
|
39
|
+
"tsup": "^8.0.0",
|
|
40
|
+
"typescript": "^5.0.0",
|
|
41
|
+
"prettier": "^3.8.1"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"reflect-metadata": "^0.2.0"
|
|
45
|
+
}
|
|
46
|
+
}
|