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.
Files changed (2) hide show
  1. package/README.md +221 -0
  2. 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
+ }