@carzo/enire 3.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/README.md +57 -0
- package/lib/classes/Client.d.ts +37 -0
- package/lib/classes/Client.js +125 -0
- package/lib/classes/Context.d.ts +24 -0
- package/lib/classes/Context.js +87 -0
- package/lib/classes/Cooldowns.d.ts +22 -0
- package/lib/classes/Cooldowns.js +1 -0
- package/lib/classes/Errors.d.ts +135 -0
- package/lib/classes/Errors.js +1 -0
- package/lib/classes/HelpCommand.d.ts +15 -0
- package/lib/classes/HelpCommand.js +1 -0
- package/lib/classes/Loader.d.ts +85 -0
- package/lib/classes/Loader.js +302 -0
- package/lib/classes/Plugins.d.ts +52 -0
- package/lib/classes/Plugins.js +107 -0
- package/lib/classes/Utils.d.ts +25 -0
- package/lib/classes/Utils.js +563 -0
- package/lib/classes/builders/CommandBuilder.d.ts +44 -0
- package/lib/classes/builders/CommandBuilder.js +91 -0
- package/lib/classes/builders/EventBuilder.d.ts +19 -0
- package/lib/classes/builders/EventBuilder.js +1 -0
- package/lib/classes/builders/GroupBuilder.d.ts +40 -0
- package/lib/classes/builders/GroupBuilder.js +72 -0
- package/lib/classes/builders/InteractionBuilder.d.ts +32 -0
- package/lib/classes/builders/InteractionBuilder.js +1 -0
- package/lib/classes/builders/ParamsBuilder.d.ts +87 -0
- package/lib/classes/builders/ParamsBuilder.js +1 -0
- package/lib/classes/experiments/Confirmator.d.ts +58 -0
- package/lib/classes/experiments/Confirmator.js +1 -0
- package/lib/classes/experiments/Paginator.d.ts +65 -0
- package/lib/classes/experiments/Paginator.js +1 -0
- package/lib/events/interactionCreate.d.ts +4 -0
- package/lib/events/interactionCreate.js +17 -0
- package/lib/events/messageCreate.d.ts +4 -0
- package/lib/events/messageCreate.js +17 -0
- package/lib/events/messageUpdate.d.ts +4 -0
- package/lib/events/messageUpdate.js +17 -0
- package/lib/experiments.d.ts +2 -0
- package/lib/experiments.js +1 -0
- package/lib/main.d.ts +15 -0
- package/lib/main.js +22 -0
- package/package.json +55 -0
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Utils = void 0;
|
|
4
|
+
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const types_1 = require("util/types");
|
|
7
|
+
const DJS = tslib_1.__importStar(require("discord.js"));
|
|
8
|
+
const Errors = tslib_1.__importStar(require("./Errors.js"));
|
|
9
|
+
const Cooldowns_js_1 = require("./Cooldowns.js");
|
|
10
|
+
|
|
11
|
+
class Utils {
|
|
12
|
+
static isType(obj, func) {
|
|
13
|
+
return func(obj);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static noop(n = null) {
|
|
17
|
+
return n;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static async getMember(query, options) {
|
|
21
|
+
if (!query || !options?.guild) return null;
|
|
22
|
+
|
|
23
|
+
const id = query.replace(/[^\d]/g, "");
|
|
24
|
+
let member = id ? options.guild.members.cache.get(id) : null;
|
|
25
|
+
|
|
26
|
+
member =
|
|
27
|
+
member ||
|
|
28
|
+
options.guild.members.cache.find(
|
|
29
|
+
(target) =>
|
|
30
|
+
target.user.username.toLowerCase() === query.toLowerCase() ||
|
|
31
|
+
target.user.globalName?.toLowerCase() === query.toLowerCase() ||
|
|
32
|
+
target.user.username.toLowerCase().includes(query.toLowerCase())
|
|
33
|
+
) ||
|
|
34
|
+
null;
|
|
35
|
+
|
|
36
|
+
if (!member && id && options.force) {
|
|
37
|
+
member = (await options.guild.members.fetch(id).catch(Utils.noop)) || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return member;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static async getChannel(query, options) {
|
|
44
|
+
if (!query || !options?.guild) return null;
|
|
45
|
+
|
|
46
|
+
const id = query.replace(/[^\d]/g, "");
|
|
47
|
+
let channel = id ? options.guild.channels.cache.get(id) : null;
|
|
48
|
+
|
|
49
|
+
channel =
|
|
50
|
+
channel ||
|
|
51
|
+
options.guild.channels.cache.find(
|
|
52
|
+
(target) => target.name.toLowerCase() === query.toLowerCase() || target.name.toLowerCase().includes(query.toLowerCase())
|
|
53
|
+
) ||
|
|
54
|
+
null;
|
|
55
|
+
|
|
56
|
+
if (!channel && id && options.force) {
|
|
57
|
+
channel = (await options.guild.channels.fetch(id).catch(Utils.noop)) || null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return channel;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static async getRole(query, options) {
|
|
64
|
+
if (!query || !options?.guild) return null;
|
|
65
|
+
|
|
66
|
+
const id = query.replace(/[^\d]/g, "");
|
|
67
|
+
let role = id ? options.guild.roles.cache.get(id) : null;
|
|
68
|
+
|
|
69
|
+
role =
|
|
70
|
+
role ||
|
|
71
|
+
options.guild.roles.cache.find(
|
|
72
|
+
(target) => target.name.toLowerCase() === query.toLowerCase() || target.name.toLowerCase().includes(query.toLowerCase())
|
|
73
|
+
) ||
|
|
74
|
+
null;
|
|
75
|
+
|
|
76
|
+
if (!role && id && options.force) {
|
|
77
|
+
role = (await options.guild.roles.fetch(id).catch(Utils.noop)) || null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return role;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static async getUser(query, bot) {
|
|
84
|
+
if (!query) return null;
|
|
85
|
+
|
|
86
|
+
const id = query.replace(/[^\d]/g, "");
|
|
87
|
+
|
|
88
|
+
const cached =
|
|
89
|
+
(id ? bot.users.cache.get(id) : null) ||
|
|
90
|
+
bot.users.cache.find(
|
|
91
|
+
(user) =>
|
|
92
|
+
user.globalName?.toLowerCase() === query.toLowerCase() ||
|
|
93
|
+
user.username.toLowerCase() === query.toLowerCase() ||
|
|
94
|
+
user.id === query
|
|
95
|
+
) ||
|
|
96
|
+
null;
|
|
97
|
+
|
|
98
|
+
if (cached) return cached;
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
return await bot.users.fetch(id || query);
|
|
102
|
+
} catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
static #cloneParams(paramsBuilder) {
|
|
108
|
+
if (!paramsBuilder?.params?.length) return [];
|
|
109
|
+
return paramsBuilder.params.map((param) => ({ ...param, value: undefined }));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
static async transform(input, param, ctx, seeable = true) {
|
|
113
|
+
if (!input && seeable) {
|
|
114
|
+
return { break: false, value: null };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (param.choices?.length) {
|
|
118
|
+
const selected = param.choices.find((choice) => choice.name.toLowerCase() === String(input).toLowerCase());
|
|
119
|
+
if (selected) return { break: false, value: selected.value };
|
|
120
|
+
throw new Errors.InvalidParamChoice(ctx, param, param.choices);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (param.type === DJS.ApplicationCommandOptionType.String) {
|
|
124
|
+
const value = String(input ?? "");
|
|
125
|
+
|
|
126
|
+
if (typeof param.max_length === "number" && value.length > param.max_length) {
|
|
127
|
+
throw new Errors.InvalidParam(ctx, `${param.name} exceeds max length.`, { param });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (typeof param.min_length === "number" && value.length < param.min_length) {
|
|
131
|
+
throw new Errors.InvalidParam(ctx, `${param.name} is under min length.`, { param });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return { break: false, value };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (param.type === DJS.ApplicationCommandOptionType.Number) {
|
|
138
|
+
const value = Number(input);
|
|
139
|
+
if (Number.isNaN(value)) throw new Errors.InvalidParamNumber(ctx, param);
|
|
140
|
+
|
|
141
|
+
if (typeof param.max_value === "number" && value > param.max_value) {
|
|
142
|
+
throw new Errors.InvalidParam(ctx, `${param.name} exceeds max value.`, { param });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (typeof param.min_value === "number" && value < param.min_value) {
|
|
146
|
+
throw new Errors.InvalidParam(ctx, `${param.name} is under min value.`, { param });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return { break: false, value };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (param.type === DJS.ApplicationCommandOptionType.Boolean) {
|
|
153
|
+
const lowered = String(input).toLowerCase();
|
|
154
|
+
if (lowered !== "true" && lowered !== "false") throw new Errors.InvalidParamBoolean(ctx, param);
|
|
155
|
+
return { break: false, value: lowered === "true" };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (param.type === DJS.ApplicationCommandOptionType.User) {
|
|
159
|
+
const member = ctx.guild ? await Utils.getMember(String(input), { guild: ctx.guild, force: true }) : await Utils.getUser(String(input), ctx.bot);
|
|
160
|
+
if (member) return { break: false, value: member };
|
|
161
|
+
throw new Errors.InvalidParamMember(ctx, param);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (param.type === DJS.ApplicationCommandOptionType.Channel) {
|
|
165
|
+
const channel = await Utils.getChannel(String(input), { guild: ctx.guild, force: true });
|
|
166
|
+
if (!channel) throw new Errors.InvalidParamChannel(ctx, param);
|
|
167
|
+
|
|
168
|
+
if (param.channel_types?.length && !param.channel_types.includes(channel.type)) {
|
|
169
|
+
throw new Errors.InvalidChannelType(ctx, param, channel.type, param.channel_types);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return { break: false, value: channel };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (param.type === DJS.ApplicationCommandOptionType.Role) {
|
|
176
|
+
const role = await Utils.getRole(String(input), { guild: ctx.guild, force: true });
|
|
177
|
+
if (role) return { break: false, value: role };
|
|
178
|
+
throw new Errors.InvalidParamRole(ctx, param);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (param.type === DJS.ApplicationCommandOptionType.Attachment) {
|
|
182
|
+
const attachment = ctx.message?.attachments?.first();
|
|
183
|
+
if (!attachment && param.required) throw new Errors.InvalidParamAttachment(ctx, param);
|
|
184
|
+
return { break: false, value: attachment };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return { break: false, value: input ?? null };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
static async #resolvePrefixParams(ctx, command, args) {
|
|
191
|
+
const params = Utils.#cloneParams(command.params);
|
|
192
|
+
if (!params.length) {
|
|
193
|
+
ctx.params = [];
|
|
194
|
+
ctx.args = args;
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let argIndex = 0;
|
|
199
|
+
|
|
200
|
+
for (let paramIndex = 0; paramIndex < params.length; paramIndex += 1) {
|
|
201
|
+
const param = params[paramIndex];
|
|
202
|
+
|
|
203
|
+
if (param.type === DJS.ApplicationCommandOptionType.Attachment) {
|
|
204
|
+
const transformed = await Utils.transform("", param, ctx, false);
|
|
205
|
+
param.value = transformed.value;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (param.ellipsis) {
|
|
210
|
+
const remaining = args.slice(argIndex).join(" ").trim();
|
|
211
|
+
|
|
212
|
+
if (!remaining && param.required) {
|
|
213
|
+
throw new Errors.MissingRequiredParam(ctx, param);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (remaining) {
|
|
217
|
+
const transformed = await Utils.transform(remaining, param, ctx);
|
|
218
|
+
param.value = transformed.value;
|
|
219
|
+
argIndex = args.length;
|
|
220
|
+
} else {
|
|
221
|
+
param.value = null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const raw = args[argIndex];
|
|
228
|
+
if ((raw === undefined || raw === null || raw === "") && param.required) {
|
|
229
|
+
throw new Errors.MissingRequiredParam(ctx, param);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (raw === undefined || raw === null || raw === "") {
|
|
233
|
+
param.value = null;
|
|
234
|
+
} else {
|
|
235
|
+
const transformed = await Utils.transform(raw, param, ctx);
|
|
236
|
+
param.value = transformed.value;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
argIndex += 1;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
ctx.params = params;
|
|
243
|
+
ctx.args = args;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
static #resolveInteractionParamValue(interaction, param) {
|
|
247
|
+
const name = param.name;
|
|
248
|
+
|
|
249
|
+
switch (param.type) {
|
|
250
|
+
case DJS.ApplicationCommandOptionType.String:
|
|
251
|
+
return interaction.options.getString(name, !!param.required);
|
|
252
|
+
case DJS.ApplicationCommandOptionType.Number:
|
|
253
|
+
return interaction.options.getNumber(name, !!param.required);
|
|
254
|
+
case DJS.ApplicationCommandOptionType.Boolean:
|
|
255
|
+
return interaction.options.getBoolean(name, !!param.required);
|
|
256
|
+
case DJS.ApplicationCommandOptionType.User:
|
|
257
|
+
return interaction.options.getMember(name) ?? interaction.options.getUser(name, !!param.required);
|
|
258
|
+
case DJS.ApplicationCommandOptionType.Channel:
|
|
259
|
+
return interaction.options.getChannel(name, !!param.required);
|
|
260
|
+
case DJS.ApplicationCommandOptionType.Role:
|
|
261
|
+
return interaction.options.getRole(name, !!param.required);
|
|
262
|
+
case DJS.ApplicationCommandOptionType.Attachment:
|
|
263
|
+
return interaction.options.getAttachment(name, !!param.required);
|
|
264
|
+
default:
|
|
265
|
+
return interaction.options.get(name)?.value ?? null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
static async #resolveInteractionParams(ctx, command, interaction) {
|
|
270
|
+
const params = Utils.#cloneParams(command.params);
|
|
271
|
+
|
|
272
|
+
for (const param of params) {
|
|
273
|
+
const value = Utils.#resolveInteractionParamValue(interaction, param);
|
|
274
|
+
|
|
275
|
+
if ((value === null || value === undefined) && param.required) {
|
|
276
|
+
throw new Errors.MissingRequiredParam(ctx, param);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
param.value = value ?? null;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
ctx.params = params;
|
|
283
|
+
ctx.args = null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
static async #runPlugins(ctx, command) {
|
|
287
|
+
const plugins = [...(command.plugins ?? []), ...ctx.bot.loader.globalPlugins];
|
|
288
|
+
|
|
289
|
+
for (const plugin of plugins) {
|
|
290
|
+
if ((0, types_1.isPromise)(plugin)) {
|
|
291
|
+
const resolved = await plugin;
|
|
292
|
+
if (!(await resolved(ctx))) return false;
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (!(await plugin(ctx))) return false;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
static async #runPredicates(ctx, predicates) {
|
|
303
|
+
for (const predicate of predicates) {
|
|
304
|
+
if (!predicate) continue;
|
|
305
|
+
if (!(await predicate(ctx))) return false;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
static #resolveCooldownSource(ctx, bucket) {
|
|
312
|
+
switch (bucket) {
|
|
313
|
+
case Cooldowns_js_1.Bucket.Guild:
|
|
314
|
+
return ctx.guild?.id || "-1";
|
|
315
|
+
case Cooldowns_js_1.Bucket.Member:
|
|
316
|
+
return ctx.guild ? `${ctx.guild.id}_${ctx.author.id}` : ctx.author.id;
|
|
317
|
+
case Cooldowns_js_1.Bucket.Channel:
|
|
318
|
+
return ctx.channel?.id || "-1";
|
|
319
|
+
case Cooldowns_js_1.Bucket.User:
|
|
320
|
+
default:
|
|
321
|
+
return ctx.author.id;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
static async #applyCooldown(ctx, command) {
|
|
326
|
+
const cooldown = command?.data?.cooldown;
|
|
327
|
+
if (!cooldown?.seconds || cooldown.seconds <= 0) return;
|
|
328
|
+
|
|
329
|
+
const bucket = cooldown.bucket || Cooldowns_js_1.Bucket.User;
|
|
330
|
+
const source = Utils.#resolveCooldownSource(ctx, bucket);
|
|
331
|
+
const cooldownMs = cooldown.seconds * 1000;
|
|
332
|
+
|
|
333
|
+
const active = await ctx.bot.cooldowns.check(command.data.name, source, cooldownMs, bucket);
|
|
334
|
+
if (active) throw new Errors.CommandInCooldown(ctx, active.left);
|
|
335
|
+
|
|
336
|
+
await ctx.bot.cooldowns.setCooldownSource(command.data.name, source, bucket, cooldownMs);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
static async executeCommand(ctx, command, options) {
|
|
340
|
+
const { group = null, source, args = null, interaction = null, prefix = "" } = options;
|
|
341
|
+
|
|
342
|
+
if (ctx.bot.ops.guildOnly && !ctx.guild) {
|
|
343
|
+
throw new Errors.GuildOnly(ctx);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (command.data.guildOnly === true && !ctx.guild) {
|
|
347
|
+
throw new Errors.GuildOnly(ctx, "This command is only available in guilds.");
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (group?.data?.guildOnly === true && !ctx.guild) {
|
|
351
|
+
throw new Errors.GuildOnly(ctx, "This command group is only available in guilds.");
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
ctx.command = command;
|
|
355
|
+
ctx.parent = group;
|
|
356
|
+
ctx.prefix = prefix;
|
|
357
|
+
|
|
358
|
+
const canRunPlugins = await Utils.#runPlugins(ctx, command);
|
|
359
|
+
if (!canRunPlugins) return;
|
|
360
|
+
|
|
361
|
+
const canRunGuards = await Utils.#runPredicates(ctx, [...(group?.data?.guards ?? []), ...(command.data?.guards ?? [])]);
|
|
362
|
+
if (!canRunGuards) return;
|
|
363
|
+
|
|
364
|
+
await Utils.#applyCooldown(ctx, command);
|
|
365
|
+
|
|
366
|
+
if (source === "prefix") {
|
|
367
|
+
await Utils.#resolvePrefixParams(ctx, command, args ?? []);
|
|
368
|
+
} else {
|
|
369
|
+
await Utils.#resolveInteractionParams(ctx, command, interaction);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
await command.code(ctx);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
static async #resolvePrefix(bot, ctx, message) {
|
|
376
|
+
if (typeof bot.ops.prefix === "string") {
|
|
377
|
+
if (!message.content.toLowerCase().startsWith(bot.ops.prefix.toLowerCase())) return null;
|
|
378
|
+
return bot.ops.prefix;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (Array.isArray(bot.ops.prefix)) {
|
|
382
|
+
return bot.ops.prefix.find((prefix) => message.content.toLowerCase().startsWith(prefix.toLowerCase())) || null;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if ((0, types_1.isAsyncFunction)(bot.ops.prefix) || typeof bot.ops.prefix === "function") {
|
|
386
|
+
const resolved = await bot.ops.prefix(ctx);
|
|
387
|
+
if (!resolved) return null;
|
|
388
|
+
if (!message.content.toLowerCase().startsWith(resolved.toLowerCase())) return null;
|
|
389
|
+
return resolved;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
static #matchAlias(target, value) {
|
|
396
|
+
const lowered = value.toLowerCase();
|
|
397
|
+
return target.data.name.toLowerCase() === lowered || (target.data.aliases || []).map((alias) => alias.toLowerCase()).includes(lowered);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
static #findPrefixCommand(bot, trigger, args) {
|
|
401
|
+
const normal =
|
|
402
|
+
bot.loader.commands.normal?.find((command) => Utils.#matchAlias(command, trigger) && command.data.as_prefix) || null;
|
|
403
|
+
|
|
404
|
+
const group =
|
|
405
|
+
bot.loader.commands.group?.find((entry) => Utils.#matchAlias(entry, trigger) && entry.data.as_prefix) || null;
|
|
406
|
+
|
|
407
|
+
if (group) {
|
|
408
|
+
const maybeSub = (args.shift() || "").toLowerCase();
|
|
409
|
+
const sub =
|
|
410
|
+
group.data.commands.find((command) => Utils.#matchAlias(command, maybeSub) && command.data.as_prefix) ||
|
|
411
|
+
group.data.commands.find((command) => command.data.fallback && command.data.as_prefix) ||
|
|
412
|
+
null;
|
|
413
|
+
|
|
414
|
+
if (sub) return { command: sub, group, args };
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (normal) return { command: normal, group: null, args };
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
static async handleMessage(bot, message, isEdit = false) {
|
|
422
|
+
if (!message || !message.content || message.author?.bot) return;
|
|
423
|
+
|
|
424
|
+
const ctx = bot.getContext(message);
|
|
425
|
+
|
|
426
|
+
if (bot.ops.restrictions?.guildIDs?.has(String(message.guild?.id))) {
|
|
427
|
+
throw new Errors.RestrictedGuild(ctx, message.guild);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (bot.ops.restrictions?.userIDs?.has(message.author.id)) {
|
|
431
|
+
throw new Errors.RestrictedUser(ctx, message.author);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const prefix = await Utils.#resolvePrefix(bot, ctx, message);
|
|
435
|
+
if (!prefix) return;
|
|
436
|
+
|
|
437
|
+
const body = message.content.slice(prefix.length).trim();
|
|
438
|
+
if (!body.length) return;
|
|
439
|
+
|
|
440
|
+
const tokens = Utils.splitArgs(body);
|
|
441
|
+
const trigger = (tokens.shift() || "").toLowerCase();
|
|
442
|
+
if (!trigger) return;
|
|
443
|
+
|
|
444
|
+
const resolved = Utils.#findPrefixCommand(bot, trigger, tokens);
|
|
445
|
+
if (!resolved) return;
|
|
446
|
+
|
|
447
|
+
await Utils.executeCommand(ctx, resolved.command, {
|
|
448
|
+
group: resolved.group,
|
|
449
|
+
source: "prefix",
|
|
450
|
+
args: resolved.args,
|
|
451
|
+
prefix,
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
static #findSlashCommand(bot, interaction) {
|
|
456
|
+
const subCommand = interaction.options.getSubcommand(false);
|
|
457
|
+
|
|
458
|
+
if (subCommand) {
|
|
459
|
+
const group = bot.loader.commands.group?.get(interaction.commandName) || null;
|
|
460
|
+
if (!group?.data?.as_slash) return null;
|
|
461
|
+
|
|
462
|
+
const command =
|
|
463
|
+
group.data.commands.find((entry) => entry.data.name === subCommand && entry.data.as_slash) ||
|
|
464
|
+
group.data.commands.find((entry) => entry.data.fallback && entry.data.as_slash) ||
|
|
465
|
+
null;
|
|
466
|
+
|
|
467
|
+
if (!command) return null;
|
|
468
|
+
return { command, group };
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const command = bot.loader.commands.normal?.find((entry) => entry.data.name === interaction.commandName && entry.data.as_slash) || null;
|
|
472
|
+
if (!command) return null;
|
|
473
|
+
|
|
474
|
+
return { command, group: null };
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
static #resolveInteractionModule(bot, interaction) {
|
|
478
|
+
if (interaction.isAutocomplete()) return bot.loader.interactions.autocomplete.get(interaction.commandName) || null;
|
|
479
|
+
if (interaction.isButton()) return bot.loader.interactions.button.get(interaction.customId) || null;
|
|
480
|
+
if (interaction.isModalSubmit()) return bot.loader.interactions.modalSubmit.get(interaction.customId) || null;
|
|
481
|
+
if (interaction.isMessageContextMenuCommand()) return bot.loader.interactions.messageContextMenu.get(interaction.commandName) || null;
|
|
482
|
+
if (interaction.isUserContextMenuCommand()) return bot.loader.interactions.userContextMenu.get(interaction.commandName) || null;
|
|
483
|
+
if (interaction.isChannelSelectMenu()) return bot.loader.interactions.channelSelectMenu.get(interaction.customId) || null;
|
|
484
|
+
if (interaction.isMentionableSelectMenu()) return bot.loader.interactions.mentionableSelectMenu.get(interaction.customId) || null;
|
|
485
|
+
if (interaction.isRoleSelectMenu()) return bot.loader.interactions.roleSelectMenu.get(interaction.customId) || null;
|
|
486
|
+
if (interaction.isStringSelectMenu()) return bot.loader.interactions.stringSelectMenu.get(interaction.customId) || null;
|
|
487
|
+
if (interaction.isUserSelectMenu()) return bot.loader.interactions.userSelectMenu.get(interaction.customId) || null;
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
static async handleInteraction(bot, interaction) {
|
|
492
|
+
const ctx = bot.getContext(interaction);
|
|
493
|
+
|
|
494
|
+
if (bot.ops.restrictions?.guildIDs?.has(String(interaction.guild?.id))) {
|
|
495
|
+
throw new Errors.RestrictedGuild(ctx, interaction.guild);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (bot.ops.restrictions?.userIDs?.has(interaction.user.id)) {
|
|
499
|
+
throw new Errors.RestrictedUser(ctx, interaction.user);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (interaction.isChatInputCommand()) {
|
|
503
|
+
const resolved = Utils.#findSlashCommand(bot, interaction);
|
|
504
|
+
if (!resolved) return;
|
|
505
|
+
|
|
506
|
+
await Utils.executeCommand(ctx, resolved.command, {
|
|
507
|
+
group: resolved.group,
|
|
508
|
+
source: "slash",
|
|
509
|
+
interaction,
|
|
510
|
+
prefix: "/",
|
|
511
|
+
});
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const matched = Utils.#resolveInteractionModule(bot, interaction);
|
|
516
|
+
if (matched) {
|
|
517
|
+
await matched.code?.(interaction);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
for (const callback of bot.loader.interactions.anyInteraction.values()) {
|
|
521
|
+
await callback.code?.(interaction);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
static async runPrefixCommand(ctx, command, args, group) {
|
|
526
|
+
await Utils.executeCommand(ctx, command, {
|
|
527
|
+
group: group || null,
|
|
528
|
+
source: "prefix",
|
|
529
|
+
args,
|
|
530
|
+
prefix: ctx.prefix,
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
static async runInteractionCommand(ctx, interaction) {
|
|
535
|
+
const resolved = Utils.#findSlashCommand(ctx.bot, interaction);
|
|
536
|
+
if (!resolved) return;
|
|
537
|
+
|
|
538
|
+
await Utils.executeCommand(ctx, resolved.command, {
|
|
539
|
+
group: resolved.group,
|
|
540
|
+
source: "slash",
|
|
541
|
+
interaction,
|
|
542
|
+
prefix: "/",
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
static splitArgs(text, special = true, removeNewLines = false) {
|
|
547
|
+
if (!special) {
|
|
548
|
+
return text.trim().split(/ +/g).filter(Boolean);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const regexp = /("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[\S]+)/gim;
|
|
552
|
+
const clean = text.replaceAll(/\r|\n/gm, removeNewLines ? "" : "#ER_BREAK_LINE#");
|
|
553
|
+
const args = [];
|
|
554
|
+
|
|
555
|
+
let match;
|
|
556
|
+
while ((match = regexp.exec(clean))) {
|
|
557
|
+
args.push(match[0].replace(/^(['"])(.*)\1$/, "$2").replace(/\\(.)/gim, "$1"));
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
return args.map((arg) => arg.replaceAll("#ER_BREAK_LINE#", "\n"));
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
exports.Utils = Utils;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare function validateDefaultMemberPermissions(permissions: unknown): string | null | undefined;
|
|
2
|
+
|
|
3
|
+
export interface CommandDataBuilder {
|
|
4
|
+
name: string;
|
|
5
|
+
aliases?: string[];
|
|
6
|
+
description?: string;
|
|
7
|
+
as_prefix?: boolean;
|
|
8
|
+
as_slash?: boolean;
|
|
9
|
+
fallback?: true;
|
|
10
|
+
guildOnly?: boolean;
|
|
11
|
+
multiple_args?: boolean;
|
|
12
|
+
defaultMemberPermissions?: string | bigint;
|
|
13
|
+
guards?: Array<(ctx: any) => boolean | Promise<boolean>>;
|
|
14
|
+
cooldown?: { seconds: number; bucket?: string };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export declare class CommandBuilder {
|
|
18
|
+
name: string;
|
|
19
|
+
aliases: string[];
|
|
20
|
+
description: string;
|
|
21
|
+
as_prefix: boolean;
|
|
22
|
+
as_slash: boolean;
|
|
23
|
+
fallback: boolean;
|
|
24
|
+
guildOnly: boolean | undefined;
|
|
25
|
+
multiple_args?: boolean;
|
|
26
|
+
defaultMemberPermissions?: string | bigint | undefined;
|
|
27
|
+
guards: Array<(ctx: any) => boolean | Promise<boolean>>;
|
|
28
|
+
cooldown?: { seconds: number; bucket?: string };
|
|
29
|
+
constructor(options?: CommandDataBuilder);
|
|
30
|
+
setName(name: string): CommandBuilder;
|
|
31
|
+
setDescription(description: string): CommandBuilder;
|
|
32
|
+
setAliases(...aliases: string[]): CommandBuilder;
|
|
33
|
+
allowPrefix(allow: boolean): CommandBuilder;
|
|
34
|
+
allowSlash(allow: boolean): CommandBuilder;
|
|
35
|
+
allowMultipleArgs(allow: boolean): CommandBuilder;
|
|
36
|
+
setGuards(...guards: Array<(ctx: any) => boolean | Promise<boolean>>): CommandBuilder;
|
|
37
|
+
setCooldown(seconds: number, bucket?: string): CommandBuilder;
|
|
38
|
+
toJSON(): {
|
|
39
|
+
name: string;
|
|
40
|
+
description: string;
|
|
41
|
+
default_member_permissions: string | null | undefined;
|
|
42
|
+
dm_permission: boolean | undefined;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CommandBuilder = exports.validateDefaultMemberPermissions = void 0;
|
|
4
|
+
|
|
5
|
+
const shapeshift_1 = require("@sapphire/shapeshift");
|
|
6
|
+
|
|
7
|
+
const memberPermissionPredicate = shapeshift_1.s
|
|
8
|
+
.union(shapeshift_1.s.bigint.transform((value) => value.toString()), shapeshift_1.s.number.safeInt.transform((value) => value.toString()), shapeshift_1.s.string.regex(/^\d+$/))
|
|
9
|
+
.nullish;
|
|
10
|
+
|
|
11
|
+
function validateDefaultMemberPermissions(permissions) {
|
|
12
|
+
return memberPermissionPredicate.parse(permissions);
|
|
13
|
+
}
|
|
14
|
+
exports.validateDefaultMemberPermissions = validateDefaultMemberPermissions;
|
|
15
|
+
|
|
16
|
+
class CommandBuilder {
|
|
17
|
+
name;
|
|
18
|
+
aliases;
|
|
19
|
+
description;
|
|
20
|
+
as_prefix;
|
|
21
|
+
as_slash;
|
|
22
|
+
fallback;
|
|
23
|
+
guildOnly;
|
|
24
|
+
multiple_args;
|
|
25
|
+
defaultMemberPermissions;
|
|
26
|
+
guards;
|
|
27
|
+
cooldown;
|
|
28
|
+
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.name = options?.name ?? "";
|
|
31
|
+
this.aliases = options?.aliases ?? [];
|
|
32
|
+
this.description = options?.description ?? "...";
|
|
33
|
+
this.fallback = options?.fallback ?? false;
|
|
34
|
+
this.as_prefix = options?.as_prefix ?? true;
|
|
35
|
+
this.as_slash = options?.as_slash ?? true;
|
|
36
|
+
this.guildOnly = options?.guildOnly;
|
|
37
|
+
this.defaultMemberPermissions = options?.defaultMemberPermissions;
|
|
38
|
+
this.guards = options?.guards ?? [];
|
|
39
|
+
this.cooldown = options?.cooldown;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setName(name) {
|
|
43
|
+
this.name = name;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
setDescription(description) {
|
|
48
|
+
this.description = description;
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
setAliases(...aliases) {
|
|
53
|
+
this.aliases = aliases;
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
allowPrefix(allow) {
|
|
58
|
+
this.as_prefix = allow;
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
allowSlash(allow) {
|
|
63
|
+
this.as_slash = allow;
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
allowMultipleArgs(allow) {
|
|
68
|
+
this.multiple_args = allow;
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
setGuards(...guards) {
|
|
73
|
+
this.guards = guards;
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
setCooldown(seconds, bucket = "USER") {
|
|
78
|
+
this.cooldown = { seconds, bucket };
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
toJSON() {
|
|
83
|
+
return {
|
|
84
|
+
name: this.name,
|
|
85
|
+
description: this.description,
|
|
86
|
+
default_member_permissions: this.defaultMemberPermissions ? validateDefaultMemberPermissions(this.defaultMemberPermissions) : undefined,
|
|
87
|
+
dm_permission: typeof this.guildOnly === "boolean" ? !this.guildOnly : undefined,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.CommandBuilder = CommandBuilder;
|