vimcord 2.0.0 → 2.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 +330 -210
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
╚═══╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
**vhem-cord**
|
|
12
|
+
**vhem-cord** - a small Discord.js framework for typed modules, command dispatching, and reusable UX tools.
|
|
13
13
|
|
|
14
14
|
[](https://www.npmjs.com/package/vimcord)
|
|
15
15
|
[](https://www.npmjs.com/package/vimcord)
|
|
@@ -25,263 +25,335 @@
|
|
|
25
25
|
|
|
26
26
|
## What's Vimcord?
|
|
27
27
|
|
|
28
|
-
**Vimcord**
|
|
28
|
+
**Vimcord** wraps Discord.js with a focused module layer, typed command contexts, shared permission checks, global hooks, and UX helpers for embeds, prompts, modals, components, and pagination.
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
> "I just wanted to build a bot, not write a command handler for the 47th time." — _You, probably_
|
|
30
|
+
It does not hide Discord.js. You still use Discord.js builders, intents, events, permissions, and interactions directly where that is the right tool.
|
|
33
31
|
|
|
34
32
|
---
|
|
35
33
|
|
|
36
34
|
## Installation
|
|
37
35
|
|
|
38
36
|
```bash
|
|
39
|
-
npm install vimcord discord.js
|
|
40
|
-
# or
|
|
41
37
|
pnpm add vimcord discord.js
|
|
42
|
-
# or
|
|
43
|
-
yarn add vimcord discord.js
|
|
44
38
|
```
|
|
45
39
|
|
|
46
|
-
|
|
40
|
+
Optional plugins:
|
|
47
41
|
|
|
48
42
|
```bash
|
|
49
|
-
|
|
43
|
+
pnpm add @vimcord/plugin-dotenv
|
|
44
|
+
pnpm add @vimcord/plugin-mongoose
|
|
50
45
|
```
|
|
51
46
|
|
|
52
47
|
---
|
|
53
48
|
|
|
54
49
|
## Quick Start
|
|
55
50
|
|
|
56
|
-
###
|
|
51
|
+
### Minimum Client
|
|
57
52
|
|
|
58
53
|
```ts
|
|
59
|
-
import {
|
|
54
|
+
import { GatewayIntentBits } from "discord.js";
|
|
55
|
+
import { Vimcord } from "vimcord";
|
|
60
56
|
|
|
61
|
-
const client =
|
|
57
|
+
const client = new Vimcord({
|
|
58
|
+
client: {
|
|
59
|
+
intents: [GatewayIntentBits.Guilds]
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
62
|
|
|
63
|
-
client.
|
|
63
|
+
await client.login();
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
`login()` uses `TOKEN`, or `TOKEN_DEV` when `client.$devMode` is true.
|
|
67
|
+
|
|
68
|
+
### Modules And Command Dispatch
|
|
67
69
|
|
|
68
70
|
```ts
|
|
69
71
|
import { GatewayIntentBits } from "discord.js";
|
|
70
|
-
import {
|
|
72
|
+
import { Vimcord } from "vimcord";
|
|
73
|
+
import { DotEnvPlugin } from "@vimcord/plugin-dotenv";
|
|
71
74
|
|
|
72
|
-
const client =
|
|
73
|
-
{
|
|
75
|
+
const client = new Vimcord({
|
|
76
|
+
client: {
|
|
74
77
|
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent]
|
|
75
78
|
},
|
|
76
|
-
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
events: "./events",
|
|
80
|
-
slashCommands: "./commands/slash",
|
|
81
|
-
prefixCommands: "./commands/prefix",
|
|
82
|
-
contextCommands: "./commands/context"
|
|
79
|
+
globals: {
|
|
80
|
+
app: {
|
|
81
|
+
name: "My Bot"
|
|
83
82
|
},
|
|
83
|
+
staff: {
|
|
84
|
+
ownerId: "123456789012345678",
|
|
85
|
+
superUsers: ["234567890123456789"]
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
connectionRefresh: {
|
|
89
|
+
interval: 60_000,
|
|
90
|
+
maxFailures: 2
|
|
91
|
+
},
|
|
92
|
+
verbose: true
|
|
93
|
+
});
|
|
84
94
|
|
|
85
|
-
|
|
86
|
-
useDefaultSlashCommandHandler: true,
|
|
87
|
-
useDefaultPrefixCommandHandler: true,
|
|
88
|
-
useDefaultContextCommandHandler: true,
|
|
95
|
+
client.use(new DotEnvPlugin());
|
|
89
96
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
97
|
+
await client.modules.load({
|
|
98
|
+
slashCommands: { dir: "./src/commands/slash", suffix: ".slash" },
|
|
99
|
+
prefixCommands: { dir: "./src/commands/prefix", suffix: ".prefix" },
|
|
100
|
+
events: { dir: "./src/events", suffix: ".event" }
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
client.on("interactionCreate", interaction => {
|
|
104
|
+
void client.modules.commands.dispatchInteraction(interaction);
|
|
105
|
+
});
|
|
94
106
|
|
|
95
|
-
client.
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
client.on("messageCreate", message => {
|
|
108
|
+
if (message.author.bot) return;
|
|
109
|
+
void client.modules.commands.dispatchMessage(message, ["!"]);
|
|
98
110
|
});
|
|
111
|
+
|
|
112
|
+
await client.login();
|
|
113
|
+
await client.modules.commands.push();
|
|
99
114
|
```
|
|
100
115
|
|
|
101
116
|
---
|
|
102
117
|
|
|
103
118
|
## Features
|
|
104
119
|
|
|
105
|
-
###
|
|
106
|
-
|
|
107
|
-
**Slash commands** with subcommand routing:
|
|
120
|
+
### Slash Commands
|
|
108
121
|
|
|
109
122
|
```ts
|
|
110
|
-
import { SlashCommandBuilder } from "
|
|
123
|
+
import { PermissionFlagsBits, SlashCommandBuilder } from "discord.js";
|
|
124
|
+
import { SlashCommandModule } from "vimcord";
|
|
111
125
|
|
|
112
|
-
export default new
|
|
126
|
+
export default new SlashCommandModule({
|
|
113
127
|
builder: new SlashCommandBuilder()
|
|
114
128
|
.setName("manage")
|
|
115
129
|
.setDescription("Server management")
|
|
116
|
-
.
|
|
130
|
+
.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers)
|
|
131
|
+
.addSubcommand(subcommand => subcommand.setName("ban").setDescription("Ban a user")),
|
|
117
132
|
|
|
118
|
-
// Route subcommands automatically
|
|
119
133
|
routes: [
|
|
120
134
|
{
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
135
|
+
path: "ban",
|
|
136
|
+
deferReply: { flags: "Ephemeral" },
|
|
137
|
+
async handler({ interaction }) {
|
|
138
|
+
await interaction.editReply("Ban flow started.");
|
|
124
139
|
}
|
|
125
140
|
}
|
|
126
141
|
],
|
|
127
142
|
|
|
128
|
-
// Permission inference — Vimcord validates before executing
|
|
129
143
|
permissions: {
|
|
130
|
-
|
|
131
|
-
bot: [PermissionFlagsBits.BanMembers]
|
|
144
|
+
client: [PermissionFlagsBits.BanMembers]
|
|
132
145
|
}
|
|
133
146
|
});
|
|
134
147
|
```
|
|
135
148
|
|
|
136
|
-
|
|
149
|
+
### Prefix Commands
|
|
137
150
|
|
|
138
151
|
```ts
|
|
139
|
-
import {
|
|
152
|
+
import { PrefixCommandModule } from "vimcord";
|
|
140
153
|
|
|
141
|
-
export default new
|
|
154
|
+
export default new PrefixCommandModule({
|
|
142
155
|
name: "ping",
|
|
143
156
|
aliases: ["p"],
|
|
144
|
-
|
|
145
|
-
|
|
157
|
+
async execute({ message, messageContent, splitContent }) {
|
|
158
|
+
const args = splitContent({ lowercase: true });
|
|
159
|
+
await message.reply(`Pong. You sent ${args.length} arg${args.length === 1 ? "" : "s"}.`);
|
|
146
160
|
}
|
|
147
161
|
});
|
|
148
162
|
```
|
|
149
163
|
|
|
150
|
-
###
|
|
164
|
+
### Event Modules
|
|
151
165
|
|
|
152
166
|
```ts
|
|
153
|
-
import {
|
|
167
|
+
import { Events } from "discord.js";
|
|
168
|
+
import { EventModule } from "vimcord";
|
|
169
|
+
|
|
170
|
+
export default new EventModule({
|
|
171
|
+
name: "logMessages",
|
|
172
|
+
event: Events.MessageCreate,
|
|
173
|
+
async execute({ args: [message] }) {
|
|
174
|
+
if (message.author.bot) return;
|
|
175
|
+
console.log(`${message.author.tag}: ${message.content}`);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Global Command Hooks
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
import { defineGlobalCommandHooks } from "vimcord";
|
|
184
|
+
|
|
185
|
+
defineGlobalCommandHooks({
|
|
186
|
+
slash: {
|
|
187
|
+
async onError({ interaction, error }) {
|
|
188
|
+
const content = `Something went wrong: ${error?.message ?? "Unknown error"}`;
|
|
189
|
+
|
|
190
|
+
if (interaction.replied || interaction.deferred) {
|
|
191
|
+
await interaction.followUp({ content, flags: "Ephemeral" });
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
await interaction.reply({ content, flags: "Ephemeral" });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Command-local hooks override `client.globals.hooks`, and `client.globals.hooks` override `defineGlobalCommandHooks()`.
|
|
202
|
+
|
|
203
|
+
### BetterEmbed
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
import { BetterEmbed, defineGlobalToolConfig } from "vimcord";
|
|
207
|
+
|
|
208
|
+
defineGlobalToolConfig({
|
|
209
|
+
embedColor: "#5865F2",
|
|
210
|
+
embedColorDev: "#FF9D00"
|
|
211
|
+
});
|
|
154
212
|
|
|
155
213
|
const embed = new BetterEmbed({
|
|
156
|
-
context: { interaction },
|
|
157
|
-
title: "Welcome, $
|
|
214
|
+
context: { interaction },
|
|
215
|
+
title: "Welcome, $USER_NAME",
|
|
158
216
|
description: ["Your avatar: $USER_AVATAR", "Today is $MONTH/$DAY/$YEAR"],
|
|
159
|
-
|
|
217
|
+
timestamp: true
|
|
160
218
|
});
|
|
161
219
|
|
|
162
|
-
// ACF (Auto Context Formatting) tokens available:
|
|
163
|
-
// $USER, $USER_NAME, $DISPLAY_NAME, $USER_AVATAR
|
|
164
|
-
// $BOT_AVATAR, $YEAR, $MONTH, $DAY, $INVIS
|
|
165
|
-
|
|
166
220
|
await embed.send(interaction);
|
|
167
221
|
```
|
|
168
222
|
|
|
169
|
-
###
|
|
223
|
+
### BetterContainer And Components V2
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import { ButtonStyle } from "discord.js";
|
|
227
|
+
import { BetterContainer } from "vimcord";
|
|
228
|
+
|
|
229
|
+
const container = new BetterContainer({ color: "#5865F2" })
|
|
230
|
+
.addText("## Account linked")
|
|
231
|
+
.addText(["Your Discord account is connected.", "Use the dashboard button to manage settings."])
|
|
232
|
+
.addSection({
|
|
233
|
+
text: "Open your dashboard.",
|
|
234
|
+
button: {
|
|
235
|
+
customId: "dashboard:open",
|
|
236
|
+
label: "Dashboard",
|
|
237
|
+
style: ButtonStyle.Primary
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
await container.send(interaction);
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Paginator
|
|
170
245
|
|
|
171
246
|
```ts
|
|
172
|
-
import { Paginator, PaginationType } from "vimcord";
|
|
247
|
+
import { BetterContainer, Paginator, PaginationTimeout, PaginationType } from "vimcord";
|
|
248
|
+
|
|
249
|
+
const intro = new BetterContainer().addText("## Help").addText("Choose a page below.");
|
|
250
|
+
const moderation = new BetterContainer().addText("## Moderation").addText("Ban, kick, and timeout commands.");
|
|
173
251
|
|
|
174
252
|
const paginator = new Paginator({
|
|
175
|
-
type: PaginationType.LongJump,
|
|
176
|
-
|
|
253
|
+
type: PaginationType.LongJump,
|
|
254
|
+
idle: 60_000,
|
|
255
|
+
onTimeout: PaginationTimeout.DisableComponents
|
|
177
256
|
});
|
|
178
257
|
|
|
179
|
-
// Add chapters (groups of pages)
|
|
180
258
|
paginator
|
|
181
|
-
.addChapter([
|
|
182
|
-
.addChapter([
|
|
259
|
+
.addChapter([intro, "Use `/help command` for command-specific help."], { label: "General", emoji: "📖" })
|
|
260
|
+
.addChapter([moderation], { label: "Moderation", emoji: "🛡️" });
|
|
183
261
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
// Events for custom logic
|
|
188
|
-
paginator.on("pageChange", (page, index) => {
|
|
189
|
-
console.log(`User viewing page ${index.nested} of chapter ${index.chapter}`);
|
|
262
|
+
paginator.on("pageChange", (_page, index) => {
|
|
263
|
+
console.log(`Viewing chapter ${index.chapter}, page ${index.nested}`);
|
|
190
264
|
});
|
|
265
|
+
|
|
266
|
+
await paginator.send(interaction);
|
|
191
267
|
```
|
|
192
268
|
|
|
193
|
-
### Prompt
|
|
269
|
+
### Prompt
|
|
194
270
|
|
|
195
271
|
```ts
|
|
196
|
-
import {
|
|
272
|
+
import { BetterEmbed, promptMessage, ResolveAction } from "vimcord";
|
|
197
273
|
|
|
198
|
-
const
|
|
274
|
+
const result = await promptMessage(interaction, {
|
|
199
275
|
embed: new BetterEmbed({
|
|
276
|
+
context: { interaction },
|
|
200
277
|
title: "Delete this message?",
|
|
201
|
-
description: "This action cannot be undone."
|
|
202
|
-
context: { interaction }
|
|
278
|
+
description: "This action cannot be undone."
|
|
203
279
|
}),
|
|
204
|
-
|
|
280
|
+
participants: [interaction.user],
|
|
281
|
+
timeout: 30_000,
|
|
282
|
+
onResolve: [ResolveAction.DisableComponents],
|
|
283
|
+
highlightSelectedButton: true
|
|
205
284
|
});
|
|
206
285
|
|
|
207
|
-
await prompt.send(interaction);
|
|
208
|
-
const result = await prompt.awaitResponse();
|
|
209
|
-
|
|
210
286
|
if (result.confirmed) {
|
|
211
|
-
await
|
|
287
|
+
await targetMessage.delete();
|
|
212
288
|
}
|
|
213
289
|
```
|
|
214
290
|
|
|
215
|
-
### BetterModal
|
|
291
|
+
### BetterModal
|
|
216
292
|
|
|
217
293
|
```ts
|
|
294
|
+
import { TextInputStyle } from "discord.js";
|
|
218
295
|
import { BetterModal } from "vimcord";
|
|
219
296
|
|
|
220
|
-
const modal = new BetterModal({
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
label: "Description",
|
|
234
|
-
custom_id: "description",
|
|
235
|
-
style: TextInputStyle.Paragraph
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
]
|
|
239
|
-
});
|
|
297
|
+
const modal = new BetterModal({ title: "Create Ticket" })
|
|
298
|
+
.addTextInput({
|
|
299
|
+
customId: "subject",
|
|
300
|
+
label: "Subject",
|
|
301
|
+
style: TextInputStyle.Short,
|
|
302
|
+
required: true
|
|
303
|
+
})
|
|
304
|
+
.addTextInput({
|
|
305
|
+
customId: "description",
|
|
306
|
+
label: "Description",
|
|
307
|
+
style: TextInputStyle.Paragraph,
|
|
308
|
+
required: false
|
|
309
|
+
});
|
|
240
310
|
|
|
241
|
-
|
|
242
|
-
|
|
311
|
+
const result = await modal.showAndAwait(interaction, { timeout: 60_000 });
|
|
312
|
+
if (!result) return;
|
|
243
313
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
314
|
+
const subject = result.getField<string>("subject", true);
|
|
315
|
+
|
|
316
|
+
await result.reply({
|
|
317
|
+
content: `Ticket created: ${subject}`,
|
|
318
|
+
flags: "Ephemeral"
|
|
319
|
+
});
|
|
251
320
|
```
|
|
252
321
|
|
|
253
|
-
### DynaSend
|
|
322
|
+
### DynaSend
|
|
254
323
|
|
|
255
324
|
```ts
|
|
256
|
-
import { dynaSend } from "vimcord";
|
|
325
|
+
import { dynaSend, SendMethod } from "vimcord";
|
|
257
326
|
|
|
258
|
-
// Works with: interactions, channels, messages, users
|
|
259
|
-
// Automatically decides: reply? editReply? followUp? channel.send?
|
|
260
327
|
await dynaSend(interaction, {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
328
|
+
sendMethod: interaction.deferred || interaction.replied ? SendMethod.EditReply : SendMethod.Reply,
|
|
329
|
+
content: "Hello from one send helper.",
|
|
330
|
+
embeds: [embed]
|
|
264
331
|
});
|
|
265
332
|
```
|
|
266
333
|
|
|
267
|
-
###
|
|
334
|
+
### MongoDB Plugin
|
|
268
335
|
|
|
269
336
|
```ts
|
|
270
|
-
import { createMongoSchema,
|
|
337
|
+
import { createMongoPlugin, createMongoSchema, MongoosePlugin } from "@vimcord/plugin-mongoose";
|
|
271
338
|
|
|
272
|
-
|
|
273
|
-
|
|
339
|
+
client.use(
|
|
340
|
+
new MongoosePlugin({
|
|
341
|
+
connectionRefresh: {
|
|
342
|
+
interval: 60_000,
|
|
343
|
+
maxFailures: 2
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
const Users = createMongoSchema("Users", {
|
|
274
349
|
userId: { type: String, required: true, unique: true },
|
|
275
|
-
username: String,
|
|
276
350
|
balance: { type: Number, default: 0 },
|
|
277
351
|
createdAt: { type: Date, default: Date.now }
|
|
278
352
|
});
|
|
279
353
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
await UserSchema.upsert({ userId: "123" }, { $inc: { balance: 100 } });
|
|
354
|
+
const user = await Users.fetch({ userId: "123" }, undefined, { required: true });
|
|
355
|
+
await Users.upsert({ userId: "123" }, { $inc: { balance: 100 } });
|
|
283
356
|
|
|
284
|
-
// Create plugins for reusable logic
|
|
285
357
|
const SoftDeletePlugin = createMongoPlugin(builder => {
|
|
286
358
|
builder.schema.add({ deletedAt: { type: Date, default: null } });
|
|
287
359
|
builder.extend({
|
|
@@ -291,73 +363,105 @@ const SoftDeletePlugin = createMongoPlugin(builder => {
|
|
|
291
363
|
});
|
|
292
364
|
});
|
|
293
365
|
|
|
294
|
-
|
|
366
|
+
Users.use(SoftDeletePlugin);
|
|
295
367
|
```
|
|
296
368
|
|
|
297
|
-
### Logger
|
|
369
|
+
### Client Logger
|
|
298
370
|
|
|
299
371
|
```ts
|
|
300
|
-
|
|
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" });
|
|
372
|
+
client.logger.success("Startup complete");
|
|
310
373
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
stopLoader("Connected!");
|
|
374
|
+
const stopLoader = client.logger.loader("Syncing commands...");
|
|
375
|
+
await client.modules.commands.push();
|
|
376
|
+
stopLoader("Commands synced");
|
|
315
377
|
```
|
|
316
378
|
|
|
317
379
|
---
|
|
318
380
|
|
|
319
381
|
## API Reference
|
|
320
382
|
|
|
321
|
-
###
|
|
322
|
-
|
|
323
|
-
| Export
|
|
324
|
-
|
|
|
325
|
-
| `
|
|
326
|
-
| `
|
|
327
|
-
| `
|
|
328
|
-
| `
|
|
329
|
-
|
|
330
|
-
|
|
383
|
+
### Core Exports
|
|
384
|
+
|
|
385
|
+
| Export | Description |
|
|
386
|
+
| --- | --- |
|
|
387
|
+
| `Vimcord` | Discord.js client subclass with modules, plugins, globals, status, and logging |
|
|
388
|
+
| `SlashCommandModule` | Slash command module with optional subcommand routes |
|
|
389
|
+
| `PrefixCommandModule` | Prefix command module with aliases and parsed message content |
|
|
390
|
+
| `MessageContextCommandModule` | Message context menu command module |
|
|
391
|
+
| `UserContextCommandModule` | User context menu command module |
|
|
392
|
+
| `EventModule` | Typed Discord event module |
|
|
393
|
+
| `BetterEmbed` | Embed helper with context formatting |
|
|
394
|
+
| `BetterContainer` | Components V2 container helper |
|
|
395
|
+
| `Paginator` | Component-based paginator |
|
|
396
|
+
| `BetterModal` | Modal helper with V2 component support |
|
|
397
|
+
| `promptMessage`, `promptModal` | Confirmation prompt helpers |
|
|
398
|
+
| `dynaSend` | Send helper for interactions, channels, messages, members, and users |
|
|
399
|
+
| `defineGlobalToolConfig` | Global UX defaults for embeds, collectors, paginator, and prompts |
|
|
400
|
+
| `defineGlobalCommandHooks` | Global command hooks used when modules do not define local hooks |
|
|
401
|
+
|
|
402
|
+
### Client Options
|
|
331
403
|
|
|
332
404
|
```ts
|
|
333
|
-
{
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
405
|
+
const client = new Vimcord({
|
|
406
|
+
customId: "main",
|
|
407
|
+
client: {
|
|
408
|
+
intents: [GatewayIntentBits.Guilds]
|
|
409
|
+
},
|
|
410
|
+
globals: {
|
|
411
|
+
app: {
|
|
412
|
+
name: "My Bot",
|
|
413
|
+
devMode: false,
|
|
414
|
+
verbose: false,
|
|
415
|
+
disableBanner: false
|
|
416
|
+
},
|
|
417
|
+
staff: {
|
|
418
|
+
ownerId: "123456789012345678",
|
|
419
|
+
superUsers: [],
|
|
420
|
+
superUserRoles: []
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
connectionRefresh: {
|
|
424
|
+
interval: 60_000,
|
|
425
|
+
requestTimeout: 10_000,
|
|
426
|
+
maxFailures: 2,
|
|
427
|
+
maxRefreshAttempts: 3
|
|
428
|
+
},
|
|
429
|
+
logLevel: "debug",
|
|
430
|
+
verbose: false
|
|
431
|
+
});
|
|
346
432
|
```
|
|
347
433
|
|
|
348
|
-
###
|
|
434
|
+
### Module Loading
|
|
349
435
|
|
|
350
436
|
```ts
|
|
351
|
-
client.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
437
|
+
await client.modules.load({
|
|
438
|
+
slashCommands: { dir: "./src/commands/slash", suffix: ".slash" },
|
|
439
|
+
prefixCommands: { dir: "./src/commands/prefix", suffix: ".prefix" },
|
|
440
|
+
messageContextCommands: { dir: "./src/commands/message-context", suffix: ".mctx" },
|
|
441
|
+
userContextCommands: { dir: "./src/commands/user-context", suffix: ".uctx" },
|
|
442
|
+
events: { dir: "./src/events", suffix: ".event" }
|
|
356
443
|
});
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Runtime Configuration
|
|
357
447
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
448
|
+
```ts
|
|
449
|
+
client.configure({
|
|
450
|
+
app: {
|
|
451
|
+
name: "My Bot",
|
|
452
|
+
devMode: true
|
|
453
|
+
},
|
|
454
|
+
staff: {
|
|
455
|
+
ownerId: "123456789012345678",
|
|
456
|
+
superUserRoles: ["987654321098765432"]
|
|
457
|
+
},
|
|
458
|
+
hooks: {
|
|
459
|
+
prefix: {
|
|
460
|
+
async onError({ message, error }) {
|
|
461
|
+
await message.reply(`Command failed: ${error?.message ?? "Unknown error"}`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
361
465
|
});
|
|
362
466
|
```
|
|
363
467
|
|
|
@@ -367,45 +471,62 @@ client.configure("staff", {
|
|
|
367
471
|
|
|
368
472
|
### Status Rotation
|
|
369
473
|
|
|
474
|
+
Status config is user-owned. Vimcord does not provide a default status rotation.
|
|
475
|
+
|
|
370
476
|
```ts
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
477
|
+
import { ActivityType } from "discord.js";
|
|
478
|
+
|
|
479
|
+
await client.status.set({
|
|
480
|
+
production: {
|
|
481
|
+
interval: 30_000,
|
|
482
|
+
randomize: true,
|
|
483
|
+
activity: [
|
|
484
|
+
{ name: "$GUILD_COUNT servers", type: ActivityType.Watching, status: "online" },
|
|
485
|
+
{ name: "Need help? Use /help", type: ActivityType.Custom, status: "online" }
|
|
486
|
+
]
|
|
487
|
+
},
|
|
488
|
+
development: {
|
|
489
|
+
activity: { name: "In development", type: ActivityType.Custom, status: "dnd" }
|
|
490
|
+
}
|
|
491
|
+
});
|
|
378
492
|
```
|
|
379
493
|
|
|
380
|
-
###
|
|
494
|
+
### Command Dispatch Events
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
import { Events } from "discord.js";
|
|
498
|
+
import { EventModule } from "vimcord";
|
|
499
|
+
|
|
500
|
+
export default new EventModule({
|
|
501
|
+
name: "dispatchInteractions",
|
|
502
|
+
event: Events.InteractionCreate,
|
|
503
|
+
async execute({ client, args: [interaction] }) {
|
|
504
|
+
await client.modules.commands.dispatchInteraction(interaction);
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
```
|
|
381
508
|
|
|
382
509
|
```ts
|
|
383
|
-
import {
|
|
510
|
+
import { Events } from "discord.js";
|
|
511
|
+
import { EventModule } from "vimcord";
|
|
384
512
|
|
|
385
|
-
export default new
|
|
513
|
+
export default new EventModule({
|
|
514
|
+
name: "dispatchPrefixCommands",
|
|
386
515
|
event: Events.MessageCreate,
|
|
387
|
-
|
|
516
|
+
async execute({ client, args: [message] }) {
|
|
388
517
|
if (message.author.bot) return;
|
|
389
|
-
|
|
518
|
+
await client.modules.commands.dispatchMessage(message, ["!", "?"]);
|
|
390
519
|
}
|
|
391
520
|
});
|
|
392
521
|
```
|
|
393
522
|
|
|
394
|
-
###
|
|
523
|
+
### Bot Staff Checks
|
|
395
524
|
|
|
396
525
|
```ts
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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
|
-
});
|
|
526
|
+
const isStaff = await client.isBotStaff(interaction.user.id);
|
|
527
|
+
if (!isStaff) {
|
|
528
|
+
await interaction.reply({ content: "This is staff-only.", flags: "Ephemeral" });
|
|
529
|
+
}
|
|
409
530
|
```
|
|
410
531
|
|
|
411
532
|
---
|
|
@@ -413,12 +534,11 @@ process.on("unhandledRejection", error => {
|
|
|
413
534
|
## Environment Variables
|
|
414
535
|
|
|
415
536
|
```bash
|
|
416
|
-
# Required
|
|
417
537
|
TOKEN=your_production_bot_token
|
|
418
|
-
TOKEN_DEV=your_development_bot_token
|
|
538
|
+
TOKEN_DEV=your_development_bot_token
|
|
419
539
|
|
|
420
|
-
# MongoDB (optional)
|
|
421
540
|
MONGO_URI=mongodb://localhost:27017/discord-bot
|
|
541
|
+
MONGO_URI_DEV=mongodb://localhost:27017/discord-bot-dev
|
|
422
542
|
```
|
|
423
543
|
|
|
424
544
|
---
|
|
@@ -435,7 +555,7 @@ Built on top of [qznt](https://github.com/xsqu1znt/qznt) for that extra bit of u
|
|
|
435
555
|
|
|
436
556
|
<div align="center">
|
|
437
557
|
|
|
438
|
-
Built with
|
|
558
|
+
Built with love for the Discord.js community
|
|
439
559
|
|
|
440
560
|
Found a bug? [Open an issue](https://github.com/xsqu1znt/vimcord/issues)
|
|
441
561
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vimcord",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "A powerful and opinionated Discord.js wrapper.",
|
|
5
5
|
"author": "xsqu1znt",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"type": "module",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@vimcord/core": "0.1.
|
|
19
|
+
"@vimcord/core": "0.1.1"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "tsup",
|