vimcord 1.0.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/dist/index.cjs +4203 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +1493 -0
- package/dist/index.d.ts +1493 -0
- package/dist/index.js +4151 -0
- package/dist/index.js.map +1 -0
- package/dist/metafile-cjs.json +1 -0
- package/dist/metafile-esm.json +1 -0
- package/package.json +58 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,4203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
BaseCommandBuilder: () => BaseCommandBuilder,
|
|
34
|
+
BetterContainer: () => BetterContainer,
|
|
35
|
+
BetterEmbed: () => BetterEmbed,
|
|
36
|
+
BetterModal: () => BetterModal,
|
|
37
|
+
CLI: () => CLI,
|
|
38
|
+
CommandType: () => CommandType,
|
|
39
|
+
ContextCommandBuilder: () => ContextCommandBuilder,
|
|
40
|
+
DynaSend: () => DynaSend,
|
|
41
|
+
EventBuilder: () => EventBuilder,
|
|
42
|
+
LogLevel: () => LogLevel,
|
|
43
|
+
Logger: () => Logger,
|
|
44
|
+
MissingPermissionReason: () => MissingPermissionReason,
|
|
45
|
+
MongoDatabase: () => MongoDatabase,
|
|
46
|
+
MongoSchemaBuilder: () => MongoSchemaBuilder,
|
|
47
|
+
PaginationTimeoutType: () => PaginationTimeoutType,
|
|
48
|
+
PaginationType: () => PaginationType,
|
|
49
|
+
Paginator: () => Paginator,
|
|
50
|
+
PrefixCommandBuilder: () => PrefixCommandBuilder,
|
|
51
|
+
Prompt: () => Prompt,
|
|
52
|
+
PromptResolveType: () => PromptResolveType,
|
|
53
|
+
RateLimitScope: () => RateLimitScope,
|
|
54
|
+
SendMethod: () => SendMethod,
|
|
55
|
+
SlashCommandBuilder: () => SlashCommandBuilder,
|
|
56
|
+
StatusType: () => StatusType,
|
|
57
|
+
Vimcord: () => Vimcord,
|
|
58
|
+
VimcordCLI: () => VimcordCLI,
|
|
59
|
+
VimcordCommandManager: () => VimcordCommandManager,
|
|
60
|
+
VimcordContextCommandManager: () => VimcordContextCommandManager,
|
|
61
|
+
VimcordEventManager: () => VimcordEventManager,
|
|
62
|
+
VimcordPrefixCommandManager: () => VimcordPrefixCommandManager,
|
|
63
|
+
VimcordSlashCommandManager: () => VimcordSlashCommandManager,
|
|
64
|
+
VimcordStatusManager: () => VimcordStatusManager,
|
|
65
|
+
__zero: () => __zero,
|
|
66
|
+
cleanMention: () => cleanMention,
|
|
67
|
+
clientInstances: () => clientInstances,
|
|
68
|
+
createClient: () => createClient,
|
|
69
|
+
createMongoSchema: () => createMongoSchema,
|
|
70
|
+
createToolsConfig: () => createToolsConfig,
|
|
71
|
+
createVimcordAppConfig: () => createVimcordAppConfig,
|
|
72
|
+
createVimcordContextCommandConfig: () => createVimcordContextCommandConfig,
|
|
73
|
+
createVimcordPrefixCommandConfig: () => createVimcordPrefixCommandConfig,
|
|
74
|
+
createVimcordSlashCommandConfig: () => createVimcordSlashCommandConfig,
|
|
75
|
+
createVimcordStaffConfig: () => createVimcordStaffConfig,
|
|
76
|
+
createVimcordStatusConfig: () => createVimcordStatusConfig,
|
|
77
|
+
defineGlobalToolsConfig: () => defineGlobalToolsConfig,
|
|
78
|
+
dynaSend: () => dynaSend,
|
|
79
|
+
fetchChannel: () => fetchChannel,
|
|
80
|
+
fetchGuild: () => fetchGuild,
|
|
81
|
+
fetchMember: () => fetchMember,
|
|
82
|
+
fetchMessage: () => fetchMessage,
|
|
83
|
+
fetchRole: () => fetchRole,
|
|
84
|
+
fetchUser: () => fetchUser,
|
|
85
|
+
formatThousands: () => formatThousands,
|
|
86
|
+
getCallerFileName: () => getCallerFileName,
|
|
87
|
+
getClientInstances: () => getClientInstances,
|
|
88
|
+
getFirstMentionId: () => getFirstMentionId,
|
|
89
|
+
getMessageMention: () => getMessageMention,
|
|
90
|
+
getProcessDir: () => getProcessDir,
|
|
91
|
+
globalVimcordToolsConfig: () => globalVimcordToolsConfig,
|
|
92
|
+
importModulesFromDir: () => importModulesFromDir,
|
|
93
|
+
initCLI: () => initCLI,
|
|
94
|
+
isMentionOrSnowflake: () => isMentionOrSnowflake,
|
|
95
|
+
logger: () => logger,
|
|
96
|
+
pickRandom: () => pickRandom,
|
|
97
|
+
prompt: () => prompt,
|
|
98
|
+
retryExponentialBackoff: () => retryExponentialBackoff,
|
|
99
|
+
sendCommandErrorEmbed: () => sendCommandErrorEmbed,
|
|
100
|
+
useClient: () => useClient,
|
|
101
|
+
useMongoDatabase: () => useMongoDatabase,
|
|
102
|
+
useReadyClient: () => useReadyClient,
|
|
103
|
+
validateCommandPermissions: () => validateCommandPermissions
|
|
104
|
+
});
|
|
105
|
+
module.exports = __toCommonJS(index_exports);
|
|
106
|
+
|
|
107
|
+
// src/types/command.base.ts
|
|
108
|
+
var CommandType = /* @__PURE__ */ ((CommandType3) => {
|
|
109
|
+
CommandType3[CommandType3["Slash"] = 0] = "Slash";
|
|
110
|
+
CommandType3[CommandType3["Prefix"] = 1] = "Prefix";
|
|
111
|
+
CommandType3[CommandType3["Context"] = 2] = "Context";
|
|
112
|
+
return CommandType3;
|
|
113
|
+
})(CommandType || {});
|
|
114
|
+
var MissingPermissionReason = /* @__PURE__ */ ((MissingPermissionReason2) => {
|
|
115
|
+
MissingPermissionReason2[MissingPermissionReason2["User"] = 0] = "User";
|
|
116
|
+
MissingPermissionReason2[MissingPermissionReason2["Bot"] = 1] = "Bot";
|
|
117
|
+
MissingPermissionReason2[MissingPermissionReason2["Role"] = 2] = "Role";
|
|
118
|
+
MissingPermissionReason2[MissingPermissionReason2["UserBlacklisted"] = 3] = "UserBlacklisted";
|
|
119
|
+
MissingPermissionReason2[MissingPermissionReason2["RoleBlacklisted"] = 4] = "RoleBlacklisted";
|
|
120
|
+
MissingPermissionReason2[MissingPermissionReason2["NotInGuild"] = 5] = "NotInGuild";
|
|
121
|
+
MissingPermissionReason2[MissingPermissionReason2["NotGuildOwner"] = 6] = "NotGuildOwner";
|
|
122
|
+
MissingPermissionReason2[MissingPermissionReason2["NotBotOwner"] = 7] = "NotBotOwner";
|
|
123
|
+
MissingPermissionReason2[MissingPermissionReason2["NotBotStaff"] = 8] = "NotBotStaff";
|
|
124
|
+
return MissingPermissionReason2;
|
|
125
|
+
})(MissingPermissionReason || {});
|
|
126
|
+
var RateLimitScope = /* @__PURE__ */ ((RateLimitScope2) => {
|
|
127
|
+
RateLimitScope2[RateLimitScope2["User"] = 0] = "User";
|
|
128
|
+
RateLimitScope2[RateLimitScope2["Guild"] = 1] = "Guild";
|
|
129
|
+
RateLimitScope2[RateLimitScope2["Channel"] = 2] = "Channel";
|
|
130
|
+
RateLimitScope2[RateLimitScope2["Global"] = 3] = "Global";
|
|
131
|
+
return RateLimitScope2;
|
|
132
|
+
})(RateLimitScope || {});
|
|
133
|
+
|
|
134
|
+
// src/validators/permissions.validator.ts
|
|
135
|
+
var import_discord = require("discord.js");
|
|
136
|
+
function __existsAndTrue(value) {
|
|
137
|
+
return value !== void 0 && value;
|
|
138
|
+
}
|
|
139
|
+
function validateCommandPermissions(permissions, client, user, command) {
|
|
140
|
+
const inGuild = "guild" in user;
|
|
141
|
+
const missingUserPermissions = [];
|
|
142
|
+
const missingBotPermissions = [];
|
|
143
|
+
const missingRoles = [];
|
|
144
|
+
if (permissions.user?.length && inGuild) {
|
|
145
|
+
for (const permission of permissions.user) {
|
|
146
|
+
if (!user.permissions.has(permission)) {
|
|
147
|
+
missingUserPermissions.push(permission);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (missingUserPermissions.length) {
|
|
151
|
+
return { validated: false, failReason: 0 /* User */, missingUserPermissions };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (permissions.bot?.length && inGuild && user.guild.members.me) {
|
|
155
|
+
for (const permission of permissions.bot) {
|
|
156
|
+
if (!user.guild.members.me.permissions.has(permission)) {
|
|
157
|
+
missingBotPermissions.push(permission);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (missingBotPermissions.length) {
|
|
161
|
+
return { validated: false, failReason: 1 /* Bot */, missingBotPermissions };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (permissions.roles?.length && inGuild) {
|
|
165
|
+
for (const role of permissions.roles) {
|
|
166
|
+
if (!user.roles.cache.has(role)) {
|
|
167
|
+
missingRoles.push(role);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (missingRoles.length) {
|
|
171
|
+
return { validated: false, failReason: 2 /* Role */, missingRoles };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (permissions.userBlacklist?.length) {
|
|
175
|
+
if (permissions.userBlacklist.includes(user.id)) {
|
|
176
|
+
return { validated: false, failReason: 3 /* UserBlacklisted */, blacklistedUser: user.id };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (permissions.roleBlacklist?.length && inGuild) {
|
|
180
|
+
if (user.roles.cache.some((role) => permissions.roleBlacklist.includes(role.id))) {
|
|
181
|
+
return { validated: false, failReason: 4 /* RoleBlacklisted */, blacklistedRole: user.id };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (__existsAndTrue(permissions.guildOnly) && !inGuild) {
|
|
185
|
+
return { validated: false, failReason: 5 /* NotInGuild */ };
|
|
186
|
+
}
|
|
187
|
+
if (__existsAndTrue(permissions.guildOwnerOnly) && inGuild && user.id !== user.guild.ownerId) {
|
|
188
|
+
return { validated: false, failReason: 6 /* NotGuildOwner */ };
|
|
189
|
+
}
|
|
190
|
+
if (__existsAndTrue(permissions.botOwnerOnly) && user.id !== client.config.staff.ownerId) {
|
|
191
|
+
return { validated: false, failReason: 7 /* NotBotOwner */ };
|
|
192
|
+
}
|
|
193
|
+
if (__existsAndTrue(permissions.botStaffOnly)) {
|
|
194
|
+
if (!client.config.staff.superUsers.includes(user.id)) {
|
|
195
|
+
return { validated: false, failReason: 8 /* NotBotStaff */ };
|
|
196
|
+
}
|
|
197
|
+
if (inGuild) {
|
|
198
|
+
for (const [k, role] of user.roles.cache) {
|
|
199
|
+
if (!user.roles.cache.has(role.id)) {
|
|
200
|
+
missingRoles.push(role.id);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (missingRoles.length) {
|
|
204
|
+
return { validated: false, failReason: 8 /* NotBotStaff */, missingRoles };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (command instanceof import_discord.BaseInteraction && command.isCommand()) {
|
|
208
|
+
let commandName = null;
|
|
209
|
+
if (command.isChatInputCommand()) {
|
|
210
|
+
const subcommand = command.options.getSubcommand();
|
|
211
|
+
commandName = `${command.commandName}${subcommand ? ` ${subcommand}` : ""}`;
|
|
212
|
+
} else {
|
|
213
|
+
commandName = command.commandName;
|
|
214
|
+
}
|
|
215
|
+
if (!client.config.staff.bypassers.some(
|
|
216
|
+
(bypass) => bypass.commandName.toLowerCase() === commandName.toLowerCase() && bypass.userIds.includes(user.id)
|
|
217
|
+
)) {
|
|
218
|
+
return { validated: false, failReason: 8 /* NotBotStaff */ };
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (typeof command === "string" && !client.config.staff.bypassers.some(
|
|
222
|
+
(bypass) => bypass.commandName.toLowerCase() === command.toLowerCase() && bypass.userIds.includes(user.id)
|
|
223
|
+
)) {
|
|
224
|
+
return { validated: false, failReason: 8 /* NotBotStaff */ };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return { validated: true };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/builders/baseCommand.builder.ts
|
|
231
|
+
var import_node_crypto = require("crypto");
|
|
232
|
+
var import_lodash = __toESM(require("lodash"));
|
|
233
|
+
var BaseCommandBuilder = class {
|
|
234
|
+
uuid = (0, import_node_crypto.randomUUID)();
|
|
235
|
+
commandType;
|
|
236
|
+
client;
|
|
237
|
+
enabled;
|
|
238
|
+
conditions;
|
|
239
|
+
permissions;
|
|
240
|
+
metadata;
|
|
241
|
+
rateLimit;
|
|
242
|
+
beforeExecute;
|
|
243
|
+
execute;
|
|
244
|
+
afterExecute;
|
|
245
|
+
onRateLimit;
|
|
246
|
+
onMissingPermissions;
|
|
247
|
+
onConditionsNotMet;
|
|
248
|
+
onUsedWhenDisabled;
|
|
249
|
+
onError;
|
|
250
|
+
globalRateLimitData = { executions: 0, timestamp: 0 };
|
|
251
|
+
userRateLimitData = /* @__PURE__ */ new Map();
|
|
252
|
+
guildRateLimitData = /* @__PURE__ */ new Map();
|
|
253
|
+
channelRateLimitData = /* @__PURE__ */ new Map();
|
|
254
|
+
constructor(type, config) {
|
|
255
|
+
this.commandType = type;
|
|
256
|
+
this.enabled = config?.enabled ?? true;
|
|
257
|
+
this.conditions = config?.conditions;
|
|
258
|
+
this.permissions = config?.permissions;
|
|
259
|
+
this.metadata = config?.metadata;
|
|
260
|
+
this.rateLimit = config?.rateLimit;
|
|
261
|
+
this.beforeExecute = config?.beforeExecute;
|
|
262
|
+
this.execute = config?.execute;
|
|
263
|
+
this.afterExecute = config?.afterExecute;
|
|
264
|
+
this.onRateLimit = config?.onRateLimit;
|
|
265
|
+
this.onMissingPermissions = config?.onMissingPermissions;
|
|
266
|
+
this.onConditionsNotMet = config?.onConditionsNotMet;
|
|
267
|
+
this.onUsedWhenDisabled = config?.onUsedWhenDisabled;
|
|
268
|
+
this.onError = config?.onError;
|
|
269
|
+
this.validateBaseConfig();
|
|
270
|
+
}
|
|
271
|
+
validateBaseConfig() {
|
|
272
|
+
if (this.rateLimit) {
|
|
273
|
+
if (this.rateLimit.max <= 0) {
|
|
274
|
+
throw new Error("DJSSlashCommandBuilder: Rate limit max must be greater than 0");
|
|
275
|
+
}
|
|
276
|
+
if (this.rateLimit.interval <= 0) {
|
|
277
|
+
throw new Error("DJSSlashCommandBuilder: Rate limit interval must be greater than 0");
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
toConfig() {
|
|
282
|
+
return {
|
|
283
|
+
enabled: this.enabled,
|
|
284
|
+
conditions: this.conditions,
|
|
285
|
+
permissions: this.permissions,
|
|
286
|
+
metadata: this.metadata,
|
|
287
|
+
rateLimit: this.rateLimit,
|
|
288
|
+
beforeExecute: this.beforeExecute,
|
|
289
|
+
execute: this.execute,
|
|
290
|
+
afterExecute: this.afterExecute,
|
|
291
|
+
onMissingPermissions: this.onMissingPermissions,
|
|
292
|
+
onConditionsNotMet: this.onConditionsNotMet,
|
|
293
|
+
onUsedWhenDisabled: this.onUsedWhenDisabled,
|
|
294
|
+
onRateLimit: this.onRateLimit,
|
|
295
|
+
onError: this.onError
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
setEnabled(enabled) {
|
|
299
|
+
this.enabled = enabled;
|
|
300
|
+
return this;
|
|
301
|
+
}
|
|
302
|
+
addConditions(...conditions) {
|
|
303
|
+
if (!this.conditions) this.conditions = [];
|
|
304
|
+
this.conditions.push(...conditions);
|
|
305
|
+
return this;
|
|
306
|
+
}
|
|
307
|
+
setConditions(conditions) {
|
|
308
|
+
this.conditions = conditions;
|
|
309
|
+
return this;
|
|
310
|
+
}
|
|
311
|
+
setPermissions(permissions) {
|
|
312
|
+
this.permissions = import_lodash.default.merge(this.permissions, permissions);
|
|
313
|
+
return this;
|
|
314
|
+
}
|
|
315
|
+
setMetadata(metadata) {
|
|
316
|
+
this.metadata = import_lodash.default.merge(this.metadata, metadata);
|
|
317
|
+
return this;
|
|
318
|
+
}
|
|
319
|
+
setRateLimit(options) {
|
|
320
|
+
this.rateLimit = options;
|
|
321
|
+
return this;
|
|
322
|
+
}
|
|
323
|
+
setBeforeExecute(callback) {
|
|
324
|
+
this.beforeExecute = callback;
|
|
325
|
+
return this;
|
|
326
|
+
}
|
|
327
|
+
setExecute(callback) {
|
|
328
|
+
this.execute = callback;
|
|
329
|
+
return this;
|
|
330
|
+
}
|
|
331
|
+
setAfterExecute(callback) {
|
|
332
|
+
this.afterExecute = callback;
|
|
333
|
+
return this;
|
|
334
|
+
}
|
|
335
|
+
setOnRateLimit(callback) {
|
|
336
|
+
this.onRateLimit = callback;
|
|
337
|
+
return this;
|
|
338
|
+
}
|
|
339
|
+
setOnMissingPermissions(callback) {
|
|
340
|
+
this.onMissingPermissions = callback;
|
|
341
|
+
return this;
|
|
342
|
+
}
|
|
343
|
+
setOnConditionsNotMet(callback) {
|
|
344
|
+
this.onConditionsNotMet = callback;
|
|
345
|
+
return this;
|
|
346
|
+
}
|
|
347
|
+
setOnUsedWhenDisabled(callback) {
|
|
348
|
+
this.onUsedWhenDisabled = callback;
|
|
349
|
+
return this;
|
|
350
|
+
}
|
|
351
|
+
setOnError(callback) {
|
|
352
|
+
this.onError = callback;
|
|
353
|
+
return this;
|
|
354
|
+
}
|
|
355
|
+
getRateLimitInfo(user, guild, channel) {
|
|
356
|
+
if (!this.rateLimit) return null;
|
|
357
|
+
let rateLimitData;
|
|
358
|
+
switch (this.rateLimit.scope) {
|
|
359
|
+
case 0 /* User */:
|
|
360
|
+
if (!user) return null;
|
|
361
|
+
rateLimitData = this.userRateLimitData.get(user.id) ?? { executions: 0, timestamp: 0 };
|
|
362
|
+
break;
|
|
363
|
+
case 1 /* Guild */:
|
|
364
|
+
if (!guild) return null;
|
|
365
|
+
rateLimitData = this.guildRateLimitData.get(guild.id) ?? { executions: 0, timestamp: 0 };
|
|
366
|
+
break;
|
|
367
|
+
case 2 /* Channel */:
|
|
368
|
+
if (!channel) return null;
|
|
369
|
+
rateLimitData = this.channelRateLimitData.get(channel.id) ?? { executions: 0, timestamp: 0 };
|
|
370
|
+
break;
|
|
371
|
+
case 3 /* Global */:
|
|
372
|
+
rateLimitData = this.globalRateLimitData;
|
|
373
|
+
break;
|
|
374
|
+
default:
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
return { ...rateLimitData, isLimited: this.isRateLimited(user, guild, channel, false) };
|
|
378
|
+
}
|
|
379
|
+
isRateLimited(user, guild, channel, updateExecutions = true) {
|
|
380
|
+
if (!this.rateLimit) return false;
|
|
381
|
+
const now = Date.now();
|
|
382
|
+
let rateLimitData;
|
|
383
|
+
switch (this.rateLimit.scope) {
|
|
384
|
+
case 0 /* User */:
|
|
385
|
+
if (!user) return false;
|
|
386
|
+
rateLimitData = this.userRateLimitData.get(user.id) ?? { executions: 0, timestamp: 0 };
|
|
387
|
+
if (now - rateLimitData.timestamp >= this.rateLimit.interval) {
|
|
388
|
+
rateLimitData.executions = 0;
|
|
389
|
+
rateLimitData.timestamp = now;
|
|
390
|
+
}
|
|
391
|
+
if (updateExecutions) rateLimitData.executions++;
|
|
392
|
+
this.userRateLimitData.set(user.id, rateLimitData);
|
|
393
|
+
break;
|
|
394
|
+
case 1 /* Guild */:
|
|
395
|
+
if (!guild) return false;
|
|
396
|
+
rateLimitData = this.guildRateLimitData.get(guild.id) ?? { executions: 0, timestamp: 0 };
|
|
397
|
+
if (now - rateLimitData.timestamp >= this.rateLimit.interval) {
|
|
398
|
+
rateLimitData.executions = 0;
|
|
399
|
+
rateLimitData.timestamp = now;
|
|
400
|
+
}
|
|
401
|
+
if (updateExecutions) rateLimitData.executions++;
|
|
402
|
+
this.guildRateLimitData.set(guild.id, rateLimitData);
|
|
403
|
+
break;
|
|
404
|
+
case 2 /* Channel */:
|
|
405
|
+
if (!channel) return false;
|
|
406
|
+
rateLimitData = this.guildRateLimitData.get(channel.id) ?? { executions: 0, timestamp: 0 };
|
|
407
|
+
if (now - rateLimitData.timestamp >= this.rateLimit.interval) {
|
|
408
|
+
rateLimitData.executions = 0;
|
|
409
|
+
rateLimitData.timestamp = now;
|
|
410
|
+
}
|
|
411
|
+
if (updateExecutions) rateLimitData.executions++;
|
|
412
|
+
this.channelRateLimitData.set(channel.id, rateLimitData);
|
|
413
|
+
break;
|
|
414
|
+
case 3 /* Global */:
|
|
415
|
+
rateLimitData = this.globalRateLimitData;
|
|
416
|
+
if (now - rateLimitData.timestamp >= this.rateLimit.interval) {
|
|
417
|
+
rateLimitData.executions = 0;
|
|
418
|
+
rateLimitData.timestamp = now;
|
|
419
|
+
}
|
|
420
|
+
if (updateExecutions) rateLimitData.executions++;
|
|
421
|
+
this.globalRateLimitData = rateLimitData;
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
return rateLimitData.executions >= this.rateLimit.max;
|
|
425
|
+
}
|
|
426
|
+
checkPermissions(client, user, command) {
|
|
427
|
+
if (!this.permissions) return { validated: true };
|
|
428
|
+
return validateCommandPermissions(this.permissions, client, user, command);
|
|
429
|
+
}
|
|
430
|
+
async checkConditions(...args) {
|
|
431
|
+
if (!this.conditions?.length) return true;
|
|
432
|
+
const results = await Promise.all(this.conditions.map((condition) => condition(...args)));
|
|
433
|
+
return results.every(Boolean);
|
|
434
|
+
}
|
|
435
|
+
async _runPreflight(clientConfig, command, ...args) {
|
|
436
|
+
try {
|
|
437
|
+
if (!this.enabled) {
|
|
438
|
+
await clientConfig.onUsedWhenDisabled?.(...args);
|
|
439
|
+
await this.onUsedWhenDisabled?.(...args);
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
if (this.isRateLimited(args[1]?.member || args[1]?.author, args[1].guild, args[1].channel)) {
|
|
443
|
+
await clientConfig.onRateLimit?.(...args);
|
|
444
|
+
await this.rateLimit?.onRateLimit?.(...args);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const permissionResults = this.checkPermissions(
|
|
448
|
+
args[0],
|
|
449
|
+
args[1]?.member || args[1]?.author || args[1]?.user,
|
|
450
|
+
command
|
|
451
|
+
);
|
|
452
|
+
if (!permissionResults.validated) {
|
|
453
|
+
await clientConfig.onMissingPermissions?.(permissionResults, ...args);
|
|
454
|
+
await this.onMissingPermissions?.(permissionResults, ...args);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
if (!await this.checkConditions(...args)) {
|
|
458
|
+
await clientConfig.onConditionsNotMet?.(...args);
|
|
459
|
+
await this.onConditionsNotMet?.(...args);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
} catch (err) {
|
|
463
|
+
if (this.onError) {
|
|
464
|
+
return this.onError(err, ...args);
|
|
465
|
+
} else if (clientConfig.onError) {
|
|
466
|
+
return clientConfig.onError(err, ...args);
|
|
467
|
+
} else {
|
|
468
|
+
throw err;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
async _runCabinCheck(clientConfig, ...args) {
|
|
473
|
+
try {
|
|
474
|
+
await clientConfig.beforeExecute?.(...args);
|
|
475
|
+
await this.beforeExecute?.(...args);
|
|
476
|
+
} catch (err) {
|
|
477
|
+
if (this.onError) {
|
|
478
|
+
return this.onError(err, ...args);
|
|
479
|
+
} else if (clientConfig.onError) {
|
|
480
|
+
return clientConfig.onError(err, ...args);
|
|
481
|
+
} else {
|
|
482
|
+
throw err;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
async _runFlyAndLand(clientConfig, ...args) {
|
|
487
|
+
try {
|
|
488
|
+
const result = await this.execute?.(...args);
|
|
489
|
+
await clientConfig?.afterExecute?.(result, ...args);
|
|
490
|
+
await this.afterExecute?.(result, ...args);
|
|
491
|
+
} catch (err) {
|
|
492
|
+
if (this.onError) {
|
|
493
|
+
return this.onError(err, ...args);
|
|
494
|
+
} else if (clientConfig.onError) {
|
|
495
|
+
return clientConfig.onError(err, ...args);
|
|
496
|
+
} else {
|
|
497
|
+
throw err;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
// src/builders/contextCommand.builder.ts
|
|
504
|
+
var import_discord2 = require("discord.js");
|
|
505
|
+
var import_lodash2 = __toESM(require("lodash"));
|
|
506
|
+
var ContextCommandBuilder = class extends BaseCommandBuilder {
|
|
507
|
+
builder;
|
|
508
|
+
deferReply;
|
|
509
|
+
deployment;
|
|
510
|
+
constructor(config) {
|
|
511
|
+
super(2 /* Context */, config);
|
|
512
|
+
this.setBuilder(config.builder);
|
|
513
|
+
this.deferReply = config?.deferReply;
|
|
514
|
+
this.deployment = config?.deployment;
|
|
515
|
+
this.validateConfig();
|
|
516
|
+
}
|
|
517
|
+
validateBuilder() {
|
|
518
|
+
if (!this.builder.name) {
|
|
519
|
+
throw new Error("VContextCommandBuilder: Command name is required");
|
|
520
|
+
}
|
|
521
|
+
try {
|
|
522
|
+
this.builder.toJSON();
|
|
523
|
+
} catch (err) {
|
|
524
|
+
throw new Error("VContextCommandBuilder: Invalid command builder", { cause: err });
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
validateConfig() {
|
|
528
|
+
}
|
|
529
|
+
toConfig() {
|
|
530
|
+
return {
|
|
531
|
+
...super.toConfig(),
|
|
532
|
+
builder: this.builder,
|
|
533
|
+
deferReply: this.deferReply,
|
|
534
|
+
deployment: this.deployment
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
setBuilder(builder) {
|
|
538
|
+
if (typeof builder === "function") {
|
|
539
|
+
this.builder = builder(new import_discord2.ContextMenuCommandBuilder());
|
|
540
|
+
} else {
|
|
541
|
+
this.builder = builder;
|
|
542
|
+
}
|
|
543
|
+
this.validateBuilder();
|
|
544
|
+
return this;
|
|
545
|
+
}
|
|
546
|
+
setDeferReply(defer) {
|
|
547
|
+
this.deferReply = defer;
|
|
548
|
+
return this;
|
|
549
|
+
}
|
|
550
|
+
setDeployment(deployment) {
|
|
551
|
+
this.deployment = import_lodash2.default.merge(this.deployment, deployment);
|
|
552
|
+
return this;
|
|
553
|
+
}
|
|
554
|
+
async executeCommand(client, interaction) {
|
|
555
|
+
try {
|
|
556
|
+
await this._runPreflight(client.config.contextCommands, interaction, client, interaction);
|
|
557
|
+
await this._runCabinCheck(client.config.contextCommands, client, interaction);
|
|
558
|
+
if (this.deferReply && !interaction.replied && !interaction.deferred) {
|
|
559
|
+
await interaction.deferReply(typeof this.deferReply === "object" ? this.deferReply : void 0);
|
|
560
|
+
}
|
|
561
|
+
return this._runFlyAndLand(client.config.contextCommands, client, interaction);
|
|
562
|
+
} catch (err) {
|
|
563
|
+
if (this.onError) {
|
|
564
|
+
return this.onError(err, client, interaction);
|
|
565
|
+
} else if (client.config.contextCommands.onError) {
|
|
566
|
+
return client.config.contextCommands.onError(err, client, interaction);
|
|
567
|
+
} else {
|
|
568
|
+
throw err;
|
|
569
|
+
}
|
|
570
|
+
} finally {
|
|
571
|
+
if (client.config.contextCommands.logExecution) {
|
|
572
|
+
client.logger.commandExecuted(this.builder.name, interaction.user.username, interaction.guild?.name);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
// src/utils/dir.ts
|
|
579
|
+
var import_jstools = __toESM(require("jstools"));
|
|
580
|
+
var import_node_path = __toESM(require("path"));
|
|
581
|
+
function getProcessDir() {
|
|
582
|
+
const mainPath = process.argv[1];
|
|
583
|
+
if (!mainPath) return "";
|
|
584
|
+
return import_node_path.default.dirname(mainPath);
|
|
585
|
+
}
|
|
586
|
+
async function importModulesFromDir(dir, fnPrefix) {
|
|
587
|
+
const cwd = getProcessDir();
|
|
588
|
+
const MODULE_RELATIVE_PATH = import_node_path.default.join(cwd, dir);
|
|
589
|
+
const MODULE_LOG_PATH = dir;
|
|
590
|
+
const files = import_jstools.default.readDir(MODULE_RELATIVE_PATH, { recursive: true }).filter(
|
|
591
|
+
(fn) => fn.endsWith(`${fnPrefix ? `.${fnPrefix}` : ""}.js`) || fn.endsWith(`${fnPrefix ? `.${fnPrefix}` : ""}.ts`)
|
|
592
|
+
);
|
|
593
|
+
if (!files.length) {
|
|
594
|
+
return [];
|
|
595
|
+
}
|
|
596
|
+
const modules = await Promise.all(
|
|
597
|
+
files.map(async (fn) => {
|
|
598
|
+
let _path = import_node_path.default.join(MODULE_RELATIVE_PATH, fn);
|
|
599
|
+
let _logPath = `./${import_node_path.default.join(MODULE_LOG_PATH, fn)}`;
|
|
600
|
+
let _module;
|
|
601
|
+
try {
|
|
602
|
+
delete require.cache[require.resolve(_path)];
|
|
603
|
+
_module = require(_path);
|
|
604
|
+
} catch (err) {
|
|
605
|
+
console.warn(`Failed to import module at '${_logPath}'`, err);
|
|
606
|
+
_module = null;
|
|
607
|
+
}
|
|
608
|
+
return { module: _module, path: _logPath };
|
|
609
|
+
})
|
|
610
|
+
);
|
|
611
|
+
const filteredModules = modules.filter((m) => m.module);
|
|
612
|
+
if (!filteredModules.length) {
|
|
613
|
+
console.warn(`No valid modules were found in directory '${dir}'`);
|
|
614
|
+
}
|
|
615
|
+
return filteredModules;
|
|
616
|
+
}
|
|
617
|
+
function getCallerFileName() {
|
|
618
|
+
const stack = new Error().stack?.split("\n");
|
|
619
|
+
return stack?.at(4)?.split("at file")?.at(1)?.split("/").at(-1)?.split(":").at(0)?.split(".").at(0);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// src/builders/event.builder.ts
|
|
623
|
+
var import_node_crypto2 = require("crypto");
|
|
624
|
+
var import_lodash3 = __toESM(require("lodash"));
|
|
625
|
+
var EventBuilder = class _EventBuilder {
|
|
626
|
+
uuid = (0, import_node_crypto2.randomUUID)();
|
|
627
|
+
event;
|
|
628
|
+
name = getCallerFileName() || this.uuid;
|
|
629
|
+
enabled;
|
|
630
|
+
once;
|
|
631
|
+
priority;
|
|
632
|
+
conditions;
|
|
633
|
+
metadata;
|
|
634
|
+
deployment;
|
|
635
|
+
rateLimit;
|
|
636
|
+
beforeExecute;
|
|
637
|
+
execute;
|
|
638
|
+
afterExecute;
|
|
639
|
+
onError;
|
|
640
|
+
rateLimitData = { executions: 0, timestamp: 0 };
|
|
641
|
+
static create(event, name) {
|
|
642
|
+
return new _EventBuilder({ event, name });
|
|
643
|
+
}
|
|
644
|
+
constructor(config) {
|
|
645
|
+
this.event = config.event;
|
|
646
|
+
this.name = config.name || this.name;
|
|
647
|
+
this.enabled = config.enabled ?? true;
|
|
648
|
+
this.once = config.once ?? false;
|
|
649
|
+
this.priority = config.priority ?? 0;
|
|
650
|
+
this.conditions = config.conditions;
|
|
651
|
+
this.metadata = config.metadata;
|
|
652
|
+
this.deployment = config.deployment;
|
|
653
|
+
this.rateLimit = config.rateLimit;
|
|
654
|
+
this.beforeExecute = config.beforeExecute;
|
|
655
|
+
this.execute = config.execute;
|
|
656
|
+
this.afterExecute = config.afterExecute;
|
|
657
|
+
this.onError = config.onError;
|
|
658
|
+
this.validate();
|
|
659
|
+
}
|
|
660
|
+
validate() {
|
|
661
|
+
if (!this.event) {
|
|
662
|
+
throw new Error("Event name is required");
|
|
663
|
+
}
|
|
664
|
+
if (this.priority !== void 0 && this.priority < 0) {
|
|
665
|
+
throw new Error("Priority must be non-negative");
|
|
666
|
+
}
|
|
667
|
+
if (this.rateLimit) {
|
|
668
|
+
if (this.rateLimit.max <= 0) {
|
|
669
|
+
throw new Error("Rate limit max must be greater than 0");
|
|
670
|
+
}
|
|
671
|
+
if (this.rateLimit.interval <= 0) {
|
|
672
|
+
throw new Error("Rate limit interval must be greater than 0");
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
if (!this.execute) {
|
|
676
|
+
throw new Error("Execute function is required");
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
clone() {
|
|
680
|
+
return new _EventBuilder(this.toConfig());
|
|
681
|
+
}
|
|
682
|
+
toConfig() {
|
|
683
|
+
return {
|
|
684
|
+
event: this.event,
|
|
685
|
+
name: this.name,
|
|
686
|
+
enabled: this.enabled,
|
|
687
|
+
once: this.once,
|
|
688
|
+
priority: this.priority,
|
|
689
|
+
conditions: this.conditions,
|
|
690
|
+
metadata: this.metadata,
|
|
691
|
+
deployment: this.deployment,
|
|
692
|
+
rateLimit: this.rateLimit,
|
|
693
|
+
beforeExecute: this.beforeExecute,
|
|
694
|
+
execute: this.execute,
|
|
695
|
+
afterExecute: this.afterExecute,
|
|
696
|
+
onError: this.onError
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
setEvent(event) {
|
|
700
|
+
this.event = event;
|
|
701
|
+
return this;
|
|
702
|
+
}
|
|
703
|
+
setName(name) {
|
|
704
|
+
this.name = name;
|
|
705
|
+
return this;
|
|
706
|
+
}
|
|
707
|
+
setEnabled(enabled) {
|
|
708
|
+
this.enabled = enabled;
|
|
709
|
+
return this;
|
|
710
|
+
}
|
|
711
|
+
enable() {
|
|
712
|
+
return this.setEnabled(true);
|
|
713
|
+
}
|
|
714
|
+
disable() {
|
|
715
|
+
return this.setEnabled(false);
|
|
716
|
+
}
|
|
717
|
+
setOnce(once = true) {
|
|
718
|
+
this.once = once;
|
|
719
|
+
return this;
|
|
720
|
+
}
|
|
721
|
+
setPriority(priority) {
|
|
722
|
+
this.priority = priority;
|
|
723
|
+
return this;
|
|
724
|
+
}
|
|
725
|
+
addCondition(condition) {
|
|
726
|
+
if (!this.conditions) this.conditions = [];
|
|
727
|
+
this.conditions.push(condition);
|
|
728
|
+
return this;
|
|
729
|
+
}
|
|
730
|
+
setConditions(conditions) {
|
|
731
|
+
this.conditions = conditions;
|
|
732
|
+
return this;
|
|
733
|
+
}
|
|
734
|
+
setMetadata(metadata) {
|
|
735
|
+
this.metadata = import_lodash3.default.merge(this.metadata, metadata);
|
|
736
|
+
return this;
|
|
737
|
+
}
|
|
738
|
+
setDeployment(deployment) {
|
|
739
|
+
this.deployment = import_lodash3.default.merge(this.deployment, deployment);
|
|
740
|
+
return this;
|
|
741
|
+
}
|
|
742
|
+
setRateLimit(options) {
|
|
743
|
+
this.rateLimit = options;
|
|
744
|
+
return this;
|
|
745
|
+
}
|
|
746
|
+
setBeforeExecute(beforeExecute) {
|
|
747
|
+
this.beforeExecute = beforeExecute;
|
|
748
|
+
return this;
|
|
749
|
+
}
|
|
750
|
+
setExecute(execute) {
|
|
751
|
+
this.execute = execute;
|
|
752
|
+
return this;
|
|
753
|
+
}
|
|
754
|
+
setAfterExecute(afterExecute) {
|
|
755
|
+
this.afterExecute = afterExecute;
|
|
756
|
+
return this;
|
|
757
|
+
}
|
|
758
|
+
setOnError(onError) {
|
|
759
|
+
this.onError = onError;
|
|
760
|
+
return this;
|
|
761
|
+
}
|
|
762
|
+
getRateLimitInfo() {
|
|
763
|
+
if (!this.rateLimit) return null;
|
|
764
|
+
return { ...this.rateLimitData, isLimited: this.isRateLimited(false) };
|
|
765
|
+
}
|
|
766
|
+
resetRateLimit() {
|
|
767
|
+
this.rateLimitData = { executions: 0, timestamp: 0 };
|
|
768
|
+
return this;
|
|
769
|
+
}
|
|
770
|
+
isRateLimited(updateExecutions = true) {
|
|
771
|
+
if (!this.rateLimit) return false;
|
|
772
|
+
const now = Date.now();
|
|
773
|
+
if (now - this.rateLimitData.timestamp >= this.rateLimit.interval) {
|
|
774
|
+
this.rateLimitData.executions = 0;
|
|
775
|
+
this.rateLimitData.timestamp = now;
|
|
776
|
+
}
|
|
777
|
+
if (updateExecutions) {
|
|
778
|
+
this.rateLimitData.executions++;
|
|
779
|
+
}
|
|
780
|
+
return this.rateLimitData.executions >= this.rateLimit.max;
|
|
781
|
+
}
|
|
782
|
+
async checkConditions(...args) {
|
|
783
|
+
if (!this.conditions?.length) return true;
|
|
784
|
+
const results = await Promise.all(this.conditions.map((condition) => condition(...args)));
|
|
785
|
+
return results.every(Boolean);
|
|
786
|
+
}
|
|
787
|
+
async executeEvent(...args) {
|
|
788
|
+
try {
|
|
789
|
+
if (!this.enabled) {
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
if (this.isRateLimited()) {
|
|
793
|
+
if (this.rateLimit?.onRateLimit) {
|
|
794
|
+
return await this.rateLimit.onRateLimit(...args);
|
|
795
|
+
}
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
if (!await this.checkConditions(...args)) {
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
if (this.beforeExecute) {
|
|
802
|
+
await this.beforeExecute(...args);
|
|
803
|
+
}
|
|
804
|
+
const result = await this.execute?.(...args);
|
|
805
|
+
if (this.afterExecute) {
|
|
806
|
+
await this.afterExecute(result, ...args);
|
|
807
|
+
}
|
|
808
|
+
return result;
|
|
809
|
+
} catch (err) {
|
|
810
|
+
if (this.onError) {
|
|
811
|
+
return await this.onError(err, ...args);
|
|
812
|
+
}
|
|
813
|
+
console.error(`Error in event '${this.name}':`, err);
|
|
814
|
+
throw err;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
// src/builders/prefixCommand.builder.ts
|
|
820
|
+
var PrefixCommandBuilder = class extends BaseCommandBuilder {
|
|
821
|
+
name;
|
|
822
|
+
aliases;
|
|
823
|
+
description;
|
|
824
|
+
constructor(config) {
|
|
825
|
+
super(1 /* Prefix */, config);
|
|
826
|
+
this.name = config.name;
|
|
827
|
+
this.description = config.description;
|
|
828
|
+
this.validateConfig();
|
|
829
|
+
}
|
|
830
|
+
validateConfig() {
|
|
831
|
+
}
|
|
832
|
+
toConfig() {
|
|
833
|
+
return {
|
|
834
|
+
...super.toConfig(),
|
|
835
|
+
name: this.name,
|
|
836
|
+
description: this.description
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
async executeCommand(client, message) {
|
|
840
|
+
try {
|
|
841
|
+
await this._runPreflight(client.config.prefixCommands, this.name, client, message);
|
|
842
|
+
await this._runCabinCheck(client.config.prefixCommands, client, message);
|
|
843
|
+
return this._runFlyAndLand(client.config.prefixCommands, client, message);
|
|
844
|
+
} catch (err) {
|
|
845
|
+
this.onError?.(err, client, message);
|
|
846
|
+
client.config.prefixCommands.onError?.(err, client, message);
|
|
847
|
+
throw err;
|
|
848
|
+
} finally {
|
|
849
|
+
if (client.config.prefixCommands.logExecution) {
|
|
850
|
+
client.logger.commandExecuted(this.name, message.author.username, message.guild?.name);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
|
|
856
|
+
// src/builders/slashCommand.builder.ts
|
|
857
|
+
var import_discord3 = require("discord.js");
|
|
858
|
+
var import_lodash4 = __toESM(require("lodash"));
|
|
859
|
+
var SlashCommandBuilder = class extends BaseCommandBuilder {
|
|
860
|
+
builder;
|
|
861
|
+
deferReply;
|
|
862
|
+
deployment;
|
|
863
|
+
routes = /* @__PURE__ */ new Map();
|
|
864
|
+
onUnknownRouteHandler;
|
|
865
|
+
constructor(config) {
|
|
866
|
+
super(0 /* Slash */, config);
|
|
867
|
+
this.setBuilder(config.builder);
|
|
868
|
+
this.setRoutes(...config.routes ?? []);
|
|
869
|
+
this.deferReply = config?.deferReply;
|
|
870
|
+
this.deployment = config?.deployment;
|
|
871
|
+
this.validateConfig();
|
|
872
|
+
}
|
|
873
|
+
validateBuilder() {
|
|
874
|
+
if (!this.builder.name) {
|
|
875
|
+
throw new Error("VSlashCommandBuilder: Command name is required");
|
|
876
|
+
}
|
|
877
|
+
if (!this.builder.description) {
|
|
878
|
+
throw new Error("VSlashCommandBuilder: Command description is required");
|
|
879
|
+
}
|
|
880
|
+
try {
|
|
881
|
+
this.builder.toJSON();
|
|
882
|
+
} catch (err) {
|
|
883
|
+
throw new Error("VSlashCommandBuilder: Invalid command builder", { cause: err });
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
validateConfig() {
|
|
887
|
+
}
|
|
888
|
+
toConfig() {
|
|
889
|
+
return {
|
|
890
|
+
...super.toConfig(),
|
|
891
|
+
builder: this.builder,
|
|
892
|
+
deferReply: this.deferReply,
|
|
893
|
+
deployment: this.deployment,
|
|
894
|
+
routes: this.routes.size ? Array.from(this.routes.entries()).map(([k, v]) => ({ name: k, handler: v })) : void 0,
|
|
895
|
+
onUnknownRouteHandler: this.onUnknownRouteHandler
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
setBuilder(builder) {
|
|
899
|
+
if (typeof builder === "function") {
|
|
900
|
+
this.builder = builder(new import_discord3.SlashCommandBuilder());
|
|
901
|
+
} else {
|
|
902
|
+
this.builder = builder;
|
|
903
|
+
}
|
|
904
|
+
this.validateBuilder();
|
|
905
|
+
return this;
|
|
906
|
+
}
|
|
907
|
+
setDeferReply(defer) {
|
|
908
|
+
this.deferReply = defer;
|
|
909
|
+
return this;
|
|
910
|
+
}
|
|
911
|
+
setDeployment(deployment) {
|
|
912
|
+
this.deployment = import_lodash4.default.merge(this.deployment, deployment);
|
|
913
|
+
return this;
|
|
914
|
+
}
|
|
915
|
+
setRoutes(...routes) {
|
|
916
|
+
if (routes.length) {
|
|
917
|
+
for (const route of routes) {
|
|
918
|
+
this.routes.set(route.name.toLowerCase(), route.handler);
|
|
919
|
+
}
|
|
920
|
+
} else {
|
|
921
|
+
this.routes = /* @__PURE__ */ new Map();
|
|
922
|
+
}
|
|
923
|
+
return this;
|
|
924
|
+
}
|
|
925
|
+
addRoutes(...routes) {
|
|
926
|
+
for (const route of routes) {
|
|
927
|
+
this.routes.set(route.name.toLowerCase(), route.handler);
|
|
928
|
+
}
|
|
929
|
+
return this;
|
|
930
|
+
}
|
|
931
|
+
setUnknownRouteHandler(handler) {
|
|
932
|
+
this.onUnknownRouteHandler = handler;
|
|
933
|
+
return this;
|
|
934
|
+
}
|
|
935
|
+
async executeCommand(client, interaction) {
|
|
936
|
+
try {
|
|
937
|
+
await this._runPreflight(client.config.slashCommands, interaction, client, interaction);
|
|
938
|
+
await this._runCabinCheck(client.config.slashCommands, client, interaction);
|
|
939
|
+
if (this.deferReply && !interaction.replied && !interaction.deferred) {
|
|
940
|
+
await interaction.deferReply(typeof this.deferReply === "object" ? this.deferReply : void 0);
|
|
941
|
+
}
|
|
942
|
+
if (this.routes.size) {
|
|
943
|
+
const subCommand = interaction.options.getSubcommand();
|
|
944
|
+
const route = this.routes.get(subCommand);
|
|
945
|
+
if (route) {
|
|
946
|
+
const result = await route(client, interaction);
|
|
947
|
+
await this.afterExecute?.(result, client, interaction);
|
|
948
|
+
return result;
|
|
949
|
+
} else if (this.onUnknownRouteHandler) {
|
|
950
|
+
const result = await this.onUnknownRouteHandler?.(client, interaction);
|
|
951
|
+
await this.afterExecute?.(result, client, interaction);
|
|
952
|
+
return result;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return this._runFlyAndLand(client.config.slashCommands, client, interaction);
|
|
956
|
+
} catch (err) {
|
|
957
|
+
this.onError?.(err, client, interaction);
|
|
958
|
+
client.config.slashCommands.onError?.(err, client, interaction);
|
|
959
|
+
throw err;
|
|
960
|
+
} finally {
|
|
961
|
+
if (client.config.slashCommands.logExecution) {
|
|
962
|
+
client.logger.commandExecuted(this.builder.name, interaction.user.username, interaction.guild?.name);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
// src/client.ts
|
|
969
|
+
var import_discord10 = require("discord.js");
|
|
970
|
+
var import_dotenv = __toESM(require("dotenv"));
|
|
971
|
+
|
|
972
|
+
// src/configs/tools.config.ts
|
|
973
|
+
var import_lodash5 = __toESM(require("lodash"));
|
|
974
|
+
var globalVimcordToolsConfig = {
|
|
975
|
+
devMode: false,
|
|
976
|
+
embedColor: [],
|
|
977
|
+
embedColorDev: [],
|
|
978
|
+
timeouts: {
|
|
979
|
+
pagination: 6e4,
|
|
980
|
+
prompt: 3e4,
|
|
981
|
+
modalSubmit: 6e4
|
|
982
|
+
},
|
|
983
|
+
paginator: {
|
|
984
|
+
notAParticipantMessage: "You are not allowed to use this!",
|
|
985
|
+
jumpableThreshold: 5,
|
|
986
|
+
longThreshold: 4,
|
|
987
|
+
buttons: {
|
|
988
|
+
first: { label: "\u25C0\u25C0", emoji: { name: "\u23EE\uFE0F", id: "\u23EE\uFE0F" } },
|
|
989
|
+
back: { label: "\u25C0", emoji: { name: "\u25C0\uFE0F", id: "\u25C0\uFE0F" } },
|
|
990
|
+
jump: { label: "\u{1F4C4}", emoji: { name: "\u{1F4C4}", id: "\u{1F4C4}" } },
|
|
991
|
+
next: { label: "\u25B6", emoji: { name: "\u25B6\uFE0F", id: "\u25B6\uFE0F" } },
|
|
992
|
+
last: { label: "\u25B6\u25B6", emoji: { name: "\u23ED\uFE0F", id: "\u23ED\uFE0F" } }
|
|
993
|
+
}
|
|
994
|
+
},
|
|
995
|
+
prompt: {
|
|
996
|
+
defaultTitle: "Are you sure?",
|
|
997
|
+
defaultDescription: "Make sure you know what you're doing!",
|
|
998
|
+
confirmLabel: "Confirm",
|
|
999
|
+
rejectLabel: "Cancel"
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
function defineGlobalToolsConfig(options) {
|
|
1003
|
+
Object.assign(globalVimcordToolsConfig, import_lodash5.default.merge(globalVimcordToolsConfig, options));
|
|
1004
|
+
}
|
|
1005
|
+
function createToolsConfig(options) {
|
|
1006
|
+
return import_lodash5.default.merge(globalVimcordToolsConfig, options);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// src/configs/app.config.ts
|
|
1010
|
+
var import_lodash6 = __toESM(require("lodash"));
|
|
1011
|
+
var defaultConfig = {
|
|
1012
|
+
devMode: process.argv.includes("--dev"),
|
|
1013
|
+
name: "Discord Bot",
|
|
1014
|
+
appVersion: "1.0.0",
|
|
1015
|
+
verbose: false,
|
|
1016
|
+
disableBanner: false
|
|
1017
|
+
};
|
|
1018
|
+
function createVimcordAppConfig(options = {}) {
|
|
1019
|
+
return import_lodash6.default.merge(defaultConfig, options);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// src/configs/staff.config.ts
|
|
1023
|
+
var import_lodash7 = __toESM(require("lodash"));
|
|
1024
|
+
var defaultConfig2 = {
|
|
1025
|
+
ownerId: null,
|
|
1026
|
+
superUsers: [],
|
|
1027
|
+
superUserRoles: [],
|
|
1028
|
+
bypassers: [],
|
|
1029
|
+
bypassesGuildAdmin: {
|
|
1030
|
+
allBotStaff: false,
|
|
1031
|
+
botOwner: false,
|
|
1032
|
+
superUsers: false,
|
|
1033
|
+
bypassers: false
|
|
1034
|
+
},
|
|
1035
|
+
guild: {
|
|
1036
|
+
id: null,
|
|
1037
|
+
inviteUrl: null,
|
|
1038
|
+
channels: {}
|
|
1039
|
+
}
|
|
1040
|
+
};
|
|
1041
|
+
function createVimcordStaffConfig(options = {}) {
|
|
1042
|
+
return import_lodash7.default.merge(defaultConfig2, options);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// src/configs/slashCommand.config.ts
|
|
1046
|
+
var import_lodash8 = __toESM(require("lodash"));
|
|
1047
|
+
var defaultConfig3 = {
|
|
1048
|
+
logExecution: true
|
|
1049
|
+
};
|
|
1050
|
+
function createVimcordSlashCommandConfig(options = {}) {
|
|
1051
|
+
return import_lodash8.default.merge(defaultConfig3, options);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// src/configs/prefixCommand.config.ts
|
|
1055
|
+
var import_lodash9 = __toESM(require("lodash"));
|
|
1056
|
+
var defaultConfig4 = {
|
|
1057
|
+
enabled: true,
|
|
1058
|
+
defaultPrefix: "!",
|
|
1059
|
+
allowMentionAsPrefix: true,
|
|
1060
|
+
allowCaseInsensitiveCommandNames: true,
|
|
1061
|
+
logExecution: true
|
|
1062
|
+
};
|
|
1063
|
+
function createVimcordPrefixCommandConfig(options = {}) {
|
|
1064
|
+
return import_lodash9.default.merge(defaultConfig4, options);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// src/configs/contextCommand.config.ts
|
|
1068
|
+
var import_lodash10 = __toESM(require("lodash"));
|
|
1069
|
+
var defaultConfig5 = {
|
|
1070
|
+
enabled: true,
|
|
1071
|
+
logExecution: true
|
|
1072
|
+
};
|
|
1073
|
+
function createVimcordContextCommandConfig(options = {}) {
|
|
1074
|
+
return import_lodash10.default.merge(defaultConfig5, options);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// src/tools/Logger.ts
|
|
1078
|
+
var import_chalk = __toESM(require("chalk"));
|
|
1079
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
1080
|
+
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
|
|
1081
|
+
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
|
|
1082
|
+
LogLevel2[LogLevel2["SUCCESS"] = 2] = "SUCCESS";
|
|
1083
|
+
LogLevel2[LogLevel2["WARN"] = 3] = "WARN";
|
|
1084
|
+
LogLevel2[LogLevel2["ERROR"] = 4] = "ERROR";
|
|
1085
|
+
return LogLevel2;
|
|
1086
|
+
})(LogLevel || {});
|
|
1087
|
+
var DEFAULT_COLORS = {
|
|
1088
|
+
primary: "#5865F2",
|
|
1089
|
+
success: "#57F287",
|
|
1090
|
+
warn: "#FEE75C",
|
|
1091
|
+
danger: "#ED4245",
|
|
1092
|
+
muted: "#747F8D",
|
|
1093
|
+
text: "#FFFFFF"
|
|
1094
|
+
};
|
|
1095
|
+
var Logger = class {
|
|
1096
|
+
logPrefixEmoji;
|
|
1097
|
+
logPrefix;
|
|
1098
|
+
minLevel;
|
|
1099
|
+
showTimestamp;
|
|
1100
|
+
colorScheme;
|
|
1101
|
+
constructor(options) {
|
|
1102
|
+
const { prefixEmoji = null, prefix = null, minLevel = 0 /* DEBUG */, showTimestamp = true } = options || {};
|
|
1103
|
+
this.logPrefixEmoji = prefixEmoji;
|
|
1104
|
+
this.logPrefix = prefix;
|
|
1105
|
+
this.minLevel = minLevel;
|
|
1106
|
+
this.showTimestamp = showTimestamp;
|
|
1107
|
+
this.colorScheme = {
|
|
1108
|
+
...DEFAULT_COLORS,
|
|
1109
|
+
...options?.colors
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
formatTimestamp() {
|
|
1113
|
+
if (!this.showTimestamp) return "";
|
|
1114
|
+
const now = /* @__PURE__ */ new Date();
|
|
1115
|
+
const time = now.toLocaleTimeString("en-US", {
|
|
1116
|
+
hour12: false,
|
|
1117
|
+
hour: "2-digit",
|
|
1118
|
+
minute: "2-digit",
|
|
1119
|
+
second: "2-digit"
|
|
1120
|
+
});
|
|
1121
|
+
return import_chalk.default.hex(this.colorScheme.muted)(`[${time}]`);
|
|
1122
|
+
}
|
|
1123
|
+
formatPrefix() {
|
|
1124
|
+
if (!this.logPrefix) return "";
|
|
1125
|
+
return import_chalk.default.bold.hex(this.colorScheme.primary)(
|
|
1126
|
+
`${this.logPrefixEmoji ? `${this.logPrefixEmoji} ` : ""}${this.logPrefix}`
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
shouldLog(level) {
|
|
1130
|
+
return level >= this.minLevel;
|
|
1131
|
+
}
|
|
1132
|
+
get prefixEmoji() {
|
|
1133
|
+
return this.logPrefixEmoji;
|
|
1134
|
+
}
|
|
1135
|
+
get prefix() {
|
|
1136
|
+
return this.logPrefix;
|
|
1137
|
+
}
|
|
1138
|
+
get colors() {
|
|
1139
|
+
return this.colorScheme;
|
|
1140
|
+
}
|
|
1141
|
+
extend(extras) {
|
|
1142
|
+
for (const [key, fn] of Object.entries(extras)) {
|
|
1143
|
+
if (typeof fn === "function") {
|
|
1144
|
+
this[key] = function(...args) {
|
|
1145
|
+
return fn.call(this, ...args);
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
return this;
|
|
1150
|
+
}
|
|
1151
|
+
setPrefix(prefix) {
|
|
1152
|
+
this.logPrefix = prefix;
|
|
1153
|
+
return this;
|
|
1154
|
+
}
|
|
1155
|
+
setPrefixEmoji(prefixEmoji) {
|
|
1156
|
+
this.logPrefixEmoji = prefixEmoji;
|
|
1157
|
+
return this;
|
|
1158
|
+
}
|
|
1159
|
+
setMinLevel(minLevel) {
|
|
1160
|
+
this.minLevel = minLevel;
|
|
1161
|
+
return this;
|
|
1162
|
+
}
|
|
1163
|
+
setShowTimestamp(show) {
|
|
1164
|
+
this.showTimestamp = show;
|
|
1165
|
+
return this;
|
|
1166
|
+
}
|
|
1167
|
+
setColors(colors) {
|
|
1168
|
+
this.colorScheme = {
|
|
1169
|
+
...DEFAULT_COLORS,
|
|
1170
|
+
...colors
|
|
1171
|
+
};
|
|
1172
|
+
return this;
|
|
1173
|
+
}
|
|
1174
|
+
log(message, ...args) {
|
|
1175
|
+
console.log(this.formatTimestamp(), this.formatPrefix(), message, ...args);
|
|
1176
|
+
}
|
|
1177
|
+
debug(message, ...args) {
|
|
1178
|
+
if (!this.shouldLog(0 /* DEBUG */)) return;
|
|
1179
|
+
console.log(
|
|
1180
|
+
this.formatTimestamp(),
|
|
1181
|
+
this.formatPrefix(),
|
|
1182
|
+
import_chalk.default.hex(this.colorScheme.muted)("DEBUG"),
|
|
1183
|
+
import_chalk.default.dim(message),
|
|
1184
|
+
...args
|
|
1185
|
+
);
|
|
1186
|
+
}
|
|
1187
|
+
info(message, ...args) {
|
|
1188
|
+
if (!this.shouldLog(1 /* INFO */)) return;
|
|
1189
|
+
console.log(this.formatTimestamp(), this.formatPrefix(), import_chalk.default.hex("#87CEEB")("INFO"), message, ...args);
|
|
1190
|
+
}
|
|
1191
|
+
success(message, ...args) {
|
|
1192
|
+
if (!this.shouldLog(2 /* SUCCESS */)) return;
|
|
1193
|
+
console.log(
|
|
1194
|
+
this.formatTimestamp(),
|
|
1195
|
+
this.formatPrefix(),
|
|
1196
|
+
import_chalk.default.bold.hex(this.colorScheme.success)("\u2713 SUCCESS"),
|
|
1197
|
+
import_chalk.default.hex(this.colorScheme.success)(message),
|
|
1198
|
+
...args
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
warn(message, ...args) {
|
|
1202
|
+
if (!this.shouldLog(3 /* WARN */)) return;
|
|
1203
|
+
console.warn(
|
|
1204
|
+
this.formatTimestamp(),
|
|
1205
|
+
this.formatPrefix(),
|
|
1206
|
+
import_chalk.default.bold.hex(this.colorScheme.warn)("\u26A0 WARN"),
|
|
1207
|
+
import_chalk.default.hex(this.colorScheme.warn)(message),
|
|
1208
|
+
...args
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1211
|
+
error(message, error, ...args) {
|
|
1212
|
+
if (!this.shouldLog(4 /* ERROR */)) return;
|
|
1213
|
+
console.error(
|
|
1214
|
+
this.formatTimestamp(),
|
|
1215
|
+
this.formatPrefix(),
|
|
1216
|
+
import_chalk.default.bold.hex(this.colorScheme.danger)("\u2715 ERROR"),
|
|
1217
|
+
import_chalk.default.hex(this.colorScheme.danger)(message),
|
|
1218
|
+
...args
|
|
1219
|
+
);
|
|
1220
|
+
if (error && error.stack) {
|
|
1221
|
+
console.error(import_chalk.default.dim(error.stack));
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
loader(message) {
|
|
1225
|
+
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1226
|
+
let i = 0;
|
|
1227
|
+
const interval = setInterval(() => {
|
|
1228
|
+
process.stdout.write(
|
|
1229
|
+
`\r${this.formatTimestamp()} ${this.formatPrefix()} ${import_chalk.default.hex(this.colorScheme.warn)(frames[i])} ${message}`
|
|
1230
|
+
);
|
|
1231
|
+
i = (i + 1) % frames.length;
|
|
1232
|
+
}, 100);
|
|
1233
|
+
return (newMessage) => {
|
|
1234
|
+
clearInterval(interval);
|
|
1235
|
+
process.stdout.write(
|
|
1236
|
+
`\r${this.formatTimestamp()} ${this.formatPrefix()} ${import_chalk.default.hex(this.colorScheme.success)("\u2713")} ${newMessage || message}
|
|
1237
|
+
`
|
|
1238
|
+
);
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
table(title, data) {
|
|
1242
|
+
console.log(this.formatTimestamp(), this.formatPrefix(), import_chalk.default.bold(title));
|
|
1243
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
1244
|
+
const formattedKey = import_chalk.default.hex(this.colorScheme.warn)(` ${key}`);
|
|
1245
|
+
const formattedValue = import_chalk.default.hex(this.colorScheme.muted)(value);
|
|
1246
|
+
console.log(`${formattedKey.padEnd(25)} ${formattedValue}`);
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
section(title) {
|
|
1250
|
+
const line = "\u2500".repeat(Math.max(30, title.length + 4));
|
|
1251
|
+
console.log(import_chalk.default.hex(this.colorScheme.muted)(`
|
|
1252
|
+
\u250C\u2500${line}\u2500\u2510`));
|
|
1253
|
+
console.log(
|
|
1254
|
+
import_chalk.default.hex(this.colorScheme.muted)("\u2502 ") + import_chalk.default.bold.hex(this.colorScheme.text)(title.padEnd(line.length)) + import_chalk.default.hex(this.colorScheme.muted)(" \u2502")
|
|
1255
|
+
);
|
|
1256
|
+
console.log(import_chalk.default.hex(this.colorScheme.muted)(`\u2514\u2500${line}\u2500\u2518`));
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
var logger = new Logger();
|
|
1260
|
+
|
|
1261
|
+
// src/tools/utils.ts
|
|
1262
|
+
function __zero(str) {
|
|
1263
|
+
return str?.length ? str : "0";
|
|
1264
|
+
}
|
|
1265
|
+
function isMentionOrSnowflake(str) {
|
|
1266
|
+
return str ? str.match(/<@[#&]?[\d]{6,}>/) || str.match(/\d{6,}/) ? true : false : false;
|
|
1267
|
+
}
|
|
1268
|
+
function cleanMention(str) {
|
|
1269
|
+
return str ? str.replaceAll(/[<@#&>]/g, "").trim() : void 0;
|
|
1270
|
+
}
|
|
1271
|
+
async function getMessageMention(message, content, type, index = 0, idOnly) {
|
|
1272
|
+
const args = content?.split(" ");
|
|
1273
|
+
const arg = isMentionOrSnowflake(args?.[index]) ? cleanMention(args?.[index]) : void 0;
|
|
1274
|
+
switch (type) {
|
|
1275
|
+
case "user":
|
|
1276
|
+
const userMention2 = message.mentions.users.at(index) || null;
|
|
1277
|
+
if (!userMention2 && arg) {
|
|
1278
|
+
return idOnly ? arg : await fetchUser(message.client, arg);
|
|
1279
|
+
} else {
|
|
1280
|
+
return idOnly ? userMention2?.id || null : userMention2;
|
|
1281
|
+
}
|
|
1282
|
+
case "member":
|
|
1283
|
+
if (!message.guild) return null;
|
|
1284
|
+
const member = await fetchMember(message.guild, message.mentions.users.at(index)?.id ?? arg);
|
|
1285
|
+
return idOnly ? member?.id || null : member;
|
|
1286
|
+
case "channel":
|
|
1287
|
+
const channelMention = message.mentions.channels.at(index) || null;
|
|
1288
|
+
if (!channelMention && arg) {
|
|
1289
|
+
return idOnly ? arg : message.guild ? await fetchChannel(message.guild, arg) : message.client.channels.cache.get(__zero(arg)) ?? message.client.channels.fetch(__zero(arg));
|
|
1290
|
+
} else {
|
|
1291
|
+
return idOnly ? channelMention?.id || null : channelMention;
|
|
1292
|
+
}
|
|
1293
|
+
case "role":
|
|
1294
|
+
const roleMention = message.mentions.roles.at(index) || null;
|
|
1295
|
+
if (!roleMention && arg) {
|
|
1296
|
+
return idOnly ? arg : message.guild ? await fetchRole(message.guild, arg) : null;
|
|
1297
|
+
} else {
|
|
1298
|
+
return idOnly ? roleMention?.id || null : roleMention;
|
|
1299
|
+
}
|
|
1300
|
+
default:
|
|
1301
|
+
return null;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
function getFirstMentionId(options) {
|
|
1305
|
+
let mentionId = "";
|
|
1306
|
+
if (options.message) {
|
|
1307
|
+
switch (options.type) {
|
|
1308
|
+
case "user":
|
|
1309
|
+
mentionId = options.message.mentions.users.first()?.id || "";
|
|
1310
|
+
break;
|
|
1311
|
+
case "channel":
|
|
1312
|
+
mentionId = options.message.mentions.channels.first()?.id || "";
|
|
1313
|
+
break;
|
|
1314
|
+
case "role":
|
|
1315
|
+
mentionId = options.message.mentions.roles.first()?.id || "";
|
|
1316
|
+
break;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
const firstArg = options.content?.split(" ")[0] || "";
|
|
1320
|
+
return mentionId || isMentionOrSnowflake(firstArg) ? cleanMention(firstArg) : "";
|
|
1321
|
+
}
|
|
1322
|
+
async function fetchUser(client, userId) {
|
|
1323
|
+
if (!userId) return null;
|
|
1324
|
+
return client.users.cache.get(__zero(userId)) || await client.users.fetch(__zero(userId)).catch(() => null);
|
|
1325
|
+
}
|
|
1326
|
+
async function fetchGuild(client, guildId) {
|
|
1327
|
+
if (!guildId) return null;
|
|
1328
|
+
return client.guilds.cache.get(__zero(guildId)) || await client.guilds.fetch(__zero(guildId)).catch(() => null);
|
|
1329
|
+
}
|
|
1330
|
+
async function fetchMember(guild, memberId) {
|
|
1331
|
+
if (!memberId) return null;
|
|
1332
|
+
return guild.members.cache.get(__zero(memberId)) || await guild.members.fetch(__zero(memberId)).catch(() => null);
|
|
1333
|
+
}
|
|
1334
|
+
async function fetchChannel(guild, channelId, type) {
|
|
1335
|
+
if (!channelId) return null;
|
|
1336
|
+
const channel = guild.channels.cache.get(__zero(channelId)) || await guild.channels.fetch(__zero(channelId)).catch(() => null);
|
|
1337
|
+
if (type && channel?.type !== type) return null;
|
|
1338
|
+
return channel;
|
|
1339
|
+
}
|
|
1340
|
+
async function fetchRole(guild, roleId) {
|
|
1341
|
+
if (!roleId) return null;
|
|
1342
|
+
return guild.roles.cache.get(__zero(roleId)) || await guild.roles.fetch(__zero(roleId)).catch(() => null) || null;
|
|
1343
|
+
}
|
|
1344
|
+
async function fetchMessage(channel, messageId) {
|
|
1345
|
+
if (!messageId) return null;
|
|
1346
|
+
return channel.messages.cache.get(__zero(messageId)) || await channel.messages.fetch(__zero(messageId)).catch(() => null) || null;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// src/types/status.ts
|
|
1350
|
+
var import_discord4 = require("discord.js");
|
|
1351
|
+
var import_lodash11 = __toESM(require("lodash"));
|
|
1352
|
+
var StatusType = /* @__PURE__ */ ((StatusType2) => {
|
|
1353
|
+
StatusType2["DND"] = "dnd";
|
|
1354
|
+
StatusType2["Idle"] = "idle";
|
|
1355
|
+
StatusType2["Online"] = "online";
|
|
1356
|
+
StatusType2["Invisible"] = "invisible";
|
|
1357
|
+
return StatusType2;
|
|
1358
|
+
})(StatusType || {});
|
|
1359
|
+
var defaultPresence = {
|
|
1360
|
+
production: {
|
|
1361
|
+
interval: 6e4,
|
|
1362
|
+
randomize: false,
|
|
1363
|
+
activity: [
|
|
1364
|
+
{ status: "online" /* Online */, type: import_discord4.ActivityType.Custom, name: "Need help? Use /help or !help" },
|
|
1365
|
+
{ status: "online" /* Online */, type: import_discord4.ActivityType.Custom, name: "Join our community!" },
|
|
1366
|
+
{ status: "online" /* Online */, type: import_discord4.ActivityType.Watching, name: "\u2728 $GUILD_COUNT servers" }
|
|
1367
|
+
]
|
|
1368
|
+
},
|
|
1369
|
+
development: {
|
|
1370
|
+
activity: { status: "dnd" /* DND */, type: import_discord4.ActivityType.Custom, name: "In development!" }
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
function createVimcordStatusConfig(options = {}) {
|
|
1374
|
+
return import_lodash11.default.merge(defaultPresence, options);
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
// src/utils/number.ts
|
|
1378
|
+
function formatThousands(num, sep = ",") {
|
|
1379
|
+
return `${num}`.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, sep);
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
// src/utils/random.ts
|
|
1383
|
+
function pickRandom(arr, options) {
|
|
1384
|
+
const _rnd = () => {
|
|
1385
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
1386
|
+
};
|
|
1387
|
+
let att = 0;
|
|
1388
|
+
let candidate = _rnd();
|
|
1389
|
+
if (options?.notEqualTo !== void 0 && arr.length > 1) {
|
|
1390
|
+
while (candidate === options.notEqualTo) {
|
|
1391
|
+
if (att < (options?.maxRerollAttempts ?? 100)) {
|
|
1392
|
+
throw new Error(`pickRandom reached max reroll attempts (${options?.maxRerollAttempts ?? 100})`);
|
|
1393
|
+
}
|
|
1394
|
+
candidate = _rnd();
|
|
1395
|
+
att++;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
return options?.clone ? structuredClone(candidate) : candidate;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// src/modules/status.manager.ts
|
|
1402
|
+
var import_node_cron = __toESM(require("node-cron"));
|
|
1403
|
+
var import_node_events = __toESM(require("events"));
|
|
1404
|
+
var VimcordStatusManager = class {
|
|
1405
|
+
client;
|
|
1406
|
+
logger;
|
|
1407
|
+
emitter = new import_node_events.default();
|
|
1408
|
+
lastActivity = null;
|
|
1409
|
+
lastActivityIndex = 0;
|
|
1410
|
+
task = null;
|
|
1411
|
+
constructor(client) {
|
|
1412
|
+
this.client = client;
|
|
1413
|
+
this.logger = new Logger({ prefixEmoji: "\u{1F4AC}", prefix: `StatusManager (i${this.client.index})` });
|
|
1414
|
+
this.emitter.on("changed", (activity) => {
|
|
1415
|
+
if (this.client.config.app.verbose) {
|
|
1416
|
+
this.logger.debug(`Status changed to '${activity.name}'`);
|
|
1417
|
+
}
|
|
1418
|
+
});
|
|
1419
|
+
this.emitter.on("cleared", () => {
|
|
1420
|
+
if (this.client.config.app.verbose) {
|
|
1421
|
+
this.logger.debug("Status cleared");
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1424
|
+
this.emitter.on("rotation", () => {
|
|
1425
|
+
if (this.client.config.app.verbose) {
|
|
1426
|
+
this.logger.debug("Status rotated");
|
|
1427
|
+
}
|
|
1428
|
+
});
|
|
1429
|
+
this.emitter.on("rotationStarted", () => {
|
|
1430
|
+
if (this.client.config.app.verbose) {
|
|
1431
|
+
this.logger.debug("Status rotation resumed \u25B6\uFE0F");
|
|
1432
|
+
}
|
|
1433
|
+
});
|
|
1434
|
+
this.emitter.on("rotationPaused", () => {
|
|
1435
|
+
if (this.client.config.app.verbose) {
|
|
1436
|
+
this.logger.debug("Status rotation paused \u23F8\uFE0F");
|
|
1437
|
+
}
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
clearData() {
|
|
1441
|
+
this.task?.destroy();
|
|
1442
|
+
this.task = null;
|
|
1443
|
+
this.lastActivity = null;
|
|
1444
|
+
this.lastActivityIndex = 0;
|
|
1445
|
+
return this;
|
|
1446
|
+
}
|
|
1447
|
+
async getReadyClient() {
|
|
1448
|
+
const client = await this.client.whenReady();
|
|
1449
|
+
if (!client.user) throw new Error("Cannot manage the client's activity when its user is not hydrated");
|
|
1450
|
+
return client;
|
|
1451
|
+
}
|
|
1452
|
+
async formatActivityName(name) {
|
|
1453
|
+
name = name.replace("$USER_COUNT", formatThousands(this.client.users.cache.size)).replace("$GUILD_COUNT", formatThousands(this.client.guilds.cache.size)).replace(
|
|
1454
|
+
"$INVITE",
|
|
1455
|
+
this.client.config.staff.guild.inviteUrl ? this.client.config.staff.guild.inviteUrl : "<STAFF_INVITE_URL_NOT_SET>"
|
|
1456
|
+
);
|
|
1457
|
+
if (name.includes("$STAFF_GUILD_MEMBER_COUNT")) {
|
|
1458
|
+
await fetchGuild(this.client, this.client.config.staff.guild.id).then((guild) => {
|
|
1459
|
+
if (!guild) return name = name.replace("$STAFF_GUILD_MEMBER_COUNT", "<STAFF_GUILD_NOT_FOUND>");
|
|
1460
|
+
name = name.replace("$STAFF_GUILD_MEMBER_COUNT", formatThousands(guild.members.cache.size));
|
|
1461
|
+
}).catch((err) => this.logger.error("Failed to fetch the staff guild", err));
|
|
1462
|
+
}
|
|
1463
|
+
return name;
|
|
1464
|
+
}
|
|
1465
|
+
async setActivity(activity) {
|
|
1466
|
+
const client = await this.getReadyClient();
|
|
1467
|
+
activity.name = await this.formatActivityName(activity.name);
|
|
1468
|
+
client.user.setStatus(activity.status);
|
|
1469
|
+
client.user.setActivity({ name: activity.name, type: activity.type, url: activity.streamUrl });
|
|
1470
|
+
this.emitter.emit("changed", activity);
|
|
1471
|
+
}
|
|
1472
|
+
async statusRotationTask(clientStatus) {
|
|
1473
|
+
let activity;
|
|
1474
|
+
if (clientStatus.randomize) {
|
|
1475
|
+
activity = pickRandom(clientStatus.activity, {
|
|
1476
|
+
notEqualTo: this.lastActivity,
|
|
1477
|
+
clone: true
|
|
1478
|
+
});
|
|
1479
|
+
this.lastActivity = activity;
|
|
1480
|
+
} else {
|
|
1481
|
+
const activityIndex = (this.lastActivityIndex + 1) % clientStatus.activity.length;
|
|
1482
|
+
this.lastActivityIndex = activityIndex;
|
|
1483
|
+
activity = clientStatus.activity[activityIndex];
|
|
1484
|
+
}
|
|
1485
|
+
await this.setActivity(activity);
|
|
1486
|
+
this.emitter.emit("rotation", activity);
|
|
1487
|
+
}
|
|
1488
|
+
async scheduleStatusRotation(clientStatus) {
|
|
1489
|
+
if (!clientStatus.interval) throw new Error("Cannot create client activity interval without interval time");
|
|
1490
|
+
this.task?.destroy();
|
|
1491
|
+
this.task = null;
|
|
1492
|
+
await this.statusRotationTask(clientStatus);
|
|
1493
|
+
this.task = import_node_cron.default.createTask(
|
|
1494
|
+
`*/${clientStatus.interval} * * * * *`,
|
|
1495
|
+
async () => await this.statusRotationTask(clientStatus),
|
|
1496
|
+
{ noOverlap: true }
|
|
1497
|
+
);
|
|
1498
|
+
this.start();
|
|
1499
|
+
this.emitter.emit("rotationStarted", this.task);
|
|
1500
|
+
}
|
|
1501
|
+
start() {
|
|
1502
|
+
if (this.task) {
|
|
1503
|
+
this.task.start();
|
|
1504
|
+
this.emitter.emit("rotationStarted", this.task);
|
|
1505
|
+
if (this.client.config.app.verbose) {
|
|
1506
|
+
this.logger.debug("Status rotation started");
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
return this;
|
|
1510
|
+
}
|
|
1511
|
+
pause() {
|
|
1512
|
+
if (this.task) {
|
|
1513
|
+
this.task.stop();
|
|
1514
|
+
this.emitter.emit("rotationPaused", this.task);
|
|
1515
|
+
if (this.client.config.app.verbose) {
|
|
1516
|
+
this.logger.debug("Status rotation paused");
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
return this;
|
|
1520
|
+
}
|
|
1521
|
+
async set(status) {
|
|
1522
|
+
const statusConfig = createVimcordStatusConfig(status);
|
|
1523
|
+
let clientStatus;
|
|
1524
|
+
if (this.client.config.app.devMode) {
|
|
1525
|
+
clientStatus = statusConfig.development;
|
|
1526
|
+
} else {
|
|
1527
|
+
clientStatus = statusConfig.production;
|
|
1528
|
+
}
|
|
1529
|
+
if (!clientStatus.interval) {
|
|
1530
|
+
await this.setActivity(Array.isArray(clientStatus.activity) ? clientStatus.activity[0] : clientStatus.activity);
|
|
1531
|
+
return this;
|
|
1532
|
+
}
|
|
1533
|
+
if (clientStatus.interval) {
|
|
1534
|
+
await this.scheduleStatusRotation(clientStatus);
|
|
1535
|
+
}
|
|
1536
|
+
return this;
|
|
1537
|
+
}
|
|
1538
|
+
async destroy() {
|
|
1539
|
+
if (this.task) {
|
|
1540
|
+
this.task.destroy();
|
|
1541
|
+
this.task = null;
|
|
1542
|
+
this.emitter.emit("rotationDestroyed");
|
|
1543
|
+
if (this.client.config.app.verbose) {
|
|
1544
|
+
this.logger.debug("Status rotation destroyed");
|
|
1545
|
+
}
|
|
1546
|
+
await this.clear();
|
|
1547
|
+
}
|
|
1548
|
+
return this;
|
|
1549
|
+
}
|
|
1550
|
+
async clear() {
|
|
1551
|
+
const client = await this.getReadyClient();
|
|
1552
|
+
this.clearData();
|
|
1553
|
+
client.user.setActivity({ name: "" });
|
|
1554
|
+
this.emitter.emit("cleared");
|
|
1555
|
+
if (this.client.config.app.verbose) {
|
|
1556
|
+
this.logger.debug("Status cleared");
|
|
1557
|
+
}
|
|
1558
|
+
return this;
|
|
1559
|
+
}
|
|
1560
|
+
};
|
|
1561
|
+
|
|
1562
|
+
// src/modules/command.manager.ts
|
|
1563
|
+
var import_discord5 = require("discord.js");
|
|
1564
|
+
var VimcordCommandManager = class {
|
|
1565
|
+
slash;
|
|
1566
|
+
prefix;
|
|
1567
|
+
context;
|
|
1568
|
+
constructor(client) {
|
|
1569
|
+
this.slash = new VimcordSlashCommandManager(client);
|
|
1570
|
+
this.prefix = new VimcordPrefixCommandManager(client);
|
|
1571
|
+
this.context = new VimcordContextCommandManager(client);
|
|
1572
|
+
}
|
|
1573
|
+
};
|
|
1574
|
+
var VimcordSlashCommandManager = class {
|
|
1575
|
+
constructor(client) {
|
|
1576
|
+
this.client = client;
|
|
1577
|
+
client.whenReady().then((c) => this.rest = new import_discord5.REST().setToken(c.token));
|
|
1578
|
+
}
|
|
1579
|
+
commands = /* @__PURE__ */ new Map();
|
|
1580
|
+
rest;
|
|
1581
|
+
get(name) {
|
|
1582
|
+
return this.commands.get(name);
|
|
1583
|
+
}
|
|
1584
|
+
getAll(options) {
|
|
1585
|
+
const matchedCommands = /* @__PURE__ */ new Map();
|
|
1586
|
+
for (const cmd of this.commands.values()) {
|
|
1587
|
+
let matched = null;
|
|
1588
|
+
if (options?.names || options?.fuzzyNames || options?.guilds) {
|
|
1589
|
+
const nameMatched = (
|
|
1590
|
+
// Exact name match
|
|
1591
|
+
options.names?.includes(cmd.builder.name) || // Fuzzy match
|
|
1592
|
+
options.fuzzyNames?.some((fuzzyCommand) => cmd.builder.name.includes(fuzzyCommand))
|
|
1593
|
+
);
|
|
1594
|
+
if ((options.names || options.fuzzyNames) && !nameMatched) continue;
|
|
1595
|
+
const guildMatched = cmd.deployment?.guilds?.some((guildId) => options.guilds?.includes(guildId));
|
|
1596
|
+
if (options.guilds && !guildMatched) continue;
|
|
1597
|
+
matched = cmd;
|
|
1598
|
+
} else {
|
|
1599
|
+
matched = cmd;
|
|
1600
|
+
}
|
|
1601
|
+
if (!matched) continue;
|
|
1602
|
+
if (options?.ignoreDeploymentOptions) {
|
|
1603
|
+
if (matchedCommands.has(matched.builder.name)) continue;
|
|
1604
|
+
matchedCommands.set(matched.builder.name, matched);
|
|
1605
|
+
continue;
|
|
1606
|
+
}
|
|
1607
|
+
const isProperEnvironment = matched?.deployment?.environments?.includes(
|
|
1608
|
+
this.client.config.app.devMode ? "development" : "production"
|
|
1609
|
+
);
|
|
1610
|
+
if ((isProperEnvironment ?? true) && ((options?.globalOnly && (matched?.deployment?.global ?? true)) ?? true)) {
|
|
1611
|
+
matchedCommands.set(matched.builder.name, matched);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
return matchedCommands;
|
|
1615
|
+
}
|
|
1616
|
+
/** Import command modules that end with `.slash` */
|
|
1617
|
+
async importFrom(dir, replaceAll) {
|
|
1618
|
+
if (replaceAll) {
|
|
1619
|
+
this.commands.clear();
|
|
1620
|
+
}
|
|
1621
|
+
dir = Array.isArray(dir) ? dir : [dir];
|
|
1622
|
+
const commandModules = await Promise.all(
|
|
1623
|
+
dir.map((dir2) => importModulesFromDir(dir2, "slash"))
|
|
1624
|
+
);
|
|
1625
|
+
let importedCommands = 0;
|
|
1626
|
+
for (const command of commandModules.flat()) {
|
|
1627
|
+
const isProperEnvironment = command.module.default.deployment?.environments?.includes(
|
|
1628
|
+
this.client.config.app.devMode ? "development" : "production"
|
|
1629
|
+
);
|
|
1630
|
+
if (isProperEnvironment ?? true) {
|
|
1631
|
+
this.commands.set(command.module.default.builder.name, command.module.default);
|
|
1632
|
+
importedCommands++;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
this.client.logger.moduleLoaded("Slash Commands", importedCommands);
|
|
1636
|
+
return this.commands;
|
|
1637
|
+
}
|
|
1638
|
+
async registerGuild(options) {
|
|
1639
|
+
const client = await this.client.whenReady();
|
|
1640
|
+
const commandsToRegister = Array.from(
|
|
1641
|
+
this.getAll({
|
|
1642
|
+
names: options?.commands,
|
|
1643
|
+
fuzzyNames: options?.fuzzyCommands
|
|
1644
|
+
}).values()
|
|
1645
|
+
).map((cmd) => cmd.builder.toJSON());
|
|
1646
|
+
if (!commandsToRegister.length) {
|
|
1647
|
+
console.log("[SlashCommandManager] No commands to register");
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
const guildIds = options?.guilds || client.guilds.cache.map((guild) => guild.id);
|
|
1651
|
+
console.log(
|
|
1652
|
+
`[SlashCommandManager] Registering ${commandsToRegister.length} app (/) ${commandsToRegister.length === 1 ? "command" : "commands"} for ${guildIds.length} ${guildIds.length === 1 ? "guild" : "guilds"}...`
|
|
1653
|
+
);
|
|
1654
|
+
await Promise.all(
|
|
1655
|
+
guildIds.map(
|
|
1656
|
+
(guildId) => this.rest.put(import_discord5.Routes.applicationGuildCommands(client.user.id, guildId), {
|
|
1657
|
+
body: commandsToRegister
|
|
1658
|
+
}).then(
|
|
1659
|
+
() => console.log(
|
|
1660
|
+
`[SlashCommandManager] \u2714 Set app (/) commands in guild: ${guildId} (${client.guilds.cache.find((g) => g.id === guildId)?.name || "n/a"})`
|
|
1661
|
+
)
|
|
1662
|
+
).catch(
|
|
1663
|
+
(err) => console.log(
|
|
1664
|
+
`[SlashCommandManager] \u2716 Failed to set app (/) commands in guild: ${guildId} (${client.guilds.cache.find((g) => g.id === guildId)?.name || "n/a"})`,
|
|
1665
|
+
err
|
|
1666
|
+
)
|
|
1667
|
+
)
|
|
1668
|
+
)
|
|
1669
|
+
);
|
|
1670
|
+
console.log(
|
|
1671
|
+
`[SlashCommandManager] \u2714 Finished registering app (/) commands for ${guildIds.length} ${guildIds.length === 1 ? "guild" : "guilds"}`
|
|
1672
|
+
);
|
|
1673
|
+
}
|
|
1674
|
+
async unregisterGuild(options) {
|
|
1675
|
+
const client = await this.client.whenReady();
|
|
1676
|
+
const guildIds = options?.guilds || client.guilds.cache.map((guild) => guild.id);
|
|
1677
|
+
console.log(
|
|
1678
|
+
`[SlashCommandManager] Unregistering app (/) commands from ${guildIds.length} ${guildIds.length === 1 ? "guild" : "guilds"}...`
|
|
1679
|
+
);
|
|
1680
|
+
await Promise.all(
|
|
1681
|
+
guildIds.map(
|
|
1682
|
+
(guildId) => this.rest.put(import_discord5.Routes.applicationGuildCommands(client.user.id, guildId), {
|
|
1683
|
+
body: []
|
|
1684
|
+
}).then(
|
|
1685
|
+
() => console.log(
|
|
1686
|
+
`[SlashCommandManager] \u2714 Removed app (/) commands in guild: ${guildId} (${client.guilds.cache.find((g) => g.id === guildId)?.name || "n/a"})`
|
|
1687
|
+
)
|
|
1688
|
+
).catch(
|
|
1689
|
+
(err) => console.log(
|
|
1690
|
+
`[SlashCommandManager] \u2716 Failed to remove app (/) commands in guild: ${guildId} (${client.guilds.cache.find((g) => g.id === guildId)?.name || "n/a"})`,
|
|
1691
|
+
err
|
|
1692
|
+
)
|
|
1693
|
+
)
|
|
1694
|
+
)
|
|
1695
|
+
);
|
|
1696
|
+
console.log(
|
|
1697
|
+
`[SlashCommandManager] \u2714 Finished unregistering app (/) commands for ${guildIds.length} ${guildIds.length === 1 ? "guild" : "guilds"}`
|
|
1698
|
+
);
|
|
1699
|
+
}
|
|
1700
|
+
async registerGlobal(options) {
|
|
1701
|
+
const client = await this.client.whenReady();
|
|
1702
|
+
const commandsToRegister = Array.from(
|
|
1703
|
+
this.getAll({
|
|
1704
|
+
names: options?.commands,
|
|
1705
|
+
fuzzyNames: options?.fuzzyCommands,
|
|
1706
|
+
globalOnly: true
|
|
1707
|
+
}).values()
|
|
1708
|
+
).map((cmd) => cmd.builder.toJSON());
|
|
1709
|
+
if (!commandsToRegister.length) {
|
|
1710
|
+
console.log("[SlashCommandManager] No commands to register");
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
console.log(
|
|
1714
|
+
`[SlashCommandManager] Registering ${commandsToRegister.length} app (/) ${commandsToRegister.length === 1 ? "command" : "commands"} globally...`
|
|
1715
|
+
);
|
|
1716
|
+
try {
|
|
1717
|
+
await this.rest.put(import_discord5.Routes.applicationCommands(client.user.id), { body: commandsToRegister });
|
|
1718
|
+
console.log("[SlashCommandManager] \u2714 Registered app (/) commands globally");
|
|
1719
|
+
} catch (err) {
|
|
1720
|
+
console.log("[SlashCommandManager] \u2716 Failed to register app (/) commands globally", err);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
async unregisterGlobal() {
|
|
1724
|
+
const client = await this.client.whenReady();
|
|
1725
|
+
console.log("[SlashCommandManager] Unregistering app (/) commands globally...");
|
|
1726
|
+
try {
|
|
1727
|
+
await this.rest.put(import_discord5.Routes.applicationCommands(client.user.id), { body: [] });
|
|
1728
|
+
console.log("[SlashCommandManager] \u2714 Removed app (/) commands globally");
|
|
1729
|
+
} catch (err) {
|
|
1730
|
+
console.log("[SlashCommandManager] \u2716 Failed to remove app (/) commands globally", err);
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
};
|
|
1734
|
+
var VimcordPrefixCommandManager = class {
|
|
1735
|
+
constructor(client) {
|
|
1736
|
+
this.client = client;
|
|
1737
|
+
}
|
|
1738
|
+
commands = /* @__PURE__ */ new Map();
|
|
1739
|
+
get(name) {
|
|
1740
|
+
if (this.client.config.prefixCommands.allowCaseInsensitiveCommandNames) {
|
|
1741
|
+
name = name.toLowerCase();
|
|
1742
|
+
return Array.from(this.commands.values()).find((cmd) => cmd.name.toLowerCase() === name);
|
|
1743
|
+
}
|
|
1744
|
+
return this.commands.get(name);
|
|
1745
|
+
}
|
|
1746
|
+
getByAlias(alias) {
|
|
1747
|
+
if (this.client.config.prefixCommands.allowCaseInsensitiveCommandNames) {
|
|
1748
|
+
alias = alias.toLowerCase();
|
|
1749
|
+
return Array.from(this.commands.values()).find((cmd) => cmd.aliases?.includes(alias));
|
|
1750
|
+
}
|
|
1751
|
+
return Array.from(this.commands.values()).find((cmd) => cmd.aliases?.includes(alias));
|
|
1752
|
+
}
|
|
1753
|
+
/** Import command modules that end with `.prefix` */
|
|
1754
|
+
async importFrom(dir, replaceAll) {
|
|
1755
|
+
if (replaceAll) {
|
|
1756
|
+
this.commands.clear();
|
|
1757
|
+
}
|
|
1758
|
+
dir = Array.isArray(dir) ? dir : [dir];
|
|
1759
|
+
const commandModules = await Promise.all(
|
|
1760
|
+
dir.map((dir2) => importModulesFromDir(dir2, "prefix"))
|
|
1761
|
+
);
|
|
1762
|
+
let importedCommands = 0;
|
|
1763
|
+
for (const command of commandModules.flat()) {
|
|
1764
|
+
this.commands.set(command.module.default.name, command.module.default);
|
|
1765
|
+
importedCommands++;
|
|
1766
|
+
}
|
|
1767
|
+
this.client.logger.moduleLoaded("Prefix Commands", importedCommands);
|
|
1768
|
+
return this.commands;
|
|
1769
|
+
}
|
|
1770
|
+
};
|
|
1771
|
+
var VimcordContextCommandManager = class {
|
|
1772
|
+
constructor(client) {
|
|
1773
|
+
this.client = client;
|
|
1774
|
+
}
|
|
1775
|
+
commands = /* @__PURE__ */ new Map();
|
|
1776
|
+
/** Import command modules that end with `.ctx` */
|
|
1777
|
+
async importFrom(dir, replaceAll) {
|
|
1778
|
+
if (replaceAll) {
|
|
1779
|
+
this.commands.clear();
|
|
1780
|
+
}
|
|
1781
|
+
dir = Array.isArray(dir) ? dir : [dir];
|
|
1782
|
+
const commandModules = await Promise.all(
|
|
1783
|
+
dir.map((dir2) => importModulesFromDir(dir2, "ctx"))
|
|
1784
|
+
);
|
|
1785
|
+
let importedCommands = 0;
|
|
1786
|
+
for (const command of commandModules.flat()) {
|
|
1787
|
+
this.commands.set(command.module.default.builder.name, command.module.default);
|
|
1788
|
+
importedCommands++;
|
|
1789
|
+
}
|
|
1790
|
+
this.client.logger.moduleLoaded("Context Commands", importedCommands);
|
|
1791
|
+
return this.commands;
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
|
|
1795
|
+
// src/modules/event.manager.ts
|
|
1796
|
+
var import_discord6 = require("discord.js");
|
|
1797
|
+
var VimcordEventManager = class {
|
|
1798
|
+
client;
|
|
1799
|
+
events = /* @__PURE__ */ new Map();
|
|
1800
|
+
logger;
|
|
1801
|
+
constructor(client) {
|
|
1802
|
+
this.client = client;
|
|
1803
|
+
this.logger = new Logger({ prefixEmoji: "\u{1F4CB}", prefix: `EventManager (i${this.client.index})` });
|
|
1804
|
+
for (const event of Object.values(import_discord6.Events)) {
|
|
1805
|
+
client.on(
|
|
1806
|
+
event.toString(),
|
|
1807
|
+
async (...args) => this.executeEvents.apply(this, [event, ...args])
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
register(...events) {
|
|
1812
|
+
for (const event of events) {
|
|
1813
|
+
this.events.set(event.name, event);
|
|
1814
|
+
if (this.client.config.app.verbose) {
|
|
1815
|
+
this.logger.debug(`'${event.name}' registered for EventType '${event.event}'`);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
unregister(...names) {
|
|
1820
|
+
for (const name of names) {
|
|
1821
|
+
const event = this.events.get(name);
|
|
1822
|
+
if (!event) continue;
|
|
1823
|
+
this.events.delete(name);
|
|
1824
|
+
if (this.client.config.app.verbose) {
|
|
1825
|
+
this.logger.debug(`'${event.name}' unregistered for EventType '${event.event}'`);
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
clear() {
|
|
1830
|
+
this.events.forEach((e) => this.unregister(e.name));
|
|
1831
|
+
this.events.clear();
|
|
1832
|
+
}
|
|
1833
|
+
get(name) {
|
|
1834
|
+
return this.events.get(name);
|
|
1835
|
+
}
|
|
1836
|
+
getByTag(tag) {
|
|
1837
|
+
return Array.from(this.events.values()).filter((event) => event.metadata?.tags?.includes(tag));
|
|
1838
|
+
}
|
|
1839
|
+
getByCategory(category) {
|
|
1840
|
+
return Array.from(this.events.values()).filter((event) => event.metadata?.category?.includes(category));
|
|
1841
|
+
}
|
|
1842
|
+
getByEvent(eventType) {
|
|
1843
|
+
return Array.from(this.events.values()).filter((event) => event.event === eventType);
|
|
1844
|
+
}
|
|
1845
|
+
async executeEvents(eventType, ...args) {
|
|
1846
|
+
const events = this.getByEvent(eventType);
|
|
1847
|
+
if (!events.length) return;
|
|
1848
|
+
const sortedEvents = events.sort((a, b) => b.priority - a.priority);
|
|
1849
|
+
await Promise.all(
|
|
1850
|
+
sortedEvents.map(async (event) => {
|
|
1851
|
+
try {
|
|
1852
|
+
await event.execute?.(this.client, ...args);
|
|
1853
|
+
if (event.once) {
|
|
1854
|
+
this.unregister(event.name);
|
|
1855
|
+
}
|
|
1856
|
+
} catch (err) {
|
|
1857
|
+
this.logger.error(`'${event.name}' failed to execute`, err);
|
|
1858
|
+
}
|
|
1859
|
+
})
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
/** Import event modules that end with `.event` */
|
|
1863
|
+
async importFrom(dir, replaceAll) {
|
|
1864
|
+
dir = Array.isArray(dir) ? dir : [dir];
|
|
1865
|
+
const eventModules = await Promise.all(
|
|
1866
|
+
dir.map((dir2) => importModulesFromDir(dir2, "event"))
|
|
1867
|
+
);
|
|
1868
|
+
if (replaceAll) {
|
|
1869
|
+
this.clear();
|
|
1870
|
+
}
|
|
1871
|
+
let importedEvents = 0;
|
|
1872
|
+
let ignoredEvents = 0;
|
|
1873
|
+
for (const event of eventModules.flat()) {
|
|
1874
|
+
if (!event.module.default.enabled) {
|
|
1875
|
+
ignoredEvents++;
|
|
1876
|
+
} else {
|
|
1877
|
+
importedEvents++;
|
|
1878
|
+
}
|
|
1879
|
+
this.register(event.module.default);
|
|
1880
|
+
}
|
|
1881
|
+
this.client.logger.moduleLoaded("Event Handlers", importedEvents, ignoredEvents);
|
|
1882
|
+
return this.events;
|
|
1883
|
+
}
|
|
1884
|
+
};
|
|
1885
|
+
|
|
1886
|
+
// src/utils/sendCommandErrorEmbed.ts
|
|
1887
|
+
var import_discord9 = require("discord.js");
|
|
1888
|
+
|
|
1889
|
+
// src/tools/BetterEmbed.ts
|
|
1890
|
+
var import_discord8 = require("discord.js");
|
|
1891
|
+
|
|
1892
|
+
// src/tools/dynaSend.ts
|
|
1893
|
+
var import_discord7 = require("discord.js");
|
|
1894
|
+
|
|
1895
|
+
// src/tools/types.ts
|
|
1896
|
+
var SendMethod = /* @__PURE__ */ ((SendMethod2) => {
|
|
1897
|
+
SendMethod2[SendMethod2["Reply"] = 0] = "Reply";
|
|
1898
|
+
SendMethod2[SendMethod2["EditReply"] = 1] = "EditReply";
|
|
1899
|
+
SendMethod2[SendMethod2["FollowUp"] = 2] = "FollowUp";
|
|
1900
|
+
SendMethod2[SendMethod2["Channel"] = 3] = "Channel";
|
|
1901
|
+
SendMethod2[SendMethod2["MessageReply"] = 4] = "MessageReply";
|
|
1902
|
+
SendMethod2[SendMethod2["MessageEdit"] = 5] = "MessageEdit";
|
|
1903
|
+
SendMethod2[SendMethod2["User"] = 6] = "User";
|
|
1904
|
+
return SendMethod2;
|
|
1905
|
+
})(SendMethod || {});
|
|
1906
|
+
|
|
1907
|
+
// src/tools/dynaSend.ts
|
|
1908
|
+
var DynaSend = class {
|
|
1909
|
+
static forceArray(value) {
|
|
1910
|
+
return Array.isArray(value) ? value : [value];
|
|
1911
|
+
}
|
|
1912
|
+
static isInteractionCallback(obj) {
|
|
1913
|
+
return obj instanceof import_discord7.InteractionCallbackResponse;
|
|
1914
|
+
}
|
|
1915
|
+
static filterFlags(flags, excludeFlags) {
|
|
1916
|
+
if (!flags) return void 0;
|
|
1917
|
+
const flagArray = this.forceArray(flags);
|
|
1918
|
+
return flagArray.filter((flag) => !excludeFlags.includes(flag));
|
|
1919
|
+
}
|
|
1920
|
+
static detectSendMethod(handler) {
|
|
1921
|
+
if (handler instanceof import_discord7.BaseInteraction) {
|
|
1922
|
+
return handler.replied || handler.deferred ? 1 /* EditReply */ : 0 /* Reply */;
|
|
1923
|
+
}
|
|
1924
|
+
if (handler instanceof import_discord7.BaseChannel) return 3 /* Channel */;
|
|
1925
|
+
if (handler instanceof import_discord7.Message) return 4 /* MessageReply */;
|
|
1926
|
+
if (handler instanceof import_discord7.GuildMember || handler instanceof import_discord7.User) return 6 /* User */;
|
|
1927
|
+
throw new Error("[DynaSend] Unable to determine send method for handler type");
|
|
1928
|
+
}
|
|
1929
|
+
static validateSendMethod(handler, method) {
|
|
1930
|
+
const interactionMethods = [0 /* Reply */, 1 /* EditReply */, 2 /* FollowUp */];
|
|
1931
|
+
if (interactionMethods.includes(method) && !(handler instanceof import_discord7.BaseInteraction)) {
|
|
1932
|
+
throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires BaseInteraction handler`);
|
|
1933
|
+
}
|
|
1934
|
+
if (method === 3 /* Channel */ && !(handler instanceof import_discord7.BaseChannel)) {
|
|
1935
|
+
throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires BaseChannel handler`);
|
|
1936
|
+
}
|
|
1937
|
+
if ([4 /* MessageReply */, 5 /* MessageEdit */].includes(method) && !(handler instanceof import_discord7.Message)) {
|
|
1938
|
+
throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires Message handler`);
|
|
1939
|
+
}
|
|
1940
|
+
if (method === 6 /* User */ && !(handler instanceof import_discord7.GuildMember || handler instanceof import_discord7.User)) {
|
|
1941
|
+
throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires User or GuildMember handler`);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
static createMessageData(options, method) {
|
|
1945
|
+
const baseData = {
|
|
1946
|
+
content: options.content,
|
|
1947
|
+
embeds: options.embeds,
|
|
1948
|
+
components: options.components,
|
|
1949
|
+
files: options.files,
|
|
1950
|
+
allowedMentions: options.allowedMentions,
|
|
1951
|
+
tts: options.tts
|
|
1952
|
+
};
|
|
1953
|
+
switch (method) {
|
|
1954
|
+
case 0 /* Reply */:
|
|
1955
|
+
return {
|
|
1956
|
+
...baseData,
|
|
1957
|
+
flags: options.flags,
|
|
1958
|
+
withResponse: options.withResponse,
|
|
1959
|
+
poll: options.poll
|
|
1960
|
+
};
|
|
1961
|
+
case 1 /* EditReply */:
|
|
1962
|
+
return {
|
|
1963
|
+
...baseData,
|
|
1964
|
+
flags: this.filterFlags(options.flags, ["Ephemeral", "SuppressNotifications"]),
|
|
1965
|
+
withResponse: options.withResponse,
|
|
1966
|
+
poll: options.poll
|
|
1967
|
+
};
|
|
1968
|
+
case 2 /* FollowUp */:
|
|
1969
|
+
return {
|
|
1970
|
+
...baseData,
|
|
1971
|
+
flags: options.flags,
|
|
1972
|
+
withResponse: options.withResponse,
|
|
1973
|
+
poll: options.poll
|
|
1974
|
+
};
|
|
1975
|
+
case 3 /* Channel */:
|
|
1976
|
+
return {
|
|
1977
|
+
...baseData,
|
|
1978
|
+
flags: this.filterFlags(options.flags, ["Ephemeral"]),
|
|
1979
|
+
poll: options.poll,
|
|
1980
|
+
stickers: options.stickers,
|
|
1981
|
+
reply: options.reply
|
|
1982
|
+
};
|
|
1983
|
+
case 4 /* MessageReply */:
|
|
1984
|
+
return {
|
|
1985
|
+
...baseData,
|
|
1986
|
+
flags: this.filterFlags(options.flags, ["Ephemeral"]),
|
|
1987
|
+
poll: options.poll,
|
|
1988
|
+
stickers: options.stickers
|
|
1989
|
+
};
|
|
1990
|
+
case 5 /* MessageEdit */:
|
|
1991
|
+
return {
|
|
1992
|
+
...baseData,
|
|
1993
|
+
flags: this.filterFlags(options.flags, ["Ephemeral", "SuppressNotifications"])
|
|
1994
|
+
};
|
|
1995
|
+
case 6 /* User */:
|
|
1996
|
+
return {
|
|
1997
|
+
...baseData,
|
|
1998
|
+
flags: this.filterFlags(options.flags, ["Ephemeral"]),
|
|
1999
|
+
poll: options.poll,
|
|
2000
|
+
forward: options.forward,
|
|
2001
|
+
stickers: options.stickers
|
|
2002
|
+
};
|
|
2003
|
+
default:
|
|
2004
|
+
return baseData;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
static async executeSend(handler, method, data) {
|
|
2008
|
+
try {
|
|
2009
|
+
switch (method) {
|
|
2010
|
+
case 0 /* Reply */: {
|
|
2011
|
+
const response = await handler.reply(data);
|
|
2012
|
+
return this.isInteractionCallback(response) ? response.resource?.message ?? null : null;
|
|
2013
|
+
}
|
|
2014
|
+
case 1 /* EditReply */:
|
|
2015
|
+
return await handler.editReply(data);
|
|
2016
|
+
case 2 /* FollowUp */:
|
|
2017
|
+
return await handler.followUp(data);
|
|
2018
|
+
case 3 /* Channel */:
|
|
2019
|
+
return await handler.send(data);
|
|
2020
|
+
case 4 /* MessageReply */:
|
|
2021
|
+
return await handler.reply(data);
|
|
2022
|
+
case 5 /* MessageEdit */: {
|
|
2023
|
+
const message = handler;
|
|
2024
|
+
if (!message.editable) {
|
|
2025
|
+
console.warn("[DynaSend] Message is not editable");
|
|
2026
|
+
return null;
|
|
2027
|
+
}
|
|
2028
|
+
return await message.edit(data);
|
|
2029
|
+
}
|
|
2030
|
+
case 6 /* User */:
|
|
2031
|
+
return await handler.send(data);
|
|
2032
|
+
default:
|
|
2033
|
+
throw new Error(`[DynaSend] Unknown send method '${method}'`);
|
|
2034
|
+
}
|
|
2035
|
+
} catch (error) {
|
|
2036
|
+
console.error(`[DynaSend] Error with method '${SendMethod[method]}':`, error);
|
|
2037
|
+
return null;
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
static scheduleDelete(message, delay) {
|
|
2041
|
+
if (delay < 1e3) {
|
|
2042
|
+
console.warn(`[DynaSend] Delete delay is less than 1 second (${delay}ms). Is this intentional?`);
|
|
2043
|
+
}
|
|
2044
|
+
setTimeout(async () => {
|
|
2045
|
+
try {
|
|
2046
|
+
if (message.deletable) {
|
|
2047
|
+
await message.delete();
|
|
2048
|
+
}
|
|
2049
|
+
} catch (error) {
|
|
2050
|
+
console.error("[DynaSend] Error deleting message:", error);
|
|
2051
|
+
}
|
|
2052
|
+
}, delay);
|
|
2053
|
+
}
|
|
2054
|
+
static async send(handler, options) {
|
|
2055
|
+
const sendMethod = options.sendMethod ?? this.detectSendMethod(handler);
|
|
2056
|
+
this.validateSendMethod(handler, sendMethod);
|
|
2057
|
+
const messageData = this.createMessageData(options, sendMethod);
|
|
2058
|
+
const message = await this.executeSend(handler, sendMethod, messageData);
|
|
2059
|
+
if (options.deleteAfter && message) {
|
|
2060
|
+
this.scheduleDelete(message, options.deleteAfter);
|
|
2061
|
+
}
|
|
2062
|
+
return message;
|
|
2063
|
+
}
|
|
2064
|
+
};
|
|
2065
|
+
async function dynaSend(handler, options) {
|
|
2066
|
+
return DynaSend.send(handler, options);
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
// src/tools/BetterEmbed.ts
|
|
2070
|
+
var BetterEmbed = class _BetterEmbed {
|
|
2071
|
+
embed = new import_discord8.EmbedBuilder();
|
|
2072
|
+
data;
|
|
2073
|
+
config;
|
|
2074
|
+
/** A powerful wrapper for `EmbedBuilder` that introduces useful features
|
|
2075
|
+
*
|
|
2076
|
+
* Auto-shorthand context formatting (_ACF_) is enabled by default
|
|
2077
|
+
*
|
|
2078
|
+
* All functions utilize _ACF_ unless `BetterEmbed.acf` is set to `false`
|
|
2079
|
+
*
|
|
2080
|
+
* ___Use a blackslash___ `\` ___to escape any context___
|
|
2081
|
+
*
|
|
2082
|
+
* \- - - Author Context - - -
|
|
2083
|
+
* - __`$USER`__: _author's mention (@xsqu1znt)_
|
|
2084
|
+
* - __`$USER_NAME`__: _author's username_
|
|
2085
|
+
* - __`$DISPLAY_NAME`__: _author's display name (requires `GuildMember` context)_
|
|
2086
|
+
* - __`$USER_AVATAR`__: _author's avatar_
|
|
2087
|
+
*
|
|
2088
|
+
* \- - - Client Context - - -
|
|
2089
|
+
*
|
|
2090
|
+
* - __`$BOT_AVATAR`__: _bot's avatar_
|
|
2091
|
+
*
|
|
2092
|
+
* \- - - Shorthand Context - - -
|
|
2093
|
+
* - __`$YEAR`__: _YYYY_
|
|
2094
|
+
* - __`$MONTH`__: _MM_
|
|
2095
|
+
* - __`$DAY`__: _DD_
|
|
2096
|
+
* - __`$year`__: _YY_
|
|
2097
|
+
* - __`$month`__: _M or MM_
|
|
2098
|
+
* - __`$day`__: _D or DD_ */
|
|
2099
|
+
constructor(data = {}) {
|
|
2100
|
+
this.config = data.config || globalVimcordToolsConfig;
|
|
2101
|
+
this.data = {
|
|
2102
|
+
context: data.context || null,
|
|
2103
|
+
author: data.author || null,
|
|
2104
|
+
title: data.title || null,
|
|
2105
|
+
thumbnailUrl: data.thumbnailUrl || null,
|
|
2106
|
+
description: data.description || null,
|
|
2107
|
+
imageUrl: data.imageUrl || null,
|
|
2108
|
+
footer: data.footer || null,
|
|
2109
|
+
fields: data.fields || [],
|
|
2110
|
+
color: data.color ?? (this.config.devMode ? this.config.embedColorDev : this.config.embedColor),
|
|
2111
|
+
timestamp: data.timestamp || null,
|
|
2112
|
+
acf: data.acf ?? true
|
|
2113
|
+
};
|
|
2114
|
+
this.build();
|
|
2115
|
+
}
|
|
2116
|
+
build() {
|
|
2117
|
+
this.normalizeData();
|
|
2118
|
+
this.applyContextFormatting();
|
|
2119
|
+
this.configureEmbed();
|
|
2120
|
+
}
|
|
2121
|
+
normalizeData() {
|
|
2122
|
+
if (typeof this.data.author === "string") {
|
|
2123
|
+
this.data.author = { text: this.data.author };
|
|
2124
|
+
}
|
|
2125
|
+
if (typeof this.data.title === "string") {
|
|
2126
|
+
this.data.title = { text: this.data.title };
|
|
2127
|
+
}
|
|
2128
|
+
if (typeof this.data.footer === "string") {
|
|
2129
|
+
this.data.footer = { text: this.data.footer };
|
|
2130
|
+
}
|
|
2131
|
+
if (this.data.timestamp === true) {
|
|
2132
|
+
this.data.timestamp = Date.now();
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
getContextUser() {
|
|
2136
|
+
const context = this.data.context;
|
|
2137
|
+
if (!context) return null;
|
|
2138
|
+
return context.user || context.interaction?.member || context.interaction?.user || context.message?.member || context.message?.author || null;
|
|
2139
|
+
}
|
|
2140
|
+
getContextClient() {
|
|
2141
|
+
const context = this.data.context;
|
|
2142
|
+
if (!context) return null;
|
|
2143
|
+
return context.client || context.interaction?.client || context.message?.client || null;
|
|
2144
|
+
}
|
|
2145
|
+
applyContextFormatting(str) {
|
|
2146
|
+
if (!this.data.acf) return;
|
|
2147
|
+
const user = this.getContextUser();
|
|
2148
|
+
const guildMember = user instanceof import_discord8.GuildMember ? user : null;
|
|
2149
|
+
const actualUser = guildMember?.user || (user instanceof import_discord8.User ? user : null);
|
|
2150
|
+
const client = this.getContextClient();
|
|
2151
|
+
const formatString = (str2) => {
|
|
2152
|
+
if (!str2 || !str2.includes("$")) return str2;
|
|
2153
|
+
return str2.replace(/(?<!\\)\$USER\b/g, actualUser?.toString() || "$USER").replace(/(?<!\\)\$USER_NAME\b/g, actualUser?.username || "$USER_NAME").replace(/(?<!\\)\$USER_AVATAR\b/g, actualUser?.avatarURL() || "$USER_AVATAR").replace(/(?<!\\)\$DISPLAY_NAME\b/g, guildMember?.displayName || "$DISPLAY_NAME").replace(/(?<!\\)\$BOT_AVATAR\b/g, client?.user?.avatarURL() || "$BOT_AVATAR").replace(/(?<!\\)\$INVIS\b/g, "\u200B").replace(/(?<!\\)\$YEAR/g, (/* @__PURE__ */ new Date()).getFullYear().toString()).replace(/(?<!\\)\$MONTH/g, String((/* @__PURE__ */ new Date()).getMonth() + 1).padStart(2, "0")).replace(/(?<!\\)\$DAY/g, String((/* @__PURE__ */ new Date()).getDate()).padStart(2, "0")).replace(/(?<!\\)\$year/g, String((/* @__PURE__ */ new Date()).getFullYear()).slice(-2)).replace(/(?<!\\)\$month/g, String((/* @__PURE__ */ new Date()).getMonth() + 1).padStart(2, "0")).replace(/(?<!\\)\$day/g, String((/* @__PURE__ */ new Date()).getDate()).padStart(2, "0")).replace(/(?<!\\|<)@([0-9]+)(?!>)/g, "<@$1>").replace(/(?<!\\|<)@&([0-9]+)(?!>)/g, "<@&$1>").replace(/(?<!\\|<)#([0-9]+)(?!>)/g, "<#$1>");
|
|
2154
|
+
};
|
|
2155
|
+
if (str) {
|
|
2156
|
+
return formatString(str);
|
|
2157
|
+
}
|
|
2158
|
+
if (this.data.author && typeof this.data.author === "object") {
|
|
2159
|
+
this.data.author.text = formatString(this.data.author.text);
|
|
2160
|
+
if (this.data.author.icon === true && actualUser) {
|
|
2161
|
+
this.data.author.icon = actualUser.avatarURL();
|
|
2162
|
+
} else if (typeof this.data.author.icon === "string") {
|
|
2163
|
+
this.data.author.icon = formatString(this.data.author.icon);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
if (this.data.title && typeof this.data.title === "object") {
|
|
2167
|
+
this.data.title.text = formatString(this.data.title.text);
|
|
2168
|
+
}
|
|
2169
|
+
if (this.data.description) {
|
|
2170
|
+
this.data.description = formatString(
|
|
2171
|
+
Array.isArray(this.data.description) ? this.data.description.join("\n") : this.data.description
|
|
2172
|
+
);
|
|
2173
|
+
}
|
|
2174
|
+
if (this.data.footer && typeof this.data.footer === "object") {
|
|
2175
|
+
this.data.footer.text = formatString(this.data.footer.text);
|
|
2176
|
+
}
|
|
2177
|
+
if (this.data.thumbnailUrl) {
|
|
2178
|
+
this.data.thumbnailUrl = formatString(this.data.thumbnailUrl);
|
|
2179
|
+
}
|
|
2180
|
+
if (this.data.imageUrl) {
|
|
2181
|
+
this.data.imageUrl = formatString(this.data.imageUrl);
|
|
2182
|
+
}
|
|
2183
|
+
this.data.fields = this.data.fields.map((field) => ({
|
|
2184
|
+
...field,
|
|
2185
|
+
name: formatString(field.name),
|
|
2186
|
+
value: formatString(field.value)
|
|
2187
|
+
}));
|
|
2188
|
+
}
|
|
2189
|
+
configureEmbed() {
|
|
2190
|
+
if (this.data.author && typeof this.data.author === "object" && this.data.author.text) {
|
|
2191
|
+
try {
|
|
2192
|
+
this.embed.setAuthor({
|
|
2193
|
+
name: this.data.author.text,
|
|
2194
|
+
iconURL: typeof this.data.author.icon === "string" ? this.data.author.icon : void 0,
|
|
2195
|
+
url: this.data.author.hyperlink || void 0
|
|
2196
|
+
});
|
|
2197
|
+
} catch (error) {
|
|
2198
|
+
console.error("[BetterEmbed] Invalid author configuration:", error);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
if (this.data.title && typeof this.data.title === "object" && this.data.title.text) {
|
|
2202
|
+
try {
|
|
2203
|
+
this.embed.setTitle(this.data.title.text);
|
|
2204
|
+
if (this.data.title.hyperlink) {
|
|
2205
|
+
this.embed.setURL(this.data.title.hyperlink);
|
|
2206
|
+
}
|
|
2207
|
+
} catch (error) {
|
|
2208
|
+
console.error("[BetterEmbed] Invalid title configuration:", error);
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
if (this.data.description) {
|
|
2212
|
+
this.embed.setDescription(
|
|
2213
|
+
Array.isArray(this.data.description) ? this.data.description.join("\n") : this.data.description
|
|
2214
|
+
);
|
|
2215
|
+
}
|
|
2216
|
+
if (this.data.thumbnailUrl) {
|
|
2217
|
+
try {
|
|
2218
|
+
this.embed.setThumbnail(this.data.thumbnailUrl);
|
|
2219
|
+
} catch (error) {
|
|
2220
|
+
console.error("[BetterEmbed] Invalid thumbnail URL:", error);
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
if (this.data.imageUrl) {
|
|
2224
|
+
try {
|
|
2225
|
+
this.embed.setImage(this.data.imageUrl);
|
|
2226
|
+
} catch (error) {
|
|
2227
|
+
console.error("[BetterEmbed] Invalid image URL:", error);
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
if (this.data.footer && typeof this.data.footer === "object" && this.data.footer.text) {
|
|
2231
|
+
try {
|
|
2232
|
+
this.embed.setFooter({
|
|
2233
|
+
text: this.data.footer.text,
|
|
2234
|
+
iconURL: typeof this.data.footer.icon === "string" ? this.data.footer.icon : void 0
|
|
2235
|
+
});
|
|
2236
|
+
} catch (error) {
|
|
2237
|
+
console.error("[BetterEmbed] Invalid footer configuration:", error);
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
if (this.data.color) {
|
|
2241
|
+
try {
|
|
2242
|
+
const color = Array.isArray(this.data.color) ? this.data.color[Math.floor(Math.random() * this.data.color.length)] ?? null : this.data.color;
|
|
2243
|
+
this.embed.setColor(color);
|
|
2244
|
+
} catch (error) {
|
|
2245
|
+
console.error("[BetterEmbed] Invalid color:", error);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
if (this.data.timestamp && this.data.timestamp !== true) {
|
|
2249
|
+
try {
|
|
2250
|
+
this.embed.setTimestamp(this.data.timestamp);
|
|
2251
|
+
} catch (error) {
|
|
2252
|
+
console.error("[BetterEmbed] Invalid timestamp:", error);
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
if (this.data.fields.length > 0) {
|
|
2256
|
+
const validFields = this.data.fields.slice(0, 25);
|
|
2257
|
+
if (this.data.fields.length > 25) {
|
|
2258
|
+
console.warn("[BetterEmbed] Only first 25 fields will be used (Discord limit)");
|
|
2259
|
+
}
|
|
2260
|
+
this.embed.setFields(validFields);
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
setAuthor(author) {
|
|
2264
|
+
this.data.author = author;
|
|
2265
|
+
this.build();
|
|
2266
|
+
return this;
|
|
2267
|
+
}
|
|
2268
|
+
setTitle(title) {
|
|
2269
|
+
this.data.title = title;
|
|
2270
|
+
this.build();
|
|
2271
|
+
return this;
|
|
2272
|
+
}
|
|
2273
|
+
setDescription(description) {
|
|
2274
|
+
this.data.description = description;
|
|
2275
|
+
this.build();
|
|
2276
|
+
return this;
|
|
2277
|
+
}
|
|
2278
|
+
setThumbnail(url) {
|
|
2279
|
+
this.data.thumbnailUrl = url;
|
|
2280
|
+
this.build();
|
|
2281
|
+
return this;
|
|
2282
|
+
}
|
|
2283
|
+
setImage(url) {
|
|
2284
|
+
this.data.imageUrl = url;
|
|
2285
|
+
this.build();
|
|
2286
|
+
return this;
|
|
2287
|
+
}
|
|
2288
|
+
setFooter(footer) {
|
|
2289
|
+
this.data.footer = footer;
|
|
2290
|
+
this.build();
|
|
2291
|
+
return this;
|
|
2292
|
+
}
|
|
2293
|
+
setColor(color) {
|
|
2294
|
+
this.data.color = color;
|
|
2295
|
+
this.build();
|
|
2296
|
+
return this;
|
|
2297
|
+
}
|
|
2298
|
+
setTimestamp(timestamp) {
|
|
2299
|
+
this.data.timestamp = timestamp;
|
|
2300
|
+
this.build();
|
|
2301
|
+
return this;
|
|
2302
|
+
}
|
|
2303
|
+
addFields(fields) {
|
|
2304
|
+
this.data.fields = [...this.data.fields, ...fields];
|
|
2305
|
+
this.build();
|
|
2306
|
+
return this;
|
|
2307
|
+
}
|
|
2308
|
+
setFields(fields) {
|
|
2309
|
+
this.data.fields = fields;
|
|
2310
|
+
this.build();
|
|
2311
|
+
return this;
|
|
2312
|
+
}
|
|
2313
|
+
spliceFields(index, deleteCount, ...fields) {
|
|
2314
|
+
this.data.fields.splice(index, deleteCount, ...fields);
|
|
2315
|
+
this.build();
|
|
2316
|
+
return this;
|
|
2317
|
+
}
|
|
2318
|
+
clone(overrides = {}) {
|
|
2319
|
+
return new _BetterEmbed({ ...this.data, ...overrides });
|
|
2320
|
+
}
|
|
2321
|
+
toJSON() {
|
|
2322
|
+
return this.embed.toJSON();
|
|
2323
|
+
}
|
|
2324
|
+
async send(handler, options = {}, overrides) {
|
|
2325
|
+
this.build();
|
|
2326
|
+
if (options.content && this.data.acf) {
|
|
2327
|
+
options.content = this.applyContextFormatting(options.content);
|
|
2328
|
+
}
|
|
2329
|
+
return await dynaSend(handler, {
|
|
2330
|
+
...options,
|
|
2331
|
+
embeds: [
|
|
2332
|
+
overrides ? this.clone(overrides) : this,
|
|
2333
|
+
...Array.isArray(options?.embeds) ? options?.embeds : options?.embeds ? [options?.embeds] : []
|
|
2334
|
+
]
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
};
|
|
2338
|
+
|
|
2339
|
+
// src/utils/sendCommandErrorEmbed.ts
|
|
2340
|
+
async function sendCommandErrorEmbed(client, error, guild, messageOrInteraction) {
|
|
2341
|
+
if (!client.features.enableCommandErrorMessage) return null;
|
|
2342
|
+
const config = typeof client.features.enableCommandErrorMessage !== "boolean" ? client.features.enableCommandErrorMessage : void 0;
|
|
2343
|
+
const buttons = {
|
|
2344
|
+
supportServer: new import_discord9.ButtonBuilder({
|
|
2345
|
+
url: config?.inviteUrl || client.config.staff.guild.inviteUrl || "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
|
2346
|
+
// may or may not be a rickroll
|
|
2347
|
+
label: config?.inviteButtonLabel || "Support Support",
|
|
2348
|
+
style: import_discord9.ButtonStyle.Link
|
|
2349
|
+
}),
|
|
2350
|
+
details: new import_discord9.ButtonBuilder({
|
|
2351
|
+
customId: "btn_details",
|
|
2352
|
+
label: config?.detailButtonLabel || "Details",
|
|
2353
|
+
style: import_discord9.ButtonStyle.Secondary
|
|
2354
|
+
})
|
|
2355
|
+
};
|
|
2356
|
+
const actionRow = new import_discord9.ActionRowBuilder({
|
|
2357
|
+
components: config?.inviteUrl && guild?.id !== (config.inviteUrl || client.config.staff.guild.id) ? [buttons.supportServer, buttons.details] : [buttons.details]
|
|
2358
|
+
});
|
|
2359
|
+
const embed_error = config?.embed?.(new BetterEmbed(), error, guild) || new BetterEmbed({
|
|
2360
|
+
color: "Red",
|
|
2361
|
+
title: "Something went wrong",
|
|
2362
|
+
description: "If you keep encountering this error, please report it"
|
|
2363
|
+
});
|
|
2364
|
+
const msg = await embed_error.send(messageOrInteraction, {
|
|
2365
|
+
components: [actionRow],
|
|
2366
|
+
flags: config?.ephemeral ? "Ephemeral" : void 0,
|
|
2367
|
+
deleteAfter: config?.deleteAfter
|
|
2368
|
+
});
|
|
2369
|
+
if (!msg) return null;
|
|
2370
|
+
const collector = msg.createMessageComponentCollector({
|
|
2371
|
+
componentType: import_discord9.ComponentType.Button,
|
|
2372
|
+
idle: config?.detailButtonIdleTimeout ?? 3e4,
|
|
2373
|
+
filter: (i) => i.customId === "btn_details"
|
|
2374
|
+
});
|
|
2375
|
+
collector.on("collect", (i) => {
|
|
2376
|
+
const attachment = new import_discord9.AttachmentBuilder(Buffer.from(`${error.message}
|
|
2377
|
+
|
|
2378
|
+
${error.stack}`), {
|
|
2379
|
+
name: "error.txt"
|
|
2380
|
+
});
|
|
2381
|
+
i.reply({ files: [attachment], flags: "Ephemeral" });
|
|
2382
|
+
});
|
|
2383
|
+
collector.on("end", () => {
|
|
2384
|
+
buttons.details.setDisabled(true);
|
|
2385
|
+
embed_error.send(messageOrInteraction, {
|
|
2386
|
+
sendMethod: messageOrInteraction instanceof import_discord9.Message ? 5 /* MessageEdit */ : void 0,
|
|
2387
|
+
components: [actionRow]
|
|
2388
|
+
});
|
|
2389
|
+
});
|
|
2390
|
+
return msg;
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
// src/utils/async.ts
|
|
2394
|
+
async function retryExponentialBackoff(fn, maxRetries = 3, retryDelay = 1e3) {
|
|
2395
|
+
let attempts = 0;
|
|
2396
|
+
while (true) {
|
|
2397
|
+
try {
|
|
2398
|
+
return await fn(attempts);
|
|
2399
|
+
} catch (error) {
|
|
2400
|
+
if (attempts >= maxRetries) throw error;
|
|
2401
|
+
await new Promise((resolve) => setTimeout(resolve, Math.pow(1.75, attempts) * retryDelay + Math.random() * 500));
|
|
2402
|
+
attempts++;
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
// package.json
|
|
2408
|
+
var version = "1.0.0";
|
|
2409
|
+
|
|
2410
|
+
// src/client.ts
|
|
2411
|
+
var import_node_crypto3 = require("crypto");
|
|
2412
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
2413
|
+
var clientInstances = [];
|
|
2414
|
+
var Vimcord = class _Vimcord extends import_discord10.Client {
|
|
2415
|
+
uuid = (0, import_node_crypto3.randomUUID)();
|
|
2416
|
+
index = clientInstances.length;
|
|
2417
|
+
clientOptions;
|
|
2418
|
+
features;
|
|
2419
|
+
config;
|
|
2420
|
+
status;
|
|
2421
|
+
events;
|
|
2422
|
+
commands;
|
|
2423
|
+
database;
|
|
2424
|
+
// Configure custom logger
|
|
2425
|
+
logger = new Logger({ prefixEmoji: "\u26A1", prefix: `vimcord (i${this.index})` }).extend({
|
|
2426
|
+
clientBanner(client) {
|
|
2427
|
+
if (client.config.app.disableBanner) return;
|
|
2428
|
+
const border = "\u2550".repeat(50);
|
|
2429
|
+
console.log(import_chalk2.default.hex(this.colors.primary)(`
|
|
2430
|
+
\u2554${border}\u2557`));
|
|
2431
|
+
console.log(
|
|
2432
|
+
import_chalk2.default.hex(this.colors.primary)("\u2551") + import_chalk2.default.bold.hex(this.colors.text)(
|
|
2433
|
+
` \u{1F680} ${client.config.app.name} v${client.config.app.appVersion}`.padEnd(
|
|
2434
|
+
50 - (client.config.app.devMode ? 12 : 0)
|
|
2435
|
+
)
|
|
2436
|
+
) + import_chalk2.default.hex(this.colors.primary)(
|
|
2437
|
+
`${client.config.app.devMode ? import_chalk2.default.hex(this.colors.warn)("devMode \u26A0\uFE0F ") : ""}\u2551`
|
|
2438
|
+
)
|
|
2439
|
+
);
|
|
2440
|
+
console.log(import_chalk2.default.hex(this.colors.primary)(`\u2551${"".padEnd(50)}\u2551`));
|
|
2441
|
+
console.log(
|
|
2442
|
+
import_chalk2.default.hex(this.colors.primary)("\u2551") + import_chalk2.default.hex(this.colors.muted)(
|
|
2443
|
+
` # Powered by Vimcord v${version}`.padEnd(50 - 3 - `${client.index}`.length)
|
|
2444
|
+
) + import_chalk2.default.hex(this.colors.primary)(`${import_chalk2.default.hex(this.colors.muted)(`i${client.index}`)} \u2551`)
|
|
2445
|
+
);
|
|
2446
|
+
console.log(import_chalk2.default.hex(this.colors.primary)(`\u255A${border}\u255D
|
|
2447
|
+
`));
|
|
2448
|
+
},
|
|
2449
|
+
clientReady(clientTag, guildCount) {
|
|
2450
|
+
console.log(
|
|
2451
|
+
this.formatTimestamp(),
|
|
2452
|
+
this.formatPrefix(),
|
|
2453
|
+
import_chalk2.default.hex(this.colors.success)("\u{1F916} READY"),
|
|
2454
|
+
import_chalk2.default.white(`Connected as ${import_chalk2.default.bold.hex(this.colors.primary)(clientTag)}`),
|
|
2455
|
+
import_chalk2.default.hex(this.colors.muted)(`\u2022 ${guildCount} guilds`)
|
|
2456
|
+
);
|
|
2457
|
+
},
|
|
2458
|
+
moduleLoaded(moduleName, count, ignoredCount) {
|
|
2459
|
+
const countText = count ? import_chalk2.default.hex(this.colors.muted)(`(${count} items)`) : "";
|
|
2460
|
+
console.log(
|
|
2461
|
+
this.formatTimestamp(),
|
|
2462
|
+
this.formatPrefix(),
|
|
2463
|
+
import_chalk2.default.hex("#9B59B6")("\u{1F4E6} MODULE"),
|
|
2464
|
+
import_chalk2.default.hex(this.colors.warn)(`${moduleName} loaded`),
|
|
2465
|
+
ignoredCount ? import_chalk2.default.hex(this.colors.muted)(`(${ignoredCount} ignored)`) : "",
|
|
2466
|
+
countText
|
|
2467
|
+
);
|
|
2468
|
+
},
|
|
2469
|
+
commandExecuted(commandName, username, guildName) {
|
|
2470
|
+
const location = guildName ? `in ${import_chalk2.default.hex(this.colors.muted)(guildName)}` : "in DMs";
|
|
2471
|
+
console.log(
|
|
2472
|
+
this.formatTimestamp(),
|
|
2473
|
+
this.formatPrefix(),
|
|
2474
|
+
import_chalk2.default.hex("#87CEEB")("\u{1F4DD} COMMAND"),
|
|
2475
|
+
import_chalk2.default.hex(this.colors.warn)(`/${commandName}`),
|
|
2476
|
+
import_chalk2.default.white(`used by ${import_chalk2.default.bold(username)}`),
|
|
2477
|
+
import_chalk2.default.hex(this.colors.muted)(location)
|
|
2478
|
+
);
|
|
2479
|
+
},
|
|
2480
|
+
database(action, details) {
|
|
2481
|
+
console.log(
|
|
2482
|
+
this.formatTimestamp(),
|
|
2483
|
+
this.formatPrefix(),
|
|
2484
|
+
import_chalk2.default.hex("#FF6B9D")("\u{1F5C4}\uFE0F DATABASE"),
|
|
2485
|
+
import_chalk2.default.white(action),
|
|
2486
|
+
details ? import_chalk2.default.hex(this.colors.muted)(details) : ""
|
|
2487
|
+
);
|
|
2488
|
+
}
|
|
2489
|
+
});
|
|
2490
|
+
clientStartingPromise = null;
|
|
2491
|
+
constructor(options, features = {}, config = {}) {
|
|
2492
|
+
super(options);
|
|
2493
|
+
this.clientOptions = options;
|
|
2494
|
+
this.features = features;
|
|
2495
|
+
this.config = {
|
|
2496
|
+
app: createVimcordAppConfig(config.app),
|
|
2497
|
+
staff: createVimcordStaffConfig(config.staff),
|
|
2498
|
+
slashCommands: createVimcordSlashCommandConfig(config.slashCommands),
|
|
2499
|
+
prefixCommands: createVimcordPrefixCommandConfig(config.prefixCommands),
|
|
2500
|
+
contextCommands: createVimcordContextCommandConfig(config.contextCommands)
|
|
2501
|
+
};
|
|
2502
|
+
this.status = new VimcordStatusManager(this);
|
|
2503
|
+
this.events = new VimcordEventManager(this);
|
|
2504
|
+
this.commands = new VimcordCommandManager(this);
|
|
2505
|
+
if (this.features.useEnv) {
|
|
2506
|
+
if (typeof this.features.useEnv === "object") {
|
|
2507
|
+
import_dotenv.default.config({ quiet: true, ...this.features.useEnv });
|
|
2508
|
+
} else {
|
|
2509
|
+
import_dotenv.default.config({ quiet: true });
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
if (this.features.useGlobalErrorHandlers) {
|
|
2513
|
+
process.on("uncaughtException", (err) => this.logger.error("Uncaught Exception", err));
|
|
2514
|
+
process.on("unhandledRejection", (err) => this.logger.error("Unhandled Rejection", err));
|
|
2515
|
+
process.on("exit", (code) => this.logger.debug(`Process exited with code ${code}`));
|
|
2516
|
+
this.on("error", (err) => this.logger.error("Client Error", err));
|
|
2517
|
+
this.on("shardError", (err) => this.logger.error("Client Shard Error", err));
|
|
2518
|
+
}
|
|
2519
|
+
this.logger.clientBanner(this);
|
|
2520
|
+
this.once("clientReady", (client) => {
|
|
2521
|
+
this.logger.clientReady(client.user.tag, client.guilds.cache.size);
|
|
2522
|
+
});
|
|
2523
|
+
clientInstances.push(this);
|
|
2524
|
+
}
|
|
2525
|
+
/** Returns the options, features, and config of this client */
|
|
2526
|
+
toJSON() {
|
|
2527
|
+
return {
|
|
2528
|
+
options: this.clientOptions,
|
|
2529
|
+
features: this.features,
|
|
2530
|
+
config: this.config
|
|
2531
|
+
};
|
|
2532
|
+
}
|
|
2533
|
+
/** Make a clone of this client */
|
|
2534
|
+
clone() {
|
|
2535
|
+
const { options, features, config } = this.toJSON();
|
|
2536
|
+
return new _Vimcord(options, features, config);
|
|
2537
|
+
}
|
|
2538
|
+
configureApp(options = {}) {
|
|
2539
|
+
this.config.app = createVimcordAppConfig(options);
|
|
2540
|
+
if (this.features.hookToolsDevMode) {
|
|
2541
|
+
globalVimcordToolsConfig.devMode = this.config.app.devMode;
|
|
2542
|
+
}
|
|
2543
|
+
return this;
|
|
2544
|
+
}
|
|
2545
|
+
configureStaff(options = {}) {
|
|
2546
|
+
this.config.staff = createVimcordStaffConfig(options);
|
|
2547
|
+
return this;
|
|
2548
|
+
}
|
|
2549
|
+
configureSlashCommands(options) {
|
|
2550
|
+
this.config.slashCommands = createVimcordSlashCommandConfig(options);
|
|
2551
|
+
return this;
|
|
2552
|
+
}
|
|
2553
|
+
configurePrefixCommands(options) {
|
|
2554
|
+
this.config.prefixCommands = createVimcordPrefixCommandConfig(options);
|
|
2555
|
+
return this;
|
|
2556
|
+
}
|
|
2557
|
+
configureContextCommands(options) {
|
|
2558
|
+
this.config.contextCommands = createVimcordContextCommandConfig(options);
|
|
2559
|
+
return this;
|
|
2560
|
+
}
|
|
2561
|
+
async addEventModules(dir, replaceAll) {
|
|
2562
|
+
await this.events.importFrom(dir, replaceAll);
|
|
2563
|
+
return this;
|
|
2564
|
+
}
|
|
2565
|
+
async addSlashCommandModules(dir, replaceAll) {
|
|
2566
|
+
await this.commands.slash.importFrom(dir, replaceAll);
|
|
2567
|
+
return this;
|
|
2568
|
+
}
|
|
2569
|
+
async addPrefixCommandModules(dir, replaceAll) {
|
|
2570
|
+
await this.commands.prefix.importFrom(dir, replaceAll);
|
|
2571
|
+
return this;
|
|
2572
|
+
}
|
|
2573
|
+
async addContextCommandModules(dir, replaceAll) {
|
|
2574
|
+
await this.commands.context.importFrom(dir, replaceAll);
|
|
2575
|
+
return this;
|
|
2576
|
+
}
|
|
2577
|
+
async useDatabase(database) {
|
|
2578
|
+
this.database = database;
|
|
2579
|
+
this.logger.database("Using", database.name);
|
|
2580
|
+
return this.database.connect();
|
|
2581
|
+
}
|
|
2582
|
+
async whenReady() {
|
|
2583
|
+
if (this.isReady()) return this;
|
|
2584
|
+
return new Promise((resolve, reject) => {
|
|
2585
|
+
const timeout = setTimeout(() => reject(new Error("Client is not ready")), 45e3);
|
|
2586
|
+
this.once("clientReady", () => {
|
|
2587
|
+
clearTimeout(timeout);
|
|
2588
|
+
resolve(this);
|
|
2589
|
+
});
|
|
2590
|
+
});
|
|
2591
|
+
}
|
|
2592
|
+
async build() {
|
|
2593
|
+
this.configureApp(this.config.app);
|
|
2594
|
+
this.configureStaff(this.config.staff);
|
|
2595
|
+
this.configureSlashCommands(this.config.slashCommands);
|
|
2596
|
+
this.configurePrefixCommands(this.config.prefixCommands);
|
|
2597
|
+
this.configureContextCommands(this.config.contextCommands);
|
|
2598
|
+
if (this.features.importModules) {
|
|
2599
|
+
const importModules = this.features.importModules;
|
|
2600
|
+
await Promise.all([
|
|
2601
|
+
importModules.events && this.addEventModules(importModules.events),
|
|
2602
|
+
importModules.slashCommands && this.addSlashCommandModules(importModules.slashCommands),
|
|
2603
|
+
importModules.prefixCommands && this.addPrefixCommandModules(importModules.prefixCommands),
|
|
2604
|
+
importModules.contextCommands && this.addContextCommandModules(importModules.contextCommands)
|
|
2605
|
+
]);
|
|
2606
|
+
}
|
|
2607
|
+
if (this.features.useDefaultSlashCommandHandler) {
|
|
2608
|
+
this.events.register(defaultSlashCommandHandler);
|
|
2609
|
+
}
|
|
2610
|
+
if (this.features.useDefaultPrefixCommandHandler) {
|
|
2611
|
+
this.events.register(defaultPrefixCommandHandler);
|
|
2612
|
+
}
|
|
2613
|
+
if (this.features.useDefaultContextCommandHandler) {
|
|
2614
|
+
this.events.register(defaultContextCommandHandler);
|
|
2615
|
+
}
|
|
2616
|
+
return this;
|
|
2617
|
+
}
|
|
2618
|
+
async start(tokenOrPreHook, preHook) {
|
|
2619
|
+
if (this.clientStartingPromise) return this.clientStartingPromise;
|
|
2620
|
+
const main = async () => {
|
|
2621
|
+
let token = typeof tokenOrPreHook === "string" ? tokenOrPreHook : void 0;
|
|
2622
|
+
token ??= this.config.app.devMode ? process.env.TOKEN_DEV : process.env.TOKEN;
|
|
2623
|
+
if (!token) {
|
|
2624
|
+
throw new Error(
|
|
2625
|
+
`TOKEN Missing: ${this.config.app.devMode ? "devMode is enabled, but TOKEN_DEV is not set" : "TOKEN not set"}`
|
|
2626
|
+
);
|
|
2627
|
+
}
|
|
2628
|
+
await this.build();
|
|
2629
|
+
try {
|
|
2630
|
+
if (typeof tokenOrPreHook === "function") {
|
|
2631
|
+
await tokenOrPreHook(this);
|
|
2632
|
+
} else {
|
|
2633
|
+
await preHook?.(this);
|
|
2634
|
+
}
|
|
2635
|
+
const stopLoader = this.logger.loader("Connecting to Discord...");
|
|
2636
|
+
const loginResult = await retryExponentialBackoff(
|
|
2637
|
+
() => super.login(token),
|
|
2638
|
+
this.features.loginAttempts ?? 3,
|
|
2639
|
+
1e3
|
|
2640
|
+
);
|
|
2641
|
+
stopLoader("Connected to Discord ");
|
|
2642
|
+
this.config.app.verbose && this.logger.debug("\u23F3 Waiting for ready...");
|
|
2643
|
+
return loginResult;
|
|
2644
|
+
} catch (err) {
|
|
2645
|
+
this.logger.error(
|
|
2646
|
+
`Failed to log into Discord after ${this.features.loginAttempts} attempt(s))`,
|
|
2647
|
+
err
|
|
2648
|
+
);
|
|
2649
|
+
return null;
|
|
2650
|
+
} finally {
|
|
2651
|
+
this.clientStartingPromise = null;
|
|
2652
|
+
}
|
|
2653
|
+
};
|
|
2654
|
+
this.clientStartingPromise = main();
|
|
2655
|
+
return this.clientStartingPromise;
|
|
2656
|
+
}
|
|
2657
|
+
async kill() {
|
|
2658
|
+
await super.destroy();
|
|
2659
|
+
const idx = clientInstances.indexOf(this);
|
|
2660
|
+
if (idx >= 0) clientInstances.splice(idx, 1);
|
|
2661
|
+
this.logger.debug("\u{1F6AA} Logged out of Discord");
|
|
2662
|
+
}
|
|
2663
|
+
/** Shortcut for {@link fetchUser tools.fetchUser} */
|
|
2664
|
+
async fetchUser(id) {
|
|
2665
|
+
const client = await this.whenReady();
|
|
2666
|
+
return fetchUser(client, id);
|
|
2667
|
+
}
|
|
2668
|
+
/** Shortcut for {@link fetchGuild tools.fetchGuild} */
|
|
2669
|
+
async fetchGuild(id) {
|
|
2670
|
+
const client = await this.whenReady();
|
|
2671
|
+
return fetchGuild(client, id);
|
|
2672
|
+
}
|
|
2673
|
+
};
|
|
2674
|
+
var defaultSlashCommandHandler = new EventBuilder({
|
|
2675
|
+
event: "interactionCreate",
|
|
2676
|
+
name: "SlashCommandHandler",
|
|
2677
|
+
async execute(client, interaction) {
|
|
2678
|
+
if (!interaction.isChatInputCommand()) return;
|
|
2679
|
+
const command = client.commands.slash.get(interaction.commandName);
|
|
2680
|
+
if (!command) {
|
|
2681
|
+
return interaction.reply({
|
|
2682
|
+
content: `**/\`${interaction.commandName}\`** is not a command`,
|
|
2683
|
+
flags: "Ephemeral"
|
|
2684
|
+
});
|
|
2685
|
+
}
|
|
2686
|
+
if (command.deferReply && !interaction.replied && !interaction.deferred) {
|
|
2687
|
+
await interaction.deferReply(typeof command.deferReply === "object" ? command.deferReply : void 0);
|
|
2688
|
+
}
|
|
2689
|
+
try {
|
|
2690
|
+
return command.executeCommand(client, interaction);
|
|
2691
|
+
} catch (err) {
|
|
2692
|
+
sendCommandErrorEmbed(client, err, interaction.guild, interaction);
|
|
2693
|
+
throw err;
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
});
|
|
2697
|
+
var defaultPrefixCommandHandler = new EventBuilder({
|
|
2698
|
+
event: "messageCreate",
|
|
2699
|
+
name: "PrefixCommandHandler",
|
|
2700
|
+
async execute(client, message) {
|
|
2701
|
+
if (message.author.bot) return;
|
|
2702
|
+
let prefixUsed;
|
|
2703
|
+
if (!message.content.startsWith(client.config.prefixCommands.defaultPrefix)) {
|
|
2704
|
+
if (client.config.prefixCommands.allowMentionAsPrefix) {
|
|
2705
|
+
if (!message.content.startsWith(`${(0, import_discord10.userMention)(client.user.id)} `)) {
|
|
2706
|
+
return;
|
|
2707
|
+
} else {
|
|
2708
|
+
prefixUsed = `${(0, import_discord10.userMention)(client.user.id)} `;
|
|
2709
|
+
}
|
|
2710
|
+
} else {
|
|
2711
|
+
return;
|
|
2712
|
+
}
|
|
2713
|
+
} else {
|
|
2714
|
+
prefixUsed = client.config.prefixCommands.defaultPrefix;
|
|
2715
|
+
}
|
|
2716
|
+
message.content = message.content.slice(prefixUsed.length);
|
|
2717
|
+
let commandName = message.content.split(" ")[0];
|
|
2718
|
+
if (!commandName) {
|
|
2719
|
+
return;
|
|
2720
|
+
}
|
|
2721
|
+
const command = client.commands.prefix.get(commandName) || client.commands.prefix.getByAlias(commandName);
|
|
2722
|
+
if (!command) {
|
|
2723
|
+
return;
|
|
2724
|
+
}
|
|
2725
|
+
message.content = message.content.slice(commandName.length + 1);
|
|
2726
|
+
try {
|
|
2727
|
+
return command.executeCommand(client, message);
|
|
2728
|
+
} catch (err) {
|
|
2729
|
+
sendCommandErrorEmbed(client, err, message.guild, message);
|
|
2730
|
+
throw err;
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
});
|
|
2734
|
+
var defaultContextCommandHandler = new EventBuilder({
|
|
2735
|
+
event: "interactionCreate",
|
|
2736
|
+
name: "ContextCommandHandler",
|
|
2737
|
+
execute(client, interaction) {
|
|
2738
|
+
if (!interaction.isContextMenuCommand()) return;
|
|
2739
|
+
interaction.reply({ content: "This handler is not yet implemented" });
|
|
2740
|
+
}
|
|
2741
|
+
});
|
|
2742
|
+
|
|
2743
|
+
// src/modules/db/mongo/mongo.ts
|
|
2744
|
+
var import_node_crypto4 = require("crypto");
|
|
2745
|
+
var import_node_events2 = __toESM(require("events"));
|
|
2746
|
+
var import_mongoose = __toESM(require("mongoose"));
|
|
2747
|
+
try {
|
|
2748
|
+
import("mongoose");
|
|
2749
|
+
} catch {
|
|
2750
|
+
throw new Error("MongoDatabase requires the mongoose package, install it with `npm install mongoose`");
|
|
2751
|
+
}
|
|
2752
|
+
var globalInstanceEmitter = new import_node_events2.default();
|
|
2753
|
+
var instances = [];
|
|
2754
|
+
async function useMongoDatabase(index) {
|
|
2755
|
+
const instance = instances.at(index ?? 0);
|
|
2756
|
+
if (!instance) {
|
|
2757
|
+
return new Promise((resolve, reject) => {
|
|
2758
|
+
const timeout = setTimeout(() => reject("useMongoDatabase timed out"), 45e3);
|
|
2759
|
+
globalInstanceEmitter.once("connected", (mdb) => {
|
|
2760
|
+
clearTimeout(timeout);
|
|
2761
|
+
resolve(mdb);
|
|
2762
|
+
});
|
|
2763
|
+
});
|
|
2764
|
+
}
|
|
2765
|
+
return instance;
|
|
2766
|
+
}
|
|
2767
|
+
var MongoDatabase = class {
|
|
2768
|
+
constructor(client, options) {
|
|
2769
|
+
this.client = client;
|
|
2770
|
+
this.mongoose = new import_mongoose.default.Mongoose(options);
|
|
2771
|
+
this.index = instances.length - 1;
|
|
2772
|
+
instances.push(this);
|
|
2773
|
+
globalInstanceEmitter.emit("created", this);
|
|
2774
|
+
}
|
|
2775
|
+
name = "MongoDatabase";
|
|
2776
|
+
uuid = (0, import_node_crypto4.randomUUID)();
|
|
2777
|
+
index;
|
|
2778
|
+
uri;
|
|
2779
|
+
mongoose;
|
|
2780
|
+
eventEmitter = new import_node_events2.default();
|
|
2781
|
+
isReady = false;
|
|
2782
|
+
isConnecting = false;
|
|
2783
|
+
async waitForReady() {
|
|
2784
|
+
if (!this.isReady && this.isConnecting) {
|
|
2785
|
+
return new Promise((resolve) => this.eventEmitter.once("ready", () => resolve(this.isReady)));
|
|
2786
|
+
}
|
|
2787
|
+
return this.isReady;
|
|
2788
|
+
}
|
|
2789
|
+
async connect(uri, connectionOptions, options) {
|
|
2790
|
+
if (!this.isReady && this.isConnecting) {
|
|
2791
|
+
return new Promise((resolve) => this.eventEmitter.once("ready", () => resolve(true)));
|
|
2792
|
+
}
|
|
2793
|
+
if (this.mongoose.connection?.readyState === 1) {
|
|
2794
|
+
return true;
|
|
2795
|
+
}
|
|
2796
|
+
uri ??= this.uri || this.client.config.app.devMode ? process.env.MONGO_URI_DEV : process.env.MONGO_URI;
|
|
2797
|
+
options = { ...options, maxRetries: options?.maxRetries ?? 3 };
|
|
2798
|
+
if (!uri) {
|
|
2799
|
+
throw new Error(
|
|
2800
|
+
`MONGO_URI Missing: ${this.client.config.app.devMode ? "DEV MODE is enabled, but MONGO_URI_DEV is not set" : "MONGO_URI not set"}`
|
|
2801
|
+
);
|
|
2802
|
+
}
|
|
2803
|
+
this.uri = uri;
|
|
2804
|
+
this.isReady = false;
|
|
2805
|
+
this.isConnecting = true;
|
|
2806
|
+
try {
|
|
2807
|
+
const stopLoader = this.client.logger.loader("Connecting to MongoDB...");
|
|
2808
|
+
await retryExponentialBackoff(
|
|
2809
|
+
(attempt) => {
|
|
2810
|
+
return this.mongoose.connect(uri, {
|
|
2811
|
+
serverSelectionTimeoutMS: 3e4,
|
|
2812
|
+
socketTimeoutMS: 45e3,
|
|
2813
|
+
connectTimeoutMS: 3e4,
|
|
2814
|
+
maxPoolSize: 10,
|
|
2815
|
+
minPoolSize: 5,
|
|
2816
|
+
bufferCommands: false,
|
|
2817
|
+
...connectionOptions
|
|
2818
|
+
});
|
|
2819
|
+
},
|
|
2820
|
+
options.maxRetries,
|
|
2821
|
+
1e3
|
|
2822
|
+
);
|
|
2823
|
+
this.isReady = true;
|
|
2824
|
+
this.eventEmitter.emit("ready");
|
|
2825
|
+
globalInstanceEmitter.emit("connected", this);
|
|
2826
|
+
stopLoader("Connected to MongoDB ");
|
|
2827
|
+
} catch (err) {
|
|
2828
|
+
this.client.logger.error(`Failed to connect to MongoDB after ${options.maxRetries} attempt(s)`, err);
|
|
2829
|
+
}
|
|
2830
|
+
this.isConnecting = false;
|
|
2831
|
+
return true;
|
|
2832
|
+
}
|
|
2833
|
+
};
|
|
2834
|
+
|
|
2835
|
+
// src/modules/db/mongo/mongoSchema.builder.ts
|
|
2836
|
+
var import_mongoose2 = require("mongoose");
|
|
2837
|
+
var import_node_crypto5 = require("crypto");
|
|
2838
|
+
var import_node_events3 = __toESM(require("events"));
|
|
2839
|
+
try {
|
|
2840
|
+
import("mongoose");
|
|
2841
|
+
} catch {
|
|
2842
|
+
throw new Error("MongoSchemaBuilder requires the mongoose package, install it with `npm install mongoose`");
|
|
2843
|
+
}
|
|
2844
|
+
function createMongoSchema(collection, definition, options) {
|
|
2845
|
+
return new MongoSchemaBuilder(collection, definition, options);
|
|
2846
|
+
}
|
|
2847
|
+
var MongoSchemaBuilder = class {
|
|
2848
|
+
schema;
|
|
2849
|
+
model;
|
|
2850
|
+
database = null;
|
|
2851
|
+
connectionIndex = 0;
|
|
2852
|
+
isReady = false;
|
|
2853
|
+
isInitializing = false;
|
|
2854
|
+
eventEmitter = new import_node_events3.default();
|
|
2855
|
+
logger;
|
|
2856
|
+
constructor(collection, definition, options) {
|
|
2857
|
+
this.connectionIndex = options?.connectionIndex ?? this.connectionIndex;
|
|
2858
|
+
this.logger = new Logger({
|
|
2859
|
+
prefixEmoji: "\u{1F96D}",
|
|
2860
|
+
prefix: `MongoSchema (c${this.connectionIndex}) [${collection}]`,
|
|
2861
|
+
colors: { primary: "#F29B58" }
|
|
2862
|
+
});
|
|
2863
|
+
this.eventEmitter.once("initialized", () => {
|
|
2864
|
+
if (this.database) {
|
|
2865
|
+
this.schema = new import_mongoose2.Schema(definition, { versionKey: false });
|
|
2866
|
+
this.model = this.database.mongoose.model(collection, this.schema);
|
|
2867
|
+
this.eventEmitter.emit("ready", true);
|
|
2868
|
+
} else {
|
|
2869
|
+
this.eventEmitter.emit("error", new Error(`MongoDatabase (c${this.connectionIndex}) not found`));
|
|
2870
|
+
}
|
|
2871
|
+
});
|
|
2872
|
+
this.eventEmitter.on("ready", (ready) => {
|
|
2873
|
+
this.isReady = ready;
|
|
2874
|
+
if (this.database?.client.config.app.verbose) {
|
|
2875
|
+
this.logger.debug(`Loaded! | ${this.database?.client.config.app.name}`);
|
|
2876
|
+
}
|
|
2877
|
+
});
|
|
2878
|
+
this.eventEmitter.on("error", (error) => this.logger.error("Error:", error));
|
|
2879
|
+
this.init().catch((error) => {
|
|
2880
|
+
this.eventEmitter.emit("error", error);
|
|
2881
|
+
});
|
|
2882
|
+
}
|
|
2883
|
+
async init() {
|
|
2884
|
+
if (this.isInitializing) return;
|
|
2885
|
+
this.isInitializing = true;
|
|
2886
|
+
try {
|
|
2887
|
+
const database = await useMongoDatabase(this.connectionIndex);
|
|
2888
|
+
if (!database) {
|
|
2889
|
+
throw new Error("Could not use MongoDatabase");
|
|
2890
|
+
}
|
|
2891
|
+
this.database = database;
|
|
2892
|
+
this.eventEmitter.emit("initialized");
|
|
2893
|
+
} catch (err) {
|
|
2894
|
+
this.eventEmitter.emit("error", err);
|
|
2895
|
+
} finally {
|
|
2896
|
+
this.isInitializing = false;
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
extend(extras) {
|
|
2900
|
+
for (const [key, fn] of Object.entries(extras)) {
|
|
2901
|
+
if (typeof fn === "function") {
|
|
2902
|
+
this[key] = function(...args) {
|
|
2903
|
+
return fn.call(this, ...args);
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
return this;
|
|
2908
|
+
}
|
|
2909
|
+
on(event, listener) {
|
|
2910
|
+
this.eventEmitter.on(event, listener);
|
|
2911
|
+
return this;
|
|
2912
|
+
}
|
|
2913
|
+
once(event, listener) {
|
|
2914
|
+
this.eventEmitter.once(event, listener);
|
|
2915
|
+
return this;
|
|
2916
|
+
}
|
|
2917
|
+
off(event, listener) {
|
|
2918
|
+
this.eventEmitter.off(event, listener);
|
|
2919
|
+
return this;
|
|
2920
|
+
}
|
|
2921
|
+
async execute(fn) {
|
|
2922
|
+
try {
|
|
2923
|
+
if (!this.isReady) {
|
|
2924
|
+
await new Promise((resolve, reject) => {
|
|
2925
|
+
const timeout = setTimeout(() => reject("execution wait for ready timed out"), 45e3);
|
|
2926
|
+
this.eventEmitter.once("ready", () => {
|
|
2927
|
+
clearTimeout(timeout);
|
|
2928
|
+
resolve();
|
|
2929
|
+
});
|
|
2930
|
+
this.eventEmitter.once("error", (error) => {
|
|
2931
|
+
clearTimeout(timeout);
|
|
2932
|
+
reject(error);
|
|
2933
|
+
});
|
|
2934
|
+
});
|
|
2935
|
+
}
|
|
2936
|
+
if (!this.database) {
|
|
2937
|
+
throw new Error("MongoDB connection not found");
|
|
2938
|
+
}
|
|
2939
|
+
return await retryExponentialBackoff(async () => await fn());
|
|
2940
|
+
} catch (err) {
|
|
2941
|
+
this.eventEmitter.emit("error", err);
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
async createHexId(bytes, path2, maxRetries = 10) {
|
|
2945
|
+
return await this.execute(async () => {
|
|
2946
|
+
const createHex = () => Buffer.from((0, import_node_crypto5.randomBytes)(bytes)).toString("hex");
|
|
2947
|
+
let id = createHex();
|
|
2948
|
+
let tries = 0;
|
|
2949
|
+
while (await this.model.exists({ [path2]: id })) {
|
|
2950
|
+
if (tries >= maxRetries) throw Error(`Failed to generate a unique hex ID after ${tries} attempt(s)`);
|
|
2951
|
+
id = createHex();
|
|
2952
|
+
tries++;
|
|
2953
|
+
}
|
|
2954
|
+
return id;
|
|
2955
|
+
});
|
|
2956
|
+
}
|
|
2957
|
+
async count(filter) {
|
|
2958
|
+
return await this.execute(async () => {
|
|
2959
|
+
return this.model.countDocuments(filter);
|
|
2960
|
+
});
|
|
2961
|
+
}
|
|
2962
|
+
async exists(filter) {
|
|
2963
|
+
return await this.execute(async () => {
|
|
2964
|
+
return await this.model.exists(filter) ? true : false;
|
|
2965
|
+
});
|
|
2966
|
+
}
|
|
2967
|
+
async create(query) {
|
|
2968
|
+
return await this.execute(async () => {
|
|
2969
|
+
return this.model.create(query);
|
|
2970
|
+
});
|
|
2971
|
+
}
|
|
2972
|
+
async upsert(filter, query, options) {
|
|
2973
|
+
return await this.execute(async () => {
|
|
2974
|
+
return this.model.findOneAndUpdate(filter, query, { ...options, upsert: true, new: true });
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
async delete(filter) {
|
|
2978
|
+
return await this.execute(async () => {
|
|
2979
|
+
return this.model.deleteOne(filter);
|
|
2980
|
+
});
|
|
2981
|
+
}
|
|
2982
|
+
async deleteAll(filter) {
|
|
2983
|
+
return await this.execute(async () => {
|
|
2984
|
+
return this.model.deleteMany(filter);
|
|
2985
|
+
});
|
|
2986
|
+
}
|
|
2987
|
+
async distinct(key, filter) {
|
|
2988
|
+
return await this.execute(async () => {
|
|
2989
|
+
return this.model.distinct(key, filter);
|
|
2990
|
+
});
|
|
2991
|
+
}
|
|
2992
|
+
async fetch(filter, projection, options) {
|
|
2993
|
+
return await this.execute(async () => {
|
|
2994
|
+
return this.model.findOne(filter, projection, { ...options, lean: options?.lean ?? true });
|
|
2995
|
+
});
|
|
2996
|
+
}
|
|
2997
|
+
async fetchAll(filter, projection, options) {
|
|
2998
|
+
return await this.execute(async () => {
|
|
2999
|
+
return this.model.find(filter, projection, { ...options, lean: options?.lean ?? true });
|
|
3000
|
+
}) || [];
|
|
3001
|
+
}
|
|
3002
|
+
async update(filter, update, options) {
|
|
3003
|
+
return await this.execute(async () => {
|
|
3004
|
+
return this.model.findOneAndUpdate(filter, update, { ...options, lean: options?.lean ?? true });
|
|
3005
|
+
});
|
|
3006
|
+
}
|
|
3007
|
+
async updateAll(filter, update, options) {
|
|
3008
|
+
return await this.execute(async () => {
|
|
3009
|
+
return this.model.updateMany(filter, update, options);
|
|
3010
|
+
});
|
|
3011
|
+
}
|
|
3012
|
+
async aggregate(pipeline, options) {
|
|
3013
|
+
return await this.execute(async () => {
|
|
3014
|
+
const result = await this.model.aggregate(pipeline, options);
|
|
3015
|
+
return result?.length ? result : [];
|
|
3016
|
+
});
|
|
3017
|
+
}
|
|
3018
|
+
};
|
|
3019
|
+
|
|
3020
|
+
// src/tools/BetterContainer.ts
|
|
3021
|
+
var import_discord11 = require("discord.js");
|
|
3022
|
+
var BetterContainer = class {
|
|
3023
|
+
container = new import_discord11.ContainerBuilder();
|
|
3024
|
+
data;
|
|
3025
|
+
config;
|
|
3026
|
+
constructor(data = {}) {
|
|
3027
|
+
this.config = data.config || globalVimcordToolsConfig;
|
|
3028
|
+
this.data = {
|
|
3029
|
+
color: data.color ?? (this.config.devMode ? this.config.embedColorDev : this.config.embedColor),
|
|
3030
|
+
...data
|
|
3031
|
+
};
|
|
3032
|
+
this.build();
|
|
3033
|
+
}
|
|
3034
|
+
configure() {
|
|
3035
|
+
if (this.data.color) {
|
|
3036
|
+
try {
|
|
3037
|
+
const color = Array.isArray(this.data.color) ? this.data.color[Math.floor(Math.random() * this.data.color.length)] ?? null : this.data.color;
|
|
3038
|
+
if (color) {
|
|
3039
|
+
this.container.setAccentColor(parseInt(color.replace("#", ""), 16));
|
|
3040
|
+
} else {
|
|
3041
|
+
this.container.clearAccentColor();
|
|
3042
|
+
}
|
|
3043
|
+
} catch (error) {
|
|
3044
|
+
console.error("[BetterContainer] Invalid color:", error);
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
build() {
|
|
3049
|
+
this.configure();
|
|
3050
|
+
}
|
|
3051
|
+
addSeparator(options) {
|
|
3052
|
+
this.container.addSeparatorComponents((sb) => {
|
|
3053
|
+
if (options?.divider !== void 0) sb.setDivider(options.divider);
|
|
3054
|
+
if (options?.spacing !== void 0) sb.setSpacing(options.spacing);
|
|
3055
|
+
return sb;
|
|
3056
|
+
});
|
|
3057
|
+
return this;
|
|
3058
|
+
}
|
|
3059
|
+
addText(text) {
|
|
3060
|
+
this.container.addTextDisplayComponents((tdb) => tdb.setContent(Array.isArray(text) ? text.join("\n") : text));
|
|
3061
|
+
return this;
|
|
3062
|
+
}
|
|
3063
|
+
addMedia(...media) {
|
|
3064
|
+
this.container.addMediaGalleryComponents((mb) => {
|
|
3065
|
+
for (const m of media) {
|
|
3066
|
+
const urls = Array.isArray(m.url) ? m.url : [m.url];
|
|
3067
|
+
for (const u of urls) {
|
|
3068
|
+
mb.addItems((mgb) => {
|
|
3069
|
+
mgb.setURL(u);
|
|
3070
|
+
if (m.spoiler) mgb.setSpoiler(true);
|
|
3071
|
+
if (m.description) mgb.setDescription(m.description);
|
|
3072
|
+
return mgb;
|
|
3073
|
+
});
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
return mb;
|
|
3077
|
+
});
|
|
3078
|
+
return this;
|
|
3079
|
+
}
|
|
3080
|
+
addSection(data) {
|
|
3081
|
+
this.container.addSectionComponents((sb) => {
|
|
3082
|
+
if (data.text) {
|
|
3083
|
+
sb.addTextDisplayComponents(
|
|
3084
|
+
(tdb) => tdb.setContent(Array.isArray(data.text) ? data.text.join("\n") : data.text)
|
|
3085
|
+
);
|
|
3086
|
+
}
|
|
3087
|
+
if (data.thumbnail) sb.setThumbnailAccessory(new import_discord11.ThumbnailBuilder(data.thumbnail));
|
|
3088
|
+
if (data.button) sb.setButtonAccessory(new import_discord11.ButtonBuilder(data.button));
|
|
3089
|
+
return sb;
|
|
3090
|
+
});
|
|
3091
|
+
return this;
|
|
3092
|
+
}
|
|
3093
|
+
addActionRow(...components) {
|
|
3094
|
+
this.container.addActionRowComponents(...components);
|
|
3095
|
+
return this;
|
|
3096
|
+
}
|
|
3097
|
+
toJSON() {
|
|
3098
|
+
return this.container.toJSON();
|
|
3099
|
+
}
|
|
3100
|
+
async send(handler, options = {}) {
|
|
3101
|
+
this.build();
|
|
3102
|
+
return await dynaSend(handler, {
|
|
3103
|
+
...options,
|
|
3104
|
+
withResponse: true,
|
|
3105
|
+
components: [this.container],
|
|
3106
|
+
flags: Array.isArray(options.flags) ? [...options.flags, "IsComponentsV2"] : options.flags ? [options.flags, "IsComponentsV2"] : "IsComponentsV2"
|
|
3107
|
+
});
|
|
3108
|
+
}
|
|
3109
|
+
};
|
|
3110
|
+
|
|
3111
|
+
// src/tools/BetterModal.ts
|
|
3112
|
+
var import_discord12 = require("discord.js");
|
|
3113
|
+
function randomCharString(length) {
|
|
3114
|
+
const chars = "ABCDEFGHJKLMOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
3115
|
+
return Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join("");
|
|
3116
|
+
}
|
|
3117
|
+
var BetterModal = class {
|
|
3118
|
+
id;
|
|
3119
|
+
options;
|
|
3120
|
+
modal;
|
|
3121
|
+
components = /* @__PURE__ */ new Map();
|
|
3122
|
+
config;
|
|
3123
|
+
constructor(options = {}) {
|
|
3124
|
+
this.id = options.id || this.createModalId();
|
|
3125
|
+
this.options = options;
|
|
3126
|
+
this.modal = new import_discord12.ModalBuilder().setCustomId(this.id);
|
|
3127
|
+
this.config = options.config || globalVimcordToolsConfig;
|
|
3128
|
+
if (options.title) {
|
|
3129
|
+
this.setTitle(options.title);
|
|
3130
|
+
}
|
|
3131
|
+
if (options.components?.length) {
|
|
3132
|
+
this.addComponents(...options.components);
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
createModalId() {
|
|
3136
|
+
return `modal:${randomCharString(10)}-${Date.now()}`;
|
|
3137
|
+
}
|
|
3138
|
+
createComponentId() {
|
|
3139
|
+
return `modal-component:${randomCharString(4)}-${Date.now().toString().slice(-4)}`;
|
|
3140
|
+
}
|
|
3141
|
+
validateComponentLength() {
|
|
3142
|
+
if (this.components.size >= 5) throw new Error("Modal can only have 5 components");
|
|
3143
|
+
}
|
|
3144
|
+
toJSON() {
|
|
3145
|
+
return this.modal.toJSON();
|
|
3146
|
+
}
|
|
3147
|
+
build() {
|
|
3148
|
+
this.modal.setLabelComponents(Array.from(this.components.values()));
|
|
3149
|
+
return this.modal;
|
|
3150
|
+
}
|
|
3151
|
+
setTitle(title) {
|
|
3152
|
+
this.modal.setTitle(title);
|
|
3153
|
+
return this;
|
|
3154
|
+
}
|
|
3155
|
+
addComponents(...components) {
|
|
3156
|
+
for (const component of components) {
|
|
3157
|
+
if ("textInput" in component) {
|
|
3158
|
+
this.addTextInput(component.textInput);
|
|
3159
|
+
} else if ("stringSelect" in component) {
|
|
3160
|
+
this.addStringSelect(component.stringSelect);
|
|
3161
|
+
} else if ("channelSelect" in component) {
|
|
3162
|
+
this.addChannelSelect(component.channelSelect);
|
|
3163
|
+
} else if ("userSelect" in component) {
|
|
3164
|
+
this.addUserSelect(component.userSelect);
|
|
3165
|
+
} else if ("roleSelect" in component) {
|
|
3166
|
+
this.addRoleSelect(component.roleSelect);
|
|
3167
|
+
} else if ("mentionableSelect" in component) {
|
|
3168
|
+
this.addMentionableSelect(component.mentionableSelect);
|
|
3169
|
+
} else if ("fileUpload" in component) {
|
|
3170
|
+
this.addFileUpload(component.fileUpload);
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
return this;
|
|
3174
|
+
}
|
|
3175
|
+
setComponents(...components) {
|
|
3176
|
+
this.modal.spliceLabelComponents(0, this.modal.components.length);
|
|
3177
|
+
this.addComponents(...components);
|
|
3178
|
+
return this;
|
|
3179
|
+
}
|
|
3180
|
+
addTextInput(data) {
|
|
3181
|
+
this.validateComponentLength();
|
|
3182
|
+
let { label, description, custom_id, ...rest } = data;
|
|
3183
|
+
custom_id ||= this.createComponentId();
|
|
3184
|
+
const textInputComponent = new import_discord12.TextInputBuilder(rest).setCustomId(custom_id);
|
|
3185
|
+
if (!rest.style) textInputComponent.setStyle(import_discord12.TextInputStyle.Short);
|
|
3186
|
+
const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setTextInputComponent(textInputComponent);
|
|
3187
|
+
if (description) labelComponent.setDescription(description);
|
|
3188
|
+
this.components.set(custom_id, labelComponent);
|
|
3189
|
+
return this;
|
|
3190
|
+
}
|
|
3191
|
+
addStringSelect(data) {
|
|
3192
|
+
this.validateComponentLength();
|
|
3193
|
+
let { label, description, custom_id, ...rest } = data;
|
|
3194
|
+
custom_id ||= this.createComponentId();
|
|
3195
|
+
const stringSelectComponent = new import_discord12.StringSelectMenuBuilder(rest).setCustomId(custom_id);
|
|
3196
|
+
const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setStringSelectMenuComponent(stringSelectComponent);
|
|
3197
|
+
if (description) labelComponent.setDescription(description);
|
|
3198
|
+
this.components.set(custom_id, labelComponent);
|
|
3199
|
+
return this;
|
|
3200
|
+
}
|
|
3201
|
+
addChannelSelect(data) {
|
|
3202
|
+
this.validateComponentLength();
|
|
3203
|
+
let { label, description, custom_id, ...rest } = data;
|
|
3204
|
+
custom_id ||= this.createComponentId();
|
|
3205
|
+
const channelSelectComponent = new import_discord12.ChannelSelectMenuBuilder(rest).setCustomId(custom_id);
|
|
3206
|
+
const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setChannelSelectMenuComponent(channelSelectComponent);
|
|
3207
|
+
if (description) labelComponent.setDescription(description);
|
|
3208
|
+
this.components.set(custom_id, labelComponent);
|
|
3209
|
+
return this;
|
|
3210
|
+
}
|
|
3211
|
+
addUserSelect(data) {
|
|
3212
|
+
this.validateComponentLength();
|
|
3213
|
+
let { label, description, custom_id, ...rest } = data;
|
|
3214
|
+
custom_id ||= this.createComponentId();
|
|
3215
|
+
const userSelectComponent = new import_discord12.UserSelectMenuBuilder(rest).setCustomId(custom_id);
|
|
3216
|
+
const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setUserSelectMenuComponent(userSelectComponent);
|
|
3217
|
+
if (description) labelComponent.setDescription(description);
|
|
3218
|
+
this.components.set(custom_id, labelComponent);
|
|
3219
|
+
return this;
|
|
3220
|
+
}
|
|
3221
|
+
addRoleSelect(data) {
|
|
3222
|
+
this.validateComponentLength();
|
|
3223
|
+
let { label, description, custom_id, ...rest } = data;
|
|
3224
|
+
custom_id ||= this.createComponentId();
|
|
3225
|
+
const roleSelectComponent = new import_discord12.RoleSelectMenuBuilder(rest).setCustomId(custom_id);
|
|
3226
|
+
const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setRoleSelectMenuComponent(roleSelectComponent);
|
|
3227
|
+
if (description) labelComponent.setDescription(description);
|
|
3228
|
+
this.components.set(custom_id, labelComponent);
|
|
3229
|
+
return this;
|
|
3230
|
+
}
|
|
3231
|
+
addMentionableSelect(data) {
|
|
3232
|
+
this.validateComponentLength();
|
|
3233
|
+
let { label, description, custom_id, ...rest } = data;
|
|
3234
|
+
custom_id ||= this.createComponentId();
|
|
3235
|
+
const mentionableSelectComponent = new import_discord12.MentionableSelectMenuBuilder(rest).setCustomId(custom_id);
|
|
3236
|
+
const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setMentionableSelectMenuComponent(mentionableSelectComponent);
|
|
3237
|
+
if (description) labelComponent.setDescription(description);
|
|
3238
|
+
this.components.set(custom_id, labelComponent);
|
|
3239
|
+
return this;
|
|
3240
|
+
}
|
|
3241
|
+
addFileUpload(data) {
|
|
3242
|
+
this.validateComponentLength();
|
|
3243
|
+
let { label, description, custom_id, ...rest } = data;
|
|
3244
|
+
custom_id ||= this.createComponentId();
|
|
3245
|
+
const fileUploadComponent = new import_discord12.FileUploadBuilder(rest).setCustomId(custom_id);
|
|
3246
|
+
const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setFileUploadComponent(fileUploadComponent);
|
|
3247
|
+
if (description) labelComponent.setDescription(description);
|
|
3248
|
+
this.components.set(custom_id, labelComponent);
|
|
3249
|
+
return this;
|
|
3250
|
+
}
|
|
3251
|
+
/** Show the modal via interaction */
|
|
3252
|
+
async show(interaction) {
|
|
3253
|
+
if (!("showModal" in interaction)) throw new Error("Interaction does not support showing modals");
|
|
3254
|
+
if (!this.modal.data.title) throw new Error("Modal must have a title");
|
|
3255
|
+
this.build();
|
|
3256
|
+
await interaction.showModal(this.modal).catch((err) => {
|
|
3257
|
+
console.error("Modal failed to send", err);
|
|
3258
|
+
});
|
|
3259
|
+
}
|
|
3260
|
+
/** Waits for the modal to be submitted and returns the component data
|
|
3261
|
+
* @param interaction The interaction used to show the modal
|
|
3262
|
+
* @param options Options */
|
|
3263
|
+
async awaitSubmit(interaction, options) {
|
|
3264
|
+
if (!("showModal" in interaction)) throw new Error("Interaction does not support showing modals");
|
|
3265
|
+
try {
|
|
3266
|
+
const modalSubmit = await interaction.awaitModalSubmit({
|
|
3267
|
+
time: this.config.timeouts.modalSubmit,
|
|
3268
|
+
...options,
|
|
3269
|
+
filter: (i) => i.customId === this.id
|
|
3270
|
+
});
|
|
3271
|
+
const fields = {};
|
|
3272
|
+
const values = [];
|
|
3273
|
+
for (const [customId] of this.components) {
|
|
3274
|
+
let value = null;
|
|
3275
|
+
try {
|
|
3276
|
+
value = modalSubmit.fields.getTextInputValue(customId);
|
|
3277
|
+
} catch {
|
|
3278
|
+
try {
|
|
3279
|
+
const field = modalSubmit.fields.fields.get(customId);
|
|
3280
|
+
if (field && "values" in field) {
|
|
3281
|
+
value = field.values;
|
|
3282
|
+
}
|
|
3283
|
+
} catch {
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
fields[customId] = value;
|
|
3287
|
+
values.push(value);
|
|
3288
|
+
}
|
|
3289
|
+
return { fields, values, interaction: modalSubmit };
|
|
3290
|
+
} catch (error) {
|
|
3291
|
+
return null;
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
async showAndAwait(interaction, options) {
|
|
3295
|
+
if (!("showModal" in interaction)) throw new Error("Interaction does not support showing modals");
|
|
3296
|
+
await this.show(interaction);
|
|
3297
|
+
return this.awaitSubmit(interaction, options);
|
|
3298
|
+
}
|
|
3299
|
+
};
|
|
3300
|
+
|
|
3301
|
+
// src/tools/Paginator.ts
|
|
3302
|
+
var import_discord13 = require("discord.js");
|
|
3303
|
+
var import_node_events4 = __toESM(require("events"));
|
|
3304
|
+
var PaginationType = /* @__PURE__ */ ((PaginationType2) => {
|
|
3305
|
+
PaginationType2[PaginationType2["Short"] = 0] = "Short";
|
|
3306
|
+
PaginationType2[PaginationType2["ShortJump"] = 1] = "ShortJump";
|
|
3307
|
+
PaginationType2[PaginationType2["Long"] = 2] = "Long";
|
|
3308
|
+
PaginationType2[PaginationType2["LongJump"] = 3] = "LongJump";
|
|
3309
|
+
return PaginationType2;
|
|
3310
|
+
})(PaginationType || {});
|
|
3311
|
+
var PaginationTimeoutType = /* @__PURE__ */ ((PaginationTimeoutType2) => {
|
|
3312
|
+
PaginationTimeoutType2[PaginationTimeoutType2["DisableComponents"] = 0] = "DisableComponents";
|
|
3313
|
+
PaginationTimeoutType2[PaginationTimeoutType2["ClearComponents"] = 1] = "ClearComponents";
|
|
3314
|
+
PaginationTimeoutType2[PaginationTimeoutType2["DeleteMessage"] = 2] = "DeleteMessage";
|
|
3315
|
+
return PaginationTimeoutType2;
|
|
3316
|
+
})(PaginationTimeoutType || {});
|
|
3317
|
+
function wrapPositive(num, max) {
|
|
3318
|
+
return (num % (max + 1) + (max + 1)) % (max + 1);
|
|
3319
|
+
}
|
|
3320
|
+
function createNavButton(id, config) {
|
|
3321
|
+
const data = config.paginator.buttons[id];
|
|
3322
|
+
const btn = new import_discord13.ButtonBuilder({ customId: `btn_${id}`, style: import_discord13.ButtonStyle.Secondary });
|
|
3323
|
+
if (data.label) {
|
|
3324
|
+
btn.setLabel(data.label);
|
|
3325
|
+
} else {
|
|
3326
|
+
btn.setEmoji(data.emoji.name);
|
|
3327
|
+
}
|
|
3328
|
+
return btn;
|
|
3329
|
+
}
|
|
3330
|
+
function isEmbed(item) {
|
|
3331
|
+
return item instanceof import_discord13.EmbedBuilder || item instanceof BetterEmbed;
|
|
3332
|
+
}
|
|
3333
|
+
function resolvePages(pages) {
|
|
3334
|
+
if (Array.isArray(pages)) {
|
|
3335
|
+
if (pages.length === 0) return [];
|
|
3336
|
+
if (Array.isArray(pages[0])) return pages;
|
|
3337
|
+
return pages;
|
|
3338
|
+
}
|
|
3339
|
+
return [pages];
|
|
3340
|
+
}
|
|
3341
|
+
var Paginator = class {
|
|
3342
|
+
chapters = [];
|
|
3343
|
+
options;
|
|
3344
|
+
config;
|
|
3345
|
+
data;
|
|
3346
|
+
events;
|
|
3347
|
+
eventEmitter = new import_node_events4.default();
|
|
3348
|
+
constructor(options = {}) {
|
|
3349
|
+
this.config = options.config || globalVimcordToolsConfig;
|
|
3350
|
+
this.options = {
|
|
3351
|
+
type: options.type ?? 0 /* Short */,
|
|
3352
|
+
participants: options.participants ?? [],
|
|
3353
|
+
pages: options.pages ?? [],
|
|
3354
|
+
useReactions: options.useReactions ?? false,
|
|
3355
|
+
dynamic: options.dynamic ?? false,
|
|
3356
|
+
timeout: options.timeout ?? this.config.timeouts.pagination,
|
|
3357
|
+
onTimeout: options.onTimeout ?? 1 /* ClearComponents */
|
|
3358
|
+
};
|
|
3359
|
+
this.data = {
|
|
3360
|
+
message: null,
|
|
3361
|
+
messageActionRows: [],
|
|
3362
|
+
messageSendOptions: void 0,
|
|
3363
|
+
extraButtons: [],
|
|
3364
|
+
page: { current: null, index: { chapter: 0, nested: 0 } },
|
|
3365
|
+
navigation: { reactions: [], isRequired: false, isLong: false, canJump: false },
|
|
3366
|
+
collectors: { component: null, reaction: null },
|
|
3367
|
+
components: {
|
|
3368
|
+
chapterSelect: new import_discord13.StringSelectMenuBuilder({ customId: "ssm_chapterSelect" }),
|
|
3369
|
+
navigation: {
|
|
3370
|
+
first: createNavButton("first", this.config),
|
|
3371
|
+
back: createNavButton("back", this.config),
|
|
3372
|
+
jump: createNavButton("jump", this.config),
|
|
3373
|
+
next: createNavButton("next", this.config),
|
|
3374
|
+
last: createNavButton("last", this.config)
|
|
3375
|
+
},
|
|
3376
|
+
actionRows: {
|
|
3377
|
+
chapterSelect: new import_discord13.ActionRowBuilder(),
|
|
3378
|
+
navigation: new import_discord13.ActionRowBuilder()
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3381
|
+
};
|
|
3382
|
+
this.data.components.actionRows.chapterSelect.setComponents(this.data.components.chapterSelect);
|
|
3383
|
+
this.events = {
|
|
3384
|
+
beforeChapterChange: [],
|
|
3385
|
+
chapterChange: [],
|
|
3386
|
+
beforePageChange: [],
|
|
3387
|
+
pageChange: [],
|
|
3388
|
+
first: [],
|
|
3389
|
+
back: [],
|
|
3390
|
+
jump: [],
|
|
3391
|
+
next: [],
|
|
3392
|
+
last: [],
|
|
3393
|
+
collect: [],
|
|
3394
|
+
react: [],
|
|
3395
|
+
timeout: []
|
|
3396
|
+
};
|
|
3397
|
+
if (this.options.pages.length) {
|
|
3398
|
+
this.addChapter(this.options.pages, { label: "Default" });
|
|
3399
|
+
}
|
|
3400
|
+
for (const [key, val] of Object.entries(this.config.paginator.buttons)) {
|
|
3401
|
+
if (!val.emoji.id) throw new Error(`[Paginator] Button '${key}.id' is not defined`);
|
|
3402
|
+
if (!val.emoji.name) throw new Error(`[Paginator] Button '${key}.name' is not defined`);
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
async build() {
|
|
3406
|
+
await this.setPage();
|
|
3407
|
+
this.data.components.actionRows.navigation.setComponents([]);
|
|
3408
|
+
this.data.navigation.reactions = [];
|
|
3409
|
+
this.data.messageActionRows = [];
|
|
3410
|
+
if (this.data.navigation.isRequired) {
|
|
3411
|
+
let navTypes = [];
|
|
3412
|
+
if (this.options.dynamic) {
|
|
3413
|
+
const isLong = this.data.navigation.isLong;
|
|
3414
|
+
const isJump = this.options.type === 1 /* ShortJump */ || this.options.type === 3 /* LongJump */;
|
|
3415
|
+
if (isLong) {
|
|
3416
|
+
this.options.type = isJump ? 3 /* LongJump */ : 2 /* Long */;
|
|
3417
|
+
} else {
|
|
3418
|
+
this.options.type = isJump ? 1 /* ShortJump */ : 0 /* Short */;
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
switch (this.options.type) {
|
|
3422
|
+
case 0 /* Short */:
|
|
3423
|
+
navTypes = ["back", "next"];
|
|
3424
|
+
break;
|
|
3425
|
+
case 1 /* ShortJump */:
|
|
3426
|
+
navTypes = ["back", "jump", "next"];
|
|
3427
|
+
break;
|
|
3428
|
+
case 2 /* Long */:
|
|
3429
|
+
navTypes = ["first", "back", "next", "last"];
|
|
3430
|
+
break;
|
|
3431
|
+
case 3 /* LongJump */:
|
|
3432
|
+
navTypes = ["first", "back", "jump", "next", "last"];
|
|
3433
|
+
break;
|
|
3434
|
+
}
|
|
3435
|
+
if (this.options.useReactions) {
|
|
3436
|
+
this.data.navigation.reactions = navTypes.map((type) => {
|
|
3437
|
+
const data = this.config.paginator.buttons[type];
|
|
3438
|
+
return { name: data.emoji.name, id: data.emoji.id };
|
|
3439
|
+
});
|
|
3440
|
+
} else {
|
|
3441
|
+
this.data.components.actionRows.navigation.setComponents(
|
|
3442
|
+
navTypes.map((type) => this.data.components.navigation[type])
|
|
3443
|
+
);
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
if (this.chapters.length > 1) {
|
|
3447
|
+
this.data.messageActionRows.push(this.data.components.actionRows.chapterSelect);
|
|
3448
|
+
}
|
|
3449
|
+
if (this.data.navigation.isRequired && !this.options.useReactions || this.data.extraButtons.length) {
|
|
3450
|
+
for (const btn of this.data.extraButtons) {
|
|
3451
|
+
this.data.components.actionRows.navigation.components.splice(btn.index, 0, btn.component);
|
|
3452
|
+
}
|
|
3453
|
+
this.data.messageActionRows.push(this.data.components.actionRows.navigation);
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
buildSendOptions(options = {}) {
|
|
3457
|
+
const sendOptions = {
|
|
3458
|
+
content: "",
|
|
3459
|
+
embeds: [],
|
|
3460
|
+
components: [],
|
|
3461
|
+
flags: [],
|
|
3462
|
+
...options,
|
|
3463
|
+
withResponse: true
|
|
3464
|
+
};
|
|
3465
|
+
const page = this.data.page.current;
|
|
3466
|
+
if (Array.isArray(page)) {
|
|
3467
|
+
sendOptions.embeds.push(...page);
|
|
3468
|
+
} else if (typeof page === "string") {
|
|
3469
|
+
sendOptions.content = page;
|
|
3470
|
+
} else if (isEmbed(page)) {
|
|
3471
|
+
sendOptions.embeds.push(page);
|
|
3472
|
+
} else if (page instanceof import_discord13.ContainerBuilder || page instanceof BetterContainer) {
|
|
3473
|
+
sendOptions.components.push(page);
|
|
3474
|
+
if (!sendOptions.flags.includes("IsComponentsV2")) {
|
|
3475
|
+
sendOptions.flags.push("IsComponentsV2");
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
sendOptions.components.push(...this.data.messageActionRows);
|
|
3479
|
+
return sendOptions;
|
|
3480
|
+
}
|
|
3481
|
+
async handlePostTimeout() {
|
|
3482
|
+
if (!this.data.message) return;
|
|
3483
|
+
this.callEventStack("timeout", this.data.message);
|
|
3484
|
+
this.data.collectors.component?.stop();
|
|
3485
|
+
this.data.collectors.reaction?.stop();
|
|
3486
|
+
switch (this.options.onTimeout) {
|
|
3487
|
+
case 0 /* DisableComponents */:
|
|
3488
|
+
if (!this.data.message.editable) break;
|
|
3489
|
+
const disabledNavComponents = this.data.components.actionRows.navigation.components.map((component) => {
|
|
3490
|
+
if ("setDisabled" in component) {
|
|
3491
|
+
return component.setDisabled(true);
|
|
3492
|
+
}
|
|
3493
|
+
return component;
|
|
3494
|
+
});
|
|
3495
|
+
const disabledNavRow = import_discord13.ActionRowBuilder.from(this.data.components.actionRows.navigation).setComponents(
|
|
3496
|
+
disabledNavComponents
|
|
3497
|
+
);
|
|
3498
|
+
const newComponents = [];
|
|
3499
|
+
const currentPage = this.data.page.current;
|
|
3500
|
+
if (currentPage instanceof import_discord13.ContainerBuilder || currentPage instanceof BetterContainer) {
|
|
3501
|
+
newComponents.push(currentPage);
|
|
3502
|
+
}
|
|
3503
|
+
if (this.chapters.length > 1) {
|
|
3504
|
+
const disabledSelect = import_discord13.StringSelectMenuBuilder.from(this.data.components.chapterSelect).setDisabled(
|
|
3505
|
+
true
|
|
3506
|
+
);
|
|
3507
|
+
newComponents.push(
|
|
3508
|
+
import_discord13.ActionRowBuilder.from(this.data.components.actionRows.chapterSelect).setComponents(disabledSelect)
|
|
3509
|
+
);
|
|
3510
|
+
}
|
|
3511
|
+
if (disabledNavRow.components.length > 0) {
|
|
3512
|
+
newComponents.push(disabledNavRow);
|
|
3513
|
+
}
|
|
3514
|
+
await this.data.message.edit({ components: newComponents }).catch(Boolean);
|
|
3515
|
+
if (this.options.useReactions) {
|
|
3516
|
+
await this.nav_removeFromMessage();
|
|
3517
|
+
}
|
|
3518
|
+
break;
|
|
3519
|
+
case 1 /* ClearComponents */:
|
|
3520
|
+
if (this.data.message.editable) {
|
|
3521
|
+
await this.nav_removeFromMessage();
|
|
3522
|
+
}
|
|
3523
|
+
break;
|
|
3524
|
+
case 2 /* DeleteMessage */:
|
|
3525
|
+
await this.data.message.delete().catch(Boolean);
|
|
3526
|
+
break;
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
async nav_removeFromMessage() {
|
|
3530
|
+
if (!this.data.message?.editable) return;
|
|
3531
|
+
if (this.options.useReactions) {
|
|
3532
|
+
await this.data.message.reactions.removeAll().catch(Boolean);
|
|
3533
|
+
} else {
|
|
3534
|
+
const newComponents = this.data.message.components.filter((c) => c.type !== import_discord13.ComponentType.Container);
|
|
3535
|
+
await this.data.message.edit({ components: newComponents }).catch(Boolean);
|
|
3536
|
+
}
|
|
3537
|
+
}
|
|
3538
|
+
async nav_addReactions() {
|
|
3539
|
+
if (!this.data.message || !this.options.useReactions || !this.data.navigation.reactions.length) return;
|
|
3540
|
+
for (const r of this.data.navigation.reactions) {
|
|
3541
|
+
await this.data.message.react(r.id).catch(Boolean);
|
|
3542
|
+
}
|
|
3543
|
+
}
|
|
3544
|
+
async collect_components() {
|
|
3545
|
+
if (!this.data.message || !this.data.messageActionRows.length) return;
|
|
3546
|
+
if (this.data.collectors.component) {
|
|
3547
|
+
this.data.collectors.component.resetTimer();
|
|
3548
|
+
return;
|
|
3549
|
+
}
|
|
3550
|
+
const participantIds = this.options.participants.map((p) => typeof p === "string" ? p : p.id);
|
|
3551
|
+
const collector = this.data.message.createMessageComponentCollector({
|
|
3552
|
+
filter: async (i) => {
|
|
3553
|
+
if (!participantIds.length) return true;
|
|
3554
|
+
if (participantIds.includes(i.user.id)) {
|
|
3555
|
+
return true;
|
|
3556
|
+
} else {
|
|
3557
|
+
await i.reply({ content: this.config.paginator.notAParticipantMessage, flags: "Ephemeral" });
|
|
3558
|
+
return false;
|
|
3559
|
+
}
|
|
3560
|
+
},
|
|
3561
|
+
...this.options.timeout ? { idle: this.options.timeout } : {}
|
|
3562
|
+
});
|
|
3563
|
+
this.data.collectors.component = collector;
|
|
3564
|
+
collector.on("collect", async (i) => {
|
|
3565
|
+
if (!i.isStringSelectMenu() && !i.isButton()) return;
|
|
3566
|
+
collector.resetTimer();
|
|
3567
|
+
this.callEventStack("collect", i, this.data.page.current, this.data.page.index);
|
|
3568
|
+
try {
|
|
3569
|
+
if (i.customId === "btn_jump") {
|
|
3570
|
+
this.callEventStack("jump", this.data.page.current, this.data.page.index);
|
|
3571
|
+
await i.reply({ content: "Jump not implemented yet.", flags: "Ephemeral" });
|
|
3572
|
+
return;
|
|
3573
|
+
}
|
|
3574
|
+
await i.deferUpdate().catch(Boolean);
|
|
3575
|
+
switch (i.customId) {
|
|
3576
|
+
case "ssm_chapterSelect":
|
|
3577
|
+
const chapterIndex = this.chapters.findIndex(
|
|
3578
|
+
(c) => c.id === i.values[0]
|
|
3579
|
+
);
|
|
3580
|
+
await this.setPage(chapterIndex, 0);
|
|
3581
|
+
break;
|
|
3582
|
+
case "btn_first":
|
|
3583
|
+
this.callEventStack("first", this.data.page.current, this.data.page.index);
|
|
3584
|
+
await this.setPage(this.data.page.index.chapter, 0);
|
|
3585
|
+
break;
|
|
3586
|
+
case "btn_back":
|
|
3587
|
+
this.callEventStack("back", this.data.page.current, this.data.page.index);
|
|
3588
|
+
await this.setPage(this.data.page.index.chapter, this.data.page.index.nested - 1);
|
|
3589
|
+
break;
|
|
3590
|
+
case "btn_next":
|
|
3591
|
+
this.callEventStack("next", this.data.page.current, this.data.page.index);
|
|
3592
|
+
await this.setPage(this.data.page.index.chapter, this.data.page.index.nested + 1);
|
|
3593
|
+
break;
|
|
3594
|
+
case "btn_last":
|
|
3595
|
+
this.callEventStack("last", this.data.page.current, this.data.page.index);
|
|
3596
|
+
await this.setPage(
|
|
3597
|
+
this.data.page.index.chapter,
|
|
3598
|
+
this.chapters[this.data.page.index.chapter].pages.length - 1
|
|
3599
|
+
);
|
|
3600
|
+
break;
|
|
3601
|
+
}
|
|
3602
|
+
await this.refresh();
|
|
3603
|
+
} catch (err) {
|
|
3604
|
+
console.error("[Paginator] Component navigation error", err);
|
|
3605
|
+
}
|
|
3606
|
+
});
|
|
3607
|
+
collector.on("end", async () => {
|
|
3608
|
+
this.data.collectors.component = null;
|
|
3609
|
+
this.handlePostTimeout();
|
|
3610
|
+
});
|
|
3611
|
+
}
|
|
3612
|
+
async callEventStack(event, ...args) {
|
|
3613
|
+
if (!this.events[event].length) return;
|
|
3614
|
+
const listeners = [...this.events[event]];
|
|
3615
|
+
for (const _event of listeners) {
|
|
3616
|
+
await _event.listener(...args);
|
|
3617
|
+
if (_event.once) {
|
|
3618
|
+
const originalIndex = this.events[event].indexOf(_event);
|
|
3619
|
+
if (originalIndex > -1) this.events[event].splice(originalIndex, 1);
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3623
|
+
on(event, listener, once = false) {
|
|
3624
|
+
this.events[event].push({ listener, once });
|
|
3625
|
+
return this;
|
|
3626
|
+
}
|
|
3627
|
+
/** Adds a chapter to the paginator.
|
|
3628
|
+
* @param pages The pages for this chapter.
|
|
3629
|
+
* Note: `[Embed1, Embed2]` = 2 Pages. `[[Embed1, Embed2]]` = 1 Page (Group of 2).
|
|
3630
|
+
* @param data Metadata for the chapter select menu. */
|
|
3631
|
+
addChapter(pages, data) {
|
|
3632
|
+
if (data.default === void 0 && !this.chapters.length) {
|
|
3633
|
+
data.default = true;
|
|
3634
|
+
}
|
|
3635
|
+
if (data.default) {
|
|
3636
|
+
this.data.components.chapterSelect.options.forEach((opt) => opt.setDefault(false));
|
|
3637
|
+
}
|
|
3638
|
+
if (!data.value) {
|
|
3639
|
+
data.value = `ssm_c:${this.chapters.length}`;
|
|
3640
|
+
}
|
|
3641
|
+
const normalizedPages = resolvePages(pages);
|
|
3642
|
+
this.chapters.push({ id: data.value, pages: normalizedPages });
|
|
3643
|
+
this.data.components.chapterSelect.addOptions(data);
|
|
3644
|
+
return this;
|
|
3645
|
+
}
|
|
3646
|
+
spliceChapters(index, deleteCount) {
|
|
3647
|
+
this.chapters.splice(index, deleteCount);
|
|
3648
|
+
this.data.components.chapterSelect.spliceOptions(index, deleteCount);
|
|
3649
|
+
return this;
|
|
3650
|
+
}
|
|
3651
|
+
hydrateChapter(index, pages, set) {
|
|
3652
|
+
if (!this.chapters[index]) {
|
|
3653
|
+
throw new Error(`[Paginator] Could not find chapter at index ${index}`);
|
|
3654
|
+
}
|
|
3655
|
+
const normalizedPages = resolvePages(pages);
|
|
3656
|
+
if (set) {
|
|
3657
|
+
this.chapters[index].pages = normalizedPages;
|
|
3658
|
+
} else {
|
|
3659
|
+
this.chapters[index].pages.push(...normalizedPages);
|
|
3660
|
+
}
|
|
3661
|
+
return this;
|
|
3662
|
+
}
|
|
3663
|
+
setPaginationType(type) {
|
|
3664
|
+
this.options.type = type;
|
|
3665
|
+
return this;
|
|
3666
|
+
}
|
|
3667
|
+
insertButtonAt(index, component) {
|
|
3668
|
+
if (this.data.components.actionRows.navigation.components.length >= 5) {
|
|
3669
|
+
throw new Error("[Paginator] You cannot have more than 5 components in 1 action row. Use a separate ActionRow");
|
|
3670
|
+
}
|
|
3671
|
+
this.data.extraButtons.push({ index, component });
|
|
3672
|
+
return this;
|
|
3673
|
+
}
|
|
3674
|
+
removeButtonAt(...index) {
|
|
3675
|
+
index.forEach((i) => this.data.extraButtons.splice(i, 1));
|
|
3676
|
+
return this;
|
|
3677
|
+
}
|
|
3678
|
+
async setPage(chapterIndex = this.data.page.index.chapter, nestedIndex = this.data.page.index.nested) {
|
|
3679
|
+
const _oldChapterIndex = this.data.page.index.chapter;
|
|
3680
|
+
this.data.page.index.chapter = wrapPositive(chapterIndex, this.chapters.length - 1);
|
|
3681
|
+
const currentChapter = this.chapters[this.data.page.index.chapter];
|
|
3682
|
+
if (!currentChapter) {
|
|
3683
|
+
throw new Error(`[Paginator] Could not find chapter at index ${this.data.page.index.chapter}`);
|
|
3684
|
+
}
|
|
3685
|
+
await this.callEventStack("beforeChapterChange", this.data.page.index.chapter);
|
|
3686
|
+
await this.callEventStack("beforePageChange", nestedIndex);
|
|
3687
|
+
const _oldNestedIndex = this.data.page.index.nested;
|
|
3688
|
+
this.data.page.index.nested = this.data.page.index.chapter !== _oldChapterIndex ? 0 : wrapPositive(nestedIndex, currentChapter.pages.length - 1);
|
|
3689
|
+
const currentPage = currentChapter.pages[this.data.page.index.nested];
|
|
3690
|
+
if (!currentPage) {
|
|
3691
|
+
throw new Error(`[Paginator] Could not find page at index ${this.data.page.index.nested}`);
|
|
3692
|
+
}
|
|
3693
|
+
this.data.page.current = currentPage;
|
|
3694
|
+
this.data.components.chapterSelect.options.forEach((opt) => opt.setDefault(false));
|
|
3695
|
+
this.data.components.chapterSelect.options.at(this.data.page.index.chapter)?.setDefault(true);
|
|
3696
|
+
const { jumpableThreshold, longThreshold } = this.config.paginator;
|
|
3697
|
+
this.data.navigation.isRequired = currentChapter.pages.length >= 2;
|
|
3698
|
+
this.data.navigation.canJump = currentChapter.pages.length >= jumpableThreshold;
|
|
3699
|
+
this.data.navigation.isLong = currentChapter.pages.length >= longThreshold;
|
|
3700
|
+
if (this.data.page.index.chapter !== _oldChapterIndex) {
|
|
3701
|
+
this.callEventStack(
|
|
3702
|
+
"chapterChange",
|
|
3703
|
+
this.data.components.chapterSelect.options.at(this.data.page.index.chapter),
|
|
3704
|
+
this.data.page.current,
|
|
3705
|
+
this.data.page.index
|
|
3706
|
+
);
|
|
3707
|
+
this.callEventStack("pageChange", this.data.page.current, this.data.page.index);
|
|
3708
|
+
} else if (this.data.page.index.nested !== _oldNestedIndex) {
|
|
3709
|
+
this.callEventStack("pageChange", this.data.page.current, this.data.page.index);
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
async refresh() {
|
|
3713
|
+
if (!this.data.message) {
|
|
3714
|
+
throw new Error("[Paginator] Cannot refresh, message not sent");
|
|
3715
|
+
}
|
|
3716
|
+
if (!this.data.message.editable) {
|
|
3717
|
+
throw new Error("[Paginator] Cannot refresh, message is not editable");
|
|
3718
|
+
}
|
|
3719
|
+
await this.build();
|
|
3720
|
+
this.data.message = await dynaSend(this.data.message, {
|
|
3721
|
+
sendMethod: 5 /* MessageEdit */,
|
|
3722
|
+
...this.buildSendOptions(this.data.messageSendOptions)
|
|
3723
|
+
});
|
|
3724
|
+
return this.data.message;
|
|
3725
|
+
}
|
|
3726
|
+
async send(handler, options) {
|
|
3727
|
+
this.data.messageSendOptions = options;
|
|
3728
|
+
await this.build();
|
|
3729
|
+
this.data.message = await dynaSend(handler, this.buildSendOptions(options));
|
|
3730
|
+
if (!this.data.message) return null;
|
|
3731
|
+
this.collect_components();
|
|
3732
|
+
return this.data.message;
|
|
3733
|
+
}
|
|
3734
|
+
};
|
|
3735
|
+
|
|
3736
|
+
// src/tools/Prompt.ts
|
|
3737
|
+
var import_discord14 = require("discord.js");
|
|
3738
|
+
var PromptResolveType = /* @__PURE__ */ ((PromptResolveType2) => {
|
|
3739
|
+
PromptResolveType2[PromptResolveType2["DisableComponents"] = 0] = "DisableComponents";
|
|
3740
|
+
PromptResolveType2[PromptResolveType2["ClearComponents"] = 1] = "ClearComponents";
|
|
3741
|
+
PromptResolveType2[PromptResolveType2["DeleteOnConfirm"] = 3] = "DeleteOnConfirm";
|
|
3742
|
+
PromptResolveType2[PromptResolveType2["DeleteOnReject"] = 4] = "DeleteOnReject";
|
|
3743
|
+
return PromptResolveType2;
|
|
3744
|
+
})(PromptResolveType || {});
|
|
3745
|
+
var Prompt = class {
|
|
3746
|
+
participants;
|
|
3747
|
+
content;
|
|
3748
|
+
embed;
|
|
3749
|
+
container;
|
|
3750
|
+
buttons;
|
|
3751
|
+
customButtons;
|
|
3752
|
+
onResolve;
|
|
3753
|
+
timeout;
|
|
3754
|
+
config;
|
|
3755
|
+
message = null;
|
|
3756
|
+
constructor(options = {}) {
|
|
3757
|
+
this.config = options.config ?? globalVimcordToolsConfig;
|
|
3758
|
+
this.participants = options.participants ?? [];
|
|
3759
|
+
this.timeout = options.timeout ?? this.config.timeouts.prompt;
|
|
3760
|
+
this.content = options.content;
|
|
3761
|
+
this.embed = options.embed ?? this.createDefaultForm();
|
|
3762
|
+
this.container = options?.container;
|
|
3763
|
+
this.buttons = this.createButtons(options.buttons);
|
|
3764
|
+
this.customButtons = this.createCustomButtons(options.customButtons);
|
|
3765
|
+
this.onResolve = options.onResolve ?? [3 /* DeleteOnConfirm */, 4 /* DeleteOnReject */];
|
|
3766
|
+
}
|
|
3767
|
+
createDefaultForm() {
|
|
3768
|
+
return new BetterEmbed({
|
|
3769
|
+
title: this.config.prompt.defaultTitle,
|
|
3770
|
+
description: this.config.prompt.defaultDescription
|
|
3771
|
+
});
|
|
3772
|
+
}
|
|
3773
|
+
createButtons(buttonOptions) {
|
|
3774
|
+
const confirm = this.buildButton(
|
|
3775
|
+
buttonOptions?.confirm,
|
|
3776
|
+
"btn_confirm",
|
|
3777
|
+
this.config.prompt.confirmLabel,
|
|
3778
|
+
import_discord14.ButtonStyle.Success
|
|
3779
|
+
);
|
|
3780
|
+
const reject = this.buildButton(
|
|
3781
|
+
buttonOptions?.reject,
|
|
3782
|
+
"btn_reject",
|
|
3783
|
+
this.config.prompt.rejectLabel,
|
|
3784
|
+
import_discord14.ButtonStyle.Danger
|
|
3785
|
+
);
|
|
3786
|
+
return { confirm, reject };
|
|
3787
|
+
}
|
|
3788
|
+
createCustomButtons(customOptions) {
|
|
3789
|
+
const map = /* @__PURE__ */ new Map();
|
|
3790
|
+
if (!customOptions) return map;
|
|
3791
|
+
for (const [customId, { builder, handler, index = 2 }] of Object.entries(customOptions)) {
|
|
3792
|
+
const button = this.buildButton(builder, customId, customId, import_discord14.ButtonStyle.Primary);
|
|
3793
|
+
map.set(customId, { button, handler, index });
|
|
3794
|
+
}
|
|
3795
|
+
return map;
|
|
3796
|
+
}
|
|
3797
|
+
buildButton(option, customId, defaultLabel, defaultStyle) {
|
|
3798
|
+
if (typeof option === "function") {
|
|
3799
|
+
return option(new import_discord14.ButtonBuilder());
|
|
3800
|
+
}
|
|
3801
|
+
if (option instanceof import_discord14.ButtonBuilder) {
|
|
3802
|
+
return option;
|
|
3803
|
+
}
|
|
3804
|
+
return new import_discord14.ButtonBuilder({
|
|
3805
|
+
customId,
|
|
3806
|
+
label: defaultLabel,
|
|
3807
|
+
style: defaultStyle,
|
|
3808
|
+
...option
|
|
3809
|
+
});
|
|
3810
|
+
}
|
|
3811
|
+
buildActionRow(disable = {}) {
|
|
3812
|
+
const confirmBtn = disable.confirm ? new import_discord14.ButtonBuilder(this.buttons.confirm.data).setDisabled(true) : this.buttons.confirm;
|
|
3813
|
+
const rejectBtn = disable.reject ? new import_discord14.ButtonBuilder(this.buttons.reject.data).setDisabled(true) : this.buttons.reject;
|
|
3814
|
+
const buttons = [];
|
|
3815
|
+
const customButtonsArray = Array.from(this.customButtons.entries()).map(([customId, data]) => ({
|
|
3816
|
+
customId,
|
|
3817
|
+
button: disable[customId] ? new import_discord14.ButtonBuilder(data.button.data).setDisabled(true) : data.button,
|
|
3818
|
+
index: data.index
|
|
3819
|
+
}));
|
|
3820
|
+
customButtonsArray.sort((a, b) => a.index - b.index);
|
|
3821
|
+
for (const custom of customButtonsArray) {
|
|
3822
|
+
if (custom.index === 0) {
|
|
3823
|
+
buttons.push(custom.button);
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
buttons.push(confirmBtn);
|
|
3827
|
+
for (const custom of customButtonsArray) {
|
|
3828
|
+
if (custom.index === 1) {
|
|
3829
|
+
buttons.push(custom.button);
|
|
3830
|
+
}
|
|
3831
|
+
}
|
|
3832
|
+
buttons.push(rejectBtn);
|
|
3833
|
+
for (const custom of customButtonsArray) {
|
|
3834
|
+
if (custom.index >= 2) {
|
|
3835
|
+
buttons.push(custom.button);
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
return new import_discord14.ActionRowBuilder({ components: buttons });
|
|
3839
|
+
}
|
|
3840
|
+
buildSendOptions(options) {
|
|
3841
|
+
const sendData = { ...options };
|
|
3842
|
+
if (this.container) {
|
|
3843
|
+
sendData.components = Array.isArray(sendData.components) ? [...sendData.components, this.container] : [this.container];
|
|
3844
|
+
const existingFlags = sendData.flags ? Array.isArray(sendData.flags) ? sendData.flags : [sendData.flags] : [];
|
|
3845
|
+
if (!existingFlags.includes("IsComponentsV2")) {
|
|
3846
|
+
sendData.flags = [...existingFlags, "IsComponentsV2"];
|
|
3847
|
+
} else {
|
|
3848
|
+
sendData.flags = existingFlags;
|
|
3849
|
+
}
|
|
3850
|
+
} else {
|
|
3851
|
+
sendData.embeds = Array.isArray(sendData.embeds) ? [this.embed, ...sendData.embeds] : [this.embed];
|
|
3852
|
+
}
|
|
3853
|
+
if (this.content) {
|
|
3854
|
+
sendData.content = this.content;
|
|
3855
|
+
}
|
|
3856
|
+
sendData.components = Array.isArray(sendData.components) ? [...sendData.components, this.buildActionRow()] : [this.buildActionRow()];
|
|
3857
|
+
return sendData;
|
|
3858
|
+
}
|
|
3859
|
+
isParticipant(userId) {
|
|
3860
|
+
if (this.participants.length === 0) return true;
|
|
3861
|
+
return this.participants.some((p) => {
|
|
3862
|
+
if (typeof p === "string") return p === userId;
|
|
3863
|
+
if (typeof p === "object" && "id" in p) return p.id === userId;
|
|
3864
|
+
return false;
|
|
3865
|
+
});
|
|
3866
|
+
}
|
|
3867
|
+
async handleResolve(confirmed) {
|
|
3868
|
+
if (!this.message) return;
|
|
3869
|
+
const shouldDelete = confirmed === true && this.onResolve.includes(3 /* DeleteOnConfirm */) || confirmed === false && this.onResolve.includes(4 /* DeleteOnReject */);
|
|
3870
|
+
if (shouldDelete) {
|
|
3871
|
+
await this.message.delete().catch(Boolean);
|
|
3872
|
+
return;
|
|
3873
|
+
}
|
|
3874
|
+
if (this.onResolve.includes(1 /* ClearComponents */)) {
|
|
3875
|
+
await this.message.edit({ components: [] }).catch(Boolean);
|
|
3876
|
+
} else if (this.onResolve.includes(0 /* DisableComponents */)) {
|
|
3877
|
+
const disableAll = { confirm: true, reject: true };
|
|
3878
|
+
for (const customId of this.customButtons.keys()) {
|
|
3879
|
+
disableAll[customId] = true;
|
|
3880
|
+
}
|
|
3881
|
+
await this.message.edit({ components: [this.buildActionRow(disableAll)] }).catch(Boolean);
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
async send(handler, options) {
|
|
3885
|
+
const sendData = this.buildSendOptions(options);
|
|
3886
|
+
this.message = await dynaSend(handler, sendData);
|
|
3887
|
+
return this.message;
|
|
3888
|
+
}
|
|
3889
|
+
async awaitResponse() {
|
|
3890
|
+
if (!this.message) {
|
|
3891
|
+
throw new Error("Prompt must be sent before awaiting response");
|
|
3892
|
+
}
|
|
3893
|
+
const validCustomIds = /* @__PURE__ */ new Set(["btn_confirm", "btn_reject", ...this.customButtons.keys()]);
|
|
3894
|
+
try {
|
|
3895
|
+
const interaction = await this.message.awaitMessageComponent({
|
|
3896
|
+
componentType: import_discord14.ComponentType.Button,
|
|
3897
|
+
filter: (i) => validCustomIds.has(i.customId) && this.isParticipant(i.user.id),
|
|
3898
|
+
time: this.timeout
|
|
3899
|
+
});
|
|
3900
|
+
await interaction.deferUpdate().catch(Boolean);
|
|
3901
|
+
let confirmed = null;
|
|
3902
|
+
if (interaction.customId === "btn_confirm") {
|
|
3903
|
+
confirmed = true;
|
|
3904
|
+
} else if (interaction.customId === "btn_reject") {
|
|
3905
|
+
confirmed = false;
|
|
3906
|
+
}
|
|
3907
|
+
const customButton = this.customButtons.get(interaction.customId);
|
|
3908
|
+
if (customButton?.handler) {
|
|
3909
|
+
await customButton.handler(interaction);
|
|
3910
|
+
}
|
|
3911
|
+
await this.handleResolve(confirmed);
|
|
3912
|
+
return {
|
|
3913
|
+
message: this.message,
|
|
3914
|
+
confirmed,
|
|
3915
|
+
customId: interaction.customId,
|
|
3916
|
+
timedOut: false
|
|
3917
|
+
};
|
|
3918
|
+
} catch (error) {
|
|
3919
|
+
await this.handleResolve(false);
|
|
3920
|
+
return {
|
|
3921
|
+
message: this.message,
|
|
3922
|
+
confirmed: null,
|
|
3923
|
+
customId: null,
|
|
3924
|
+
timedOut: true
|
|
3925
|
+
};
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
};
|
|
3929
|
+
async function prompt(handler, options, sendOptions) {
|
|
3930
|
+
const p = new Prompt(options);
|
|
3931
|
+
await p.send(handler, sendOptions);
|
|
3932
|
+
return await p.awaitResponse();
|
|
3933
|
+
}
|
|
3934
|
+
|
|
3935
|
+
// src/utils/VimcordCLI.ts
|
|
3936
|
+
var import_node_readline = require("readline");
|
|
3937
|
+
var import_jstools2 = __toESM(require("jstools"));
|
|
3938
|
+
var VimcordCLI = class {
|
|
3939
|
+
rl;
|
|
3940
|
+
options;
|
|
3941
|
+
commands = /* @__PURE__ */ new Map();
|
|
3942
|
+
logger = new Logger({ prefixEmoji: "\u{1F680}", prefix: "CLI", showTimestamp: false });
|
|
3943
|
+
constructor(options) {
|
|
3944
|
+
this.options = options;
|
|
3945
|
+
this.rl = (0, import_node_readline.createInterface)({
|
|
3946
|
+
input: process.stdin,
|
|
3947
|
+
output: process.stdout,
|
|
3948
|
+
terminal: false
|
|
3949
|
+
});
|
|
3950
|
+
this.rl.on("line", (line) => {
|
|
3951
|
+
const { isCommand, commandName, content, args } = this.parseLine(line);
|
|
3952
|
+
if (!isCommand) return;
|
|
3953
|
+
const command = this.commands.get(commandName);
|
|
3954
|
+
if (!command) {
|
|
3955
|
+
const nearestMatches = Array.from(this.commands.keys()).filter(
|
|
3956
|
+
(cmd) => cmd.toLowerCase().includes(commandName.toLowerCase())
|
|
3957
|
+
);
|
|
3958
|
+
return this.logger.error(
|
|
3959
|
+
`Unknown command '${commandName}'${nearestMatches.length ? `. Did you mean ${nearestMatches.length > 1 ? `[${nearestMatches.map((m) => `'${this.options.prefix}${m}'`).join(", ")}]` : `'${this.options.prefix}${nearestMatches[0]}'`}?` : ""}`
|
|
3960
|
+
);
|
|
3961
|
+
}
|
|
3962
|
+
command.fn(args, content);
|
|
3963
|
+
});
|
|
3964
|
+
}
|
|
3965
|
+
parseLine(line) {
|
|
3966
|
+
if (line.startsWith(this.options.prefix)) {
|
|
3967
|
+
line = line.slice(this.options.prefix.length);
|
|
3968
|
+
} else {
|
|
3969
|
+
return { isCommand: false };
|
|
3970
|
+
}
|
|
3971
|
+
const args = line.split(" ").map((s) => s.trim());
|
|
3972
|
+
const commandName = args.shift();
|
|
3973
|
+
return { isCommand: true, commandName, content: args.join(" "), args };
|
|
3974
|
+
}
|
|
3975
|
+
getClientInstance(line) {
|
|
3976
|
+
const clientIndex = import_jstools2.default.getFlagSubstring(line, "--client", 1) || import_jstools2.default.getFlagSubstring(line, "-c", 1);
|
|
3977
|
+
if (clientIndex) {
|
|
3978
|
+
const idx = Number(clientIndex);
|
|
3979
|
+
if (isNaN(idx)) {
|
|
3980
|
+
CLI.logger.error(`'${clientIndex}' is not a valid number`);
|
|
3981
|
+
return void 0;
|
|
3982
|
+
}
|
|
3983
|
+
const client = clientInstances[idx];
|
|
3984
|
+
if (!client) {
|
|
3985
|
+
CLI.logger.error("Client instance not found");
|
|
3986
|
+
return void 0;
|
|
3987
|
+
}
|
|
3988
|
+
return client;
|
|
3989
|
+
} else {
|
|
3990
|
+
const client = clientInstances[0];
|
|
3991
|
+
if (!client) {
|
|
3992
|
+
CLI.logger.error("Client instance not found");
|
|
3993
|
+
return void 0;
|
|
3994
|
+
}
|
|
3995
|
+
return client;
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
addCommand(commandName, description, fn) {
|
|
3999
|
+
this.commands.set(commandName, { description, fn });
|
|
4000
|
+
}
|
|
4001
|
+
removeCommand(commandName) {
|
|
4002
|
+
if (!this.commands.has(commandName)) return false;
|
|
4003
|
+
this.commands.delete(commandName);
|
|
4004
|
+
return true;
|
|
4005
|
+
}
|
|
4006
|
+
};
|
|
4007
|
+
var initCalled = false;
|
|
4008
|
+
var CLI = new VimcordCLI({ prefix: "/" });
|
|
4009
|
+
CLI.addCommand("help", "View information about a command, or the available CLI options", (args) => {
|
|
4010
|
+
const prefix = CLI.options.prefix;
|
|
4011
|
+
const helpList = {};
|
|
4012
|
+
for (const cmd of CLI.commands.entries()) {
|
|
4013
|
+
const commandName = cmd[0];
|
|
4014
|
+
const commandDescription = cmd[1].description;
|
|
4015
|
+
helpList[`${prefix}${commandName}`] = `~ ${commandDescription}`;
|
|
4016
|
+
}
|
|
4017
|
+
CLI.logger.table("(help)", helpList);
|
|
4018
|
+
});
|
|
4019
|
+
CLI.addCommand("register", "Register app commands globally, or per guild", async (args, content) => {
|
|
4020
|
+
const client = CLI.getClientInstance(content);
|
|
4021
|
+
if (!client) return;
|
|
4022
|
+
const mode = args[0]?.toLowerCase() || "";
|
|
4023
|
+
if (!["guild", "global"].includes(mode)) {
|
|
4024
|
+
return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
|
|
4025
|
+
}
|
|
4026
|
+
let guildIds = (import_jstools2.default.getFlagSubstring(content, "--guilds", 1) || import_jstools2.default.getFlagSubstring(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
|
|
4027
|
+
if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
|
|
4028
|
+
switch (mode) {
|
|
4029
|
+
case "guild":
|
|
4030
|
+
await client.commands.slash.registerGuild({ guilds: guildIds });
|
|
4031
|
+
break;
|
|
4032
|
+
case "global":
|
|
4033
|
+
await client.commands.slash.registerGlobal();
|
|
4034
|
+
break;
|
|
4035
|
+
}
|
|
4036
|
+
});
|
|
4037
|
+
CLI.addCommand("unregister", "Unregister app commands globally, or per guild", async (args, content) => {
|
|
4038
|
+
const client = CLI.getClientInstance(content);
|
|
4039
|
+
if (!client) return;
|
|
4040
|
+
const mode = args[0]?.toLowerCase() || "";
|
|
4041
|
+
if (!["guild", "global"].includes(mode)) {
|
|
4042
|
+
return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
|
|
4043
|
+
}
|
|
4044
|
+
let guildIds = (import_jstools2.default.getFlagSubstring(content, "--guilds", 1) || import_jstools2.default.getFlagSubstring(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
|
|
4045
|
+
if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
|
|
4046
|
+
switch (mode) {
|
|
4047
|
+
case "guild":
|
|
4048
|
+
await client.commands.slash.unregisterGuild({ guilds: guildIds });
|
|
4049
|
+
break;
|
|
4050
|
+
case "global":
|
|
4051
|
+
await client.commands.slash.unregisterGlobal();
|
|
4052
|
+
break;
|
|
4053
|
+
}
|
|
4054
|
+
});
|
|
4055
|
+
CLI.addCommand("stats", "View statistics about a client instance", (args, content) => {
|
|
4056
|
+
const client = CLI.getClientInstance(content);
|
|
4057
|
+
if (!client) return;
|
|
4058
|
+
CLI.logger.table(`(stats) ~ ${client.config.app.name}`, {
|
|
4059
|
+
"Guilds:": import_jstools2.default.formatThousands(client.guilds.cache.size),
|
|
4060
|
+
"Ping:": `${client.ws.ping || 0}ms`,
|
|
4061
|
+
"Uptime:": `${import_jstools2.default.msToSec(client.uptime || 0)}s`,
|
|
4062
|
+
"Process Uptime:": `${Math.floor(process.uptime())}s`,
|
|
4063
|
+
"Memory Usage:": `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`
|
|
4064
|
+
});
|
|
4065
|
+
});
|
|
4066
|
+
CLI.addCommand("cmds", "List the loaded commands", (args, content) => {
|
|
4067
|
+
const client = CLI.getClientInstance(content);
|
|
4068
|
+
if (!client) return;
|
|
4069
|
+
const mode = args[0] || "slash";
|
|
4070
|
+
switch (mode) {
|
|
4071
|
+
case "slash":
|
|
4072
|
+
const slashCommands = Array.from(client.commands.slash.commands.values());
|
|
4073
|
+
slashCommands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
|
|
4074
|
+
const slashCommands_f = {};
|
|
4075
|
+
for (const cmd of slashCommands) {
|
|
4076
|
+
slashCommands_f[`/${cmd.builder.name}`] = `~ ${cmd.builder.description || "No description"}`;
|
|
4077
|
+
}
|
|
4078
|
+
return CLI.logger.table(
|
|
4079
|
+
`(cmds) ~ slash (${import_jstools2.default.formatThousands(client.commands.slash.commands.size)})`,
|
|
4080
|
+
slashCommands_f
|
|
4081
|
+
);
|
|
4082
|
+
case "prefix":
|
|
4083
|
+
const prefixCommands = Array.from(client.commands.prefix.commands.values());
|
|
4084
|
+
prefixCommands.sort((a, b) => a.name.localeCompare(b.name));
|
|
4085
|
+
const prefixCommands_f = {};
|
|
4086
|
+
for (const cmd of prefixCommands) {
|
|
4087
|
+
prefixCommands_f[`${client.config.prefixCommands.defaultPrefix}${cmd.name}`] = `~ ${cmd.description || "No description"}`;
|
|
4088
|
+
}
|
|
4089
|
+
return CLI.logger.table(
|
|
4090
|
+
`(cmds) ~ prefix (${import_jstools2.default.formatThousands(client.commands.prefix.commands.size)})`,
|
|
4091
|
+
prefixCommands_f
|
|
4092
|
+
);
|
|
4093
|
+
case "ctx":
|
|
4094
|
+
const contextCommands = Array.from(client.commands.context.commands.values());
|
|
4095
|
+
contextCommands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
|
|
4096
|
+
const contextCommands_f = {};
|
|
4097
|
+
for (const cmd of contextCommands) {
|
|
4098
|
+
contextCommands_f[`${cmd.builder.name}`] = "";
|
|
4099
|
+
}
|
|
4100
|
+
return CLI.logger.table(
|
|
4101
|
+
`(cmds) ~ ctx (${import_jstools2.default.formatThousands(client.commands.context.commands.size)})`,
|
|
4102
|
+
contextCommands_f
|
|
4103
|
+
);
|
|
4104
|
+
default:
|
|
4105
|
+
return CLI.logger.error(`'${mode}' is not a valid option. Your options are [slash|prefix|ctx]`);
|
|
4106
|
+
}
|
|
4107
|
+
});
|
|
4108
|
+
function initCLI() {
|
|
4109
|
+
if (initCalled) return;
|
|
4110
|
+
CLI.logger.log(`~ Type ${CLI.options.prefix}help to view available commands`);
|
|
4111
|
+
initCalled = true;
|
|
4112
|
+
}
|
|
4113
|
+
|
|
4114
|
+
// src/utils/clientUtils.ts
|
|
4115
|
+
function useClient(index = 0) {
|
|
4116
|
+
return clientInstances.at(index);
|
|
4117
|
+
}
|
|
4118
|
+
async function useReadyClient(index = 0) {
|
|
4119
|
+
return useClient(index)?.whenReady();
|
|
4120
|
+
}
|
|
4121
|
+
function createClient(options, features = {}, config = {}) {
|
|
4122
|
+
const client = new Vimcord(options, features, config);
|
|
4123
|
+
initCLI();
|
|
4124
|
+
return client;
|
|
4125
|
+
}
|
|
4126
|
+
function getClientInstances() {
|
|
4127
|
+
return clientInstances;
|
|
4128
|
+
}
|
|
4129
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
4130
|
+
0 && (module.exports = {
|
|
4131
|
+
BaseCommandBuilder,
|
|
4132
|
+
BetterContainer,
|
|
4133
|
+
BetterEmbed,
|
|
4134
|
+
BetterModal,
|
|
4135
|
+
CLI,
|
|
4136
|
+
CommandType,
|
|
4137
|
+
ContextCommandBuilder,
|
|
4138
|
+
DynaSend,
|
|
4139
|
+
EventBuilder,
|
|
4140
|
+
LogLevel,
|
|
4141
|
+
Logger,
|
|
4142
|
+
MissingPermissionReason,
|
|
4143
|
+
MongoDatabase,
|
|
4144
|
+
MongoSchemaBuilder,
|
|
4145
|
+
PaginationTimeoutType,
|
|
4146
|
+
PaginationType,
|
|
4147
|
+
Paginator,
|
|
4148
|
+
PrefixCommandBuilder,
|
|
4149
|
+
Prompt,
|
|
4150
|
+
PromptResolveType,
|
|
4151
|
+
RateLimitScope,
|
|
4152
|
+
SendMethod,
|
|
4153
|
+
SlashCommandBuilder,
|
|
4154
|
+
StatusType,
|
|
4155
|
+
Vimcord,
|
|
4156
|
+
VimcordCLI,
|
|
4157
|
+
VimcordCommandManager,
|
|
4158
|
+
VimcordContextCommandManager,
|
|
4159
|
+
VimcordEventManager,
|
|
4160
|
+
VimcordPrefixCommandManager,
|
|
4161
|
+
VimcordSlashCommandManager,
|
|
4162
|
+
VimcordStatusManager,
|
|
4163
|
+
__zero,
|
|
4164
|
+
cleanMention,
|
|
4165
|
+
clientInstances,
|
|
4166
|
+
createClient,
|
|
4167
|
+
createMongoSchema,
|
|
4168
|
+
createToolsConfig,
|
|
4169
|
+
createVimcordAppConfig,
|
|
4170
|
+
createVimcordContextCommandConfig,
|
|
4171
|
+
createVimcordPrefixCommandConfig,
|
|
4172
|
+
createVimcordSlashCommandConfig,
|
|
4173
|
+
createVimcordStaffConfig,
|
|
4174
|
+
createVimcordStatusConfig,
|
|
4175
|
+
defineGlobalToolsConfig,
|
|
4176
|
+
dynaSend,
|
|
4177
|
+
fetchChannel,
|
|
4178
|
+
fetchGuild,
|
|
4179
|
+
fetchMember,
|
|
4180
|
+
fetchMessage,
|
|
4181
|
+
fetchRole,
|
|
4182
|
+
fetchUser,
|
|
4183
|
+
formatThousands,
|
|
4184
|
+
getCallerFileName,
|
|
4185
|
+
getClientInstances,
|
|
4186
|
+
getFirstMentionId,
|
|
4187
|
+
getMessageMention,
|
|
4188
|
+
getProcessDir,
|
|
4189
|
+
globalVimcordToolsConfig,
|
|
4190
|
+
importModulesFromDir,
|
|
4191
|
+
initCLI,
|
|
4192
|
+
isMentionOrSnowflake,
|
|
4193
|
+
logger,
|
|
4194
|
+
pickRandom,
|
|
4195
|
+
prompt,
|
|
4196
|
+
retryExponentialBackoff,
|
|
4197
|
+
sendCommandErrorEmbed,
|
|
4198
|
+
useClient,
|
|
4199
|
+
useMongoDatabase,
|
|
4200
|
+
useReadyClient,
|
|
4201
|
+
validateCommandPermissions
|
|
4202
|
+
});
|
|
4203
|
+
//# sourceMappingURL=index.cjs.map
|