vimcord 1.0.35 → 1.0.37
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 +395 -47
- package/dist/index.cjs +1286 -1039
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +793 -452
- package/dist/index.d.ts +793 -452
- package/dist/index.js +1249 -1012
- package/dist/index.js.map +1 -1
- package/dist/metafile-cjs.json +1 -1
- package/dist/metafile-esm.json +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,8 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
```
|
|
4
|
+
██╗ ██╗██╗███╗ ███╗ ██████╗ ██████╗ ██████╗ ██████╗
|
|
5
|
+
██║ ██║██║████╗ ████║██╔════╝██╔═══██╗██╔══██╗██╔══██╗
|
|
6
|
+
██║ ██║██║██╔████╔██║██║ ██║ ██║██████╔╝██║ ██║
|
|
7
|
+
╚██╗ ██╔╝██║██║╚██╔╝██║██║ ██║ ██║██╔══██╗██║ ██║
|
|
8
|
+
╚████╔╝ ██║██║ ╚═╝ ██║╚██████╗╚██████╔╝██║ ██║██████╔╝
|
|
9
|
+
╚═══╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**vhem-cord** — the Discord.js framework that actually respects your time
|
|
13
|
+
|
|
14
|
+
[](https://www.npmjs.com/package/vimcord)
|
|
15
|
+
[](https://www.npmjs.com/package/vimcord)
|
|
16
|
+
[](https://www.typescriptlang.org/)
|
|
17
|
+
[](LICENSE)
|
|
18
|
+
[](https://discord.js.org/)
|
|
19
|
+
|
|
20
|
+
[Installation](#installation) · [Quick Start](#quick-start) · [Features](#features) · [API](#api-reference) · [Examples](#examples)
|
|
21
|
+
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## What's Vimcord?
|
|
27
|
+
|
|
28
|
+
**Vimcord** (pronounced _vhem-cord_) is a lightweight, opinionated framework for **Discord.js**. Built for developers who want to go from an idea to a working command without fighting boilerplate.
|
|
4
29
|
|
|
5
|
-
|
|
30
|
+
Think of it as Discord.js with the sharp edges sanded off — full TypeScript inference, automatic error boundaries, and utilities that actually make sense.
|
|
31
|
+
|
|
32
|
+
> "I just wanted to build a bot, not write a command handler for the 47th time." — _You, probably_
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
6
37
|
|
|
7
38
|
```bash
|
|
8
39
|
npm install vimcord discord.js
|
|
@@ -12,83 +43,400 @@ pnpm add vimcord discord.js
|
|
|
12
43
|
yarn add vimcord discord.js
|
|
13
44
|
```
|
|
14
45
|
|
|
15
|
-
|
|
46
|
+
**Peer dependencies** (optional but recommended):
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install mongoose # Only if using MongoDB
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
16
55
|
|
|
17
|
-
|
|
56
|
+
### The Absolute Minimum
|
|
18
57
|
|
|
19
58
|
```ts
|
|
20
|
-
import {
|
|
21
|
-
|
|
59
|
+
import { createClient, GatewayIntentBits } from "vimcord";
|
|
60
|
+
|
|
61
|
+
const client = createClient({ intents: [GatewayIntentBits.Guilds] }, { useDefaultSlashCommandHandler: true });
|
|
62
|
+
|
|
63
|
+
client.start();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### The "I Actually Want Features" Setup
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { GatewayIntentBits } from "discord.js";
|
|
70
|
+
import { createClient, MongoDatabase } from "vimcord";
|
|
22
71
|
|
|
23
72
|
const client = createClient(
|
|
24
73
|
{
|
|
25
|
-
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages]
|
|
74
|
+
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent]
|
|
26
75
|
},
|
|
27
76
|
{
|
|
28
|
-
|
|
77
|
+
// Auto-load modules from directories
|
|
78
|
+
importModules: {
|
|
79
|
+
events: "./events",
|
|
80
|
+
slashCommands: "./commands/slash",
|
|
81
|
+
prefixCommands: "./commands/prefix",
|
|
82
|
+
contextCommands: "./commands/context"
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
// Built-in handlers for each command type
|
|
29
86
|
useDefaultSlashCommandHandler: true,
|
|
30
87
|
useDefaultPrefixCommandHandler: true,
|
|
31
88
|
useDefaultContextCommandHandler: true,
|
|
32
89
|
|
|
33
|
-
//
|
|
34
|
-
|
|
90
|
+
// Catch and log unhandled errors
|
|
91
|
+
useGlobalErrorHandlers: true
|
|
92
|
+
}
|
|
93
|
+
);
|
|
35
94
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
95
|
+
client.start(async () => {
|
|
96
|
+
// Connect to MongoDB before login
|
|
97
|
+
await client.useDatabase(new MongoDatabase(client));
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Features
|
|
104
|
+
|
|
105
|
+
### Command Management That Doesn't Suck
|
|
106
|
+
|
|
107
|
+
**Slash commands** with subcommand routing:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { SlashCommandBuilder } from "vimcord";
|
|
111
|
+
|
|
112
|
+
export default new SlashCommandBuilder({
|
|
113
|
+
builder: new SlashCommandBuilder()
|
|
114
|
+
.setName("manage")
|
|
115
|
+
.setDescription("Server management")
|
|
116
|
+
.addSubcommand(sub => sub.setName("ban").setDescription("Ban a user")),
|
|
117
|
+
|
|
118
|
+
// Route subcommands automatically
|
|
119
|
+
routes: [
|
|
120
|
+
{
|
|
121
|
+
name: "ban",
|
|
122
|
+
handler: async (client, interaction) => {
|
|
123
|
+
// Handle /manage ban
|
|
124
|
+
}
|
|
42
125
|
}
|
|
126
|
+
],
|
|
127
|
+
|
|
128
|
+
// Permission inference — Vimcord validates before executing
|
|
129
|
+
permissions: {
|
|
130
|
+
user: [PermissionFlagsBits.BanMembers],
|
|
131
|
+
bot: [PermissionFlagsBits.BanMembers]
|
|
43
132
|
}
|
|
44
|
-
);
|
|
133
|
+
});
|
|
134
|
+
```
|
|
45
135
|
|
|
46
|
-
|
|
47
|
-
// NOTE: This runs *BEFORE* the client logs in
|
|
136
|
+
**Prefix commands** with the same DX:
|
|
48
137
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
138
|
+
```ts
|
|
139
|
+
import { PrefixCommandBuilder } from "vimcord";
|
|
140
|
+
|
|
141
|
+
export default new PrefixCommandBuilder({
|
|
142
|
+
name: "ping",
|
|
143
|
+
aliases: ["p"],
|
|
144
|
+
execute: async (client, message, args) => {
|
|
145
|
+
await message.reply("Pong!");
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### BetterEmbed: Stop Writing Boilerplate
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { BetterEmbed } from "vimcord";
|
|
154
|
+
|
|
155
|
+
const embed = new BetterEmbed({
|
|
156
|
+
context: { interaction }, // Auto-context for tokens
|
|
157
|
+
title: "Welcome, $USER!",
|
|
158
|
+
description: ["Your avatar: $USER_AVATAR", "Today is $MONTH/$DAY/$YEAR"],
|
|
159
|
+
color: "#5865F2"
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// ACF (Auto Context Formatting) tokens available:
|
|
163
|
+
// $USER, $USER_NAME, $DISPLAY_NAME, $USER_AVATAR
|
|
164
|
+
// $BOT_AVATAR, $YEAR, $MONTH, $DAY, $INVIS
|
|
165
|
+
|
|
166
|
+
await embed.send(interaction);
|
|
52
167
|
```
|
|
53
168
|
|
|
54
|
-
|
|
169
|
+
### The Paginator: Multi-Page Made Simple
|
|
55
170
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
171
|
+
```ts
|
|
172
|
+
import { Paginator, PaginationType } from "vimcord";
|
|
173
|
+
|
|
174
|
+
const paginator = new Paginator({
|
|
175
|
+
type: PaginationType.LongJump, // first | back | jump | next | last
|
|
176
|
+
timeout: 60000
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Add chapters (groups of pages)
|
|
180
|
+
paginator
|
|
181
|
+
.addChapter([helpPage1, helpPage2, helpPage3], { label: "General Help", emoji: "📖" })
|
|
182
|
+
.addChapter([modPage1, modPage2], { label: "Moderation", emoji: "🛡️" });
|
|
183
|
+
|
|
184
|
+
// Send it anywhere
|
|
185
|
+
const message = await paginator.send(interaction);
|
|
61
186
|
|
|
62
|
-
|
|
187
|
+
// Events for custom logic
|
|
188
|
+
paginator.on("pageChange", (page, index) => {
|
|
189
|
+
console.log(`User viewing page ${index.nested} of chapter ${index.chapter}`);
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Prompt: Confirmation Dialogs
|
|
63
194
|
|
|
64
|
-
|
|
195
|
+
```ts
|
|
196
|
+
import { Prompt } from "vimcord";
|
|
65
197
|
|
|
66
|
-
|
|
198
|
+
const prompt = new Prompt({
|
|
199
|
+
embed: new BetterEmbed({
|
|
200
|
+
title: "Delete this message?",
|
|
201
|
+
description: "This action cannot be undone.",
|
|
202
|
+
context: { interaction }
|
|
203
|
+
}),
|
|
204
|
+
timeout: 30000
|
|
205
|
+
});
|
|
67
206
|
|
|
68
|
-
|
|
207
|
+
await prompt.send(interaction);
|
|
208
|
+
const result = await prompt.awaitResponse();
|
|
69
209
|
|
|
70
|
-
|
|
210
|
+
if (result.confirmed) {
|
|
211
|
+
await message.delete();
|
|
212
|
+
}
|
|
213
|
+
```
|
|
71
214
|
|
|
72
|
-
###
|
|
215
|
+
### BetterModal: V2 Components Done Right
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
import { BetterModal } from "vimcord";
|
|
219
|
+
|
|
220
|
+
const modal = new BetterModal({
|
|
221
|
+
title: "Create Ticket",
|
|
222
|
+
components: [
|
|
223
|
+
{
|
|
224
|
+
textInput: {
|
|
225
|
+
label: "Subject",
|
|
226
|
+
custom_id: "subject",
|
|
227
|
+
style: TextInputStyle.Short,
|
|
228
|
+
required: true
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
textInput: {
|
|
233
|
+
label: "Description",
|
|
234
|
+
custom_id: "description",
|
|
235
|
+
style: TextInputStyle.Paragraph
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Show and await in one call
|
|
242
|
+
const result = await modal.showAndAwait(interaction);
|
|
243
|
+
|
|
244
|
+
if (result) {
|
|
245
|
+
const subject = result.getField("subject");
|
|
246
|
+
await result.reply({
|
|
247
|
+
content: `Ticket created: ${subject}`,
|
|
248
|
+
flags: "Ephemeral"
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### DynaSend: One Method, Every Context
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
import { dynaSend } from "vimcord";
|
|
257
|
+
|
|
258
|
+
// Works with: interactions, channels, messages, users
|
|
259
|
+
// Automatically decides: reply? editReply? followUp? channel.send?
|
|
260
|
+
await dynaSend(interaction, {
|
|
261
|
+
content: "Hello!",
|
|
262
|
+
embeds: [myEmbed],
|
|
263
|
+
components: [actionRow]
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Database: MongoDB Without the Pain
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
import { createMongoSchema, MongoDatabase } from "vimcord";
|
|
271
|
+
|
|
272
|
+
// Define a schema with retry logic built-in
|
|
273
|
+
const UserSchema = createMongoSchema("Users", {
|
|
274
|
+
userId: { type: String, required: true, unique: true },
|
|
275
|
+
username: String,
|
|
276
|
+
balance: { type: Number, default: 0 },
|
|
277
|
+
createdAt: { type: Date, default: Date.now }
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// CRUD operations with automatic retries
|
|
281
|
+
const user = await UserSchema.fetch({ userId: "123" });
|
|
282
|
+
await UserSchema.upsert({ userId: "123" }, { $inc: { balance: 100 } });
|
|
283
|
+
|
|
284
|
+
// Create plugins for reusable logic
|
|
285
|
+
const SoftDeletePlugin = createMongoPlugin(builder => {
|
|
286
|
+
builder.schema.add({ deletedAt: { type: Date, default: null } });
|
|
287
|
+
builder.extend({
|
|
288
|
+
async softDelete(filter) {
|
|
289
|
+
return this.update(filter, { deletedAt: new Date() });
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
UserSchema.use(SoftDeletePlugin);
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Logger: Terminal Output That Doesn't Suck
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
import { Logger } from "vimcord";
|
|
301
|
+
|
|
302
|
+
const logger = new Logger({
|
|
303
|
+
prefix: "Economy",
|
|
304
|
+
prefixEmoji: "💰",
|
|
305
|
+
colors: { primary: "#57F287" }
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
logger.success("User purchased item");
|
|
309
|
+
logger.table("Stats", { users: 150, revenue: "$420.69" });
|
|
310
|
+
|
|
311
|
+
// Loader for async operations
|
|
312
|
+
const stopLoader = logger.loader("Connecting to database...");
|
|
313
|
+
await connectToDB();
|
|
314
|
+
stopLoader("Connected!");
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## API Reference
|
|
320
|
+
|
|
321
|
+
### Client Creation
|
|
322
|
+
|
|
323
|
+
| Export | Description |
|
|
324
|
+
| --------------------------------------------- | ----------------------------- |
|
|
325
|
+
| `createClient(options, features?, config?)` | Create a new Vimcord instance |
|
|
326
|
+
| `Vimcord.create(options, features?, config?)` | Same as above |
|
|
327
|
+
| `Vimcord.getInstance(id?)` | Get existing instance by ID |
|
|
328
|
+
| `Vimcord.getReadyInstance(id?, timeout?)` | Wait for ready instance |
|
|
329
|
+
|
|
330
|
+
### Feature Flags
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
{
|
|
334
|
+
useDefaultSlashCommandHandler: boolean; // Auto-handle slash commands
|
|
335
|
+
useDefaultPrefixCommandHandler: boolean; // Auto-handle prefix commands
|
|
336
|
+
useDefaultContextCommandHandler: boolean; // Auto-handle context commands
|
|
337
|
+
useGlobalErrorHandlers: boolean; // Catch unhandled errors
|
|
338
|
+
importModules: {
|
|
339
|
+
events?: string | string[] | ModuleImportOptions;
|
|
340
|
+
slashCommands?: string | string[] | ModuleImportOptions;
|
|
341
|
+
prefixCommands?: string | string[] | ModuleImportOptions;
|
|
342
|
+
contextCommands?: string | string[] | ModuleImportOptions;
|
|
343
|
+
};
|
|
344
|
+
maxLoginAttempts?: number; // Retry login on failure (default: 3)
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Configuration
|
|
349
|
+
|
|
350
|
+
```ts
|
|
351
|
+
client.configure("app", {
|
|
352
|
+
name: "MyBot", // Display name
|
|
353
|
+
version: "1.0.0", // Version string
|
|
354
|
+
devMode: false, // Use TOKEN_DEV env var
|
|
355
|
+
verbose: false // Extra logging
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
client.configure("staff", {
|
|
359
|
+
ownerId: "123456", // Bot owner
|
|
360
|
+
staffRoleIds: ["..."] // Staff roles
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Examples
|
|
367
|
+
|
|
368
|
+
### Status Rotation
|
|
369
|
+
|
|
370
|
+
```ts
|
|
371
|
+
client.status.setRotation(
|
|
372
|
+
[
|
|
373
|
+
{ name: "with commands", type: ActivityType.Playing },
|
|
374
|
+
{ name: "over {guilds} servers", type: ActivityType.Watching }
|
|
375
|
+
],
|
|
376
|
+
{ interval: 30000 }
|
|
377
|
+
); // Rotate every 30s
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Event Handler
|
|
381
|
+
|
|
382
|
+
```ts
|
|
383
|
+
import { EventBuilder } from "vimcord";
|
|
384
|
+
|
|
385
|
+
export default new EventBuilder({
|
|
386
|
+
event: Events.MessageCreate,
|
|
387
|
+
execute: async (client, message) => {
|
|
388
|
+
if (message.author.bot) return;
|
|
389
|
+
// Handle message
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Error Handling
|
|
395
|
+
|
|
396
|
+
```ts
|
|
397
|
+
// Vimcord automatically catches command errors and sends user-friendly messages
|
|
398
|
+
// Configure what happens on error:
|
|
399
|
+
|
|
400
|
+
client.configure("slashCommands", {
|
|
401
|
+
errorMessage: "❌ Something went wrong! Our team has been notified.",
|
|
402
|
+
logErrors: true
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Or handle specific errors:
|
|
406
|
+
process.on("unhandledRejection", error => {
|
|
407
|
+
client.logger.error("Unhandled rejection", error as Error);
|
|
408
|
+
});
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## Environment Variables
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
# Required
|
|
417
|
+
TOKEN=your_production_bot_token
|
|
418
|
+
TOKEN_DEV=your_development_bot_token # Used when devMode: true
|
|
419
|
+
|
|
420
|
+
# MongoDB (optional)
|
|
421
|
+
MONGO_URI=mongodb://localhost:27017/discord-bot
|
|
422
|
+
```
|
|
73
423
|
|
|
74
|
-
|
|
424
|
+
---
|
|
75
425
|
|
|
76
|
-
|
|
426
|
+
## About
|
|
77
427
|
|
|
78
|
-
|
|
428
|
+
Created by [**xsqu1znt**](https://github.com/xsqu1znt) with a simple goal: make Discord bot development enjoyable again.
|
|
79
429
|
|
|
80
|
-
|
|
430
|
+
Built on top of [qznt](https://github.com/xsqu1znt/qznt) for that extra bit of utility magic.
|
|
81
431
|
|
|
82
|
-
|
|
83
|
-
- **Feature-Rich**: Includes a built-in CLI, automated status rotation, and sophisticated error boundaries.
|
|
84
|
-
- **Developer-Centric**: Focused on performance and ergonomics.
|
|
432
|
+
**License:** MIT
|
|
85
433
|
|
|
86
|
-
|
|
434
|
+
---
|
|
87
435
|
|
|
88
|
-
|
|
436
|
+
<div align="center">
|
|
89
437
|
|
|
90
|
-
|
|
438
|
+
Built with 💜 for the Discord.js community
|
|
91
439
|
|
|
92
|
-
|
|
440
|
+
Found a bug? [Open an issue](https://github.com/xsqu1znt/vimcord/issues)
|
|
93
441
|
|
|
94
|
-
|
|
442
|
+
</div>
|