seedcord 0.4.3 → 0.5.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 +1032 -348
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +740 -74
- package/dist/index.d.ts +740 -74
- package/dist/index.mjs +988 -345
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -7
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
import { Logger, ShutdownPhase, CoordinatedShutdown, CoordinatedStartup, HealthCheck, StartupPhase } from '@seedcord/services';
|
|
3
3
|
export * from '@seedcord/services';
|
|
4
|
-
import
|
|
5
|
-
import { SeparatorBuilder, SectionBuilder, MediaGalleryBuilder, FileBuilder, TextDisplayBuilder, ContainerBuilder,
|
|
4
|
+
import chalk4 from 'chalk';
|
|
5
|
+
import { SeparatorBuilder, SectionBuilder, MediaGalleryBuilder, FileBuilder, TextDisplayBuilder, ContainerBuilder, RoleSelectMenuBuilder, MentionableSelectMenuBuilder, ChannelSelectMenuBuilder, UserSelectMenuBuilder, StringSelectMenuOptionBuilder, StringSelectMenuBuilder, ButtonBuilder, TextInputBuilder, LabelBuilder, ModalBuilder, EmbedBuilder, SlashCommandSubcommandGroupBuilder, SlashCommandSubcommandBuilder, ContextMenuCommandBuilder, SlashCommandBuilder, InteractionContextType, ActionRowBuilder, Collection, MessageFlags, Events, Client, WebhookClient, AttachmentBuilder, SeparatorSpacingSize, DiscordAPIError, SnowflakeUtil, Role, PermissionFlagsBits, ChatInputCommandInteraction, AutocompleteInteraction, Message, TextChannel, Guild, RESTJSONErrorCodes, Colors } from 'discord.js';
|
|
6
6
|
import { Envapt } from 'envapt';
|
|
7
|
-
import { traverseDirectory } from '@seedcord/utils';
|
|
7
|
+
import { hexToNumber, traverseDirectory, filterCirculars, prettify } from '@seedcord/utils';
|
|
8
8
|
export * from '@seedcord/utils';
|
|
9
9
|
import * as crypto2 from 'crypto';
|
|
10
10
|
import { EventEmitter } from 'events';
|
|
@@ -39,26 +39,26 @@ var Pluggable = class _Pluggable {
|
|
|
39
39
|
return this;
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
42
|
+
* Attaches a plugin to this instance
|
|
43
|
+
*
|
|
44
|
+
* Plugins provide external functionality and are initialized during the specified startup phase.
|
|
45
|
+
* The plugin instance becomes available as a property in `core` wherever it's available.
|
|
46
|
+
*
|
|
47
|
+
* Make sure to augment the {@link Core} interface with the plugin type to ensure TypeScript recognizes it and provides intellisense.
|
|
48
|
+
*
|
|
49
|
+
* @typeParam Key - The property name for accessing the plugin
|
|
50
|
+
* @typeParam Ctor - The plugin constructor type
|
|
51
|
+
* @param key - Property name to access the plugin instance
|
|
52
|
+
* @param Plugin - Plugin constructor class
|
|
53
|
+
* @param startupPhase - When during startup to initialize this plugin ({@link StartupPhase})
|
|
54
|
+
* @param args - Additional arguments to pass to the plugin constructor
|
|
55
|
+
* @returns This instance with the plugin attached as a typed property
|
|
56
|
+
* @throws An {@link Error} When called after initialization or if key already exists
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* seedcord.attach('db', Mongo, StartupPhase.Configuration, { uri: 'mongodb://...', name: 'seedcord', dir: ... })
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
62
|
attach(key, Plugin2, startupPhase, ...args) {
|
|
63
63
|
if (this.isInitialized) throw new Error("Cannot attach a plugin after initialization.");
|
|
64
64
|
if (this[key]) throw new Error(`Plugin with key "${key}" already exists.`);
|
|
@@ -67,13 +67,27 @@ var Pluggable = class _Pluggable {
|
|
|
67
67
|
[key]: instance
|
|
68
68
|
};
|
|
69
69
|
this.startup.addTask(startupPhase, `Plugin:${key}`, async () => {
|
|
70
|
-
instance.logger.info(
|
|
70
|
+
instance.logger.info(chalk4.bold("Initializing"));
|
|
71
71
|
await instance.init();
|
|
72
|
-
instance.logger.info(
|
|
72
|
+
instance.logger.info(chalk4.bold("Initialized"));
|
|
73
73
|
}, _Pluggable.PLUGIN_INIT_TIMEOUT_MS);
|
|
74
74
|
return Object.assign(this, entry);
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
|
+
function parseEnvColor(raw, fallback) {
|
|
78
|
+
if (!raw) return fallback;
|
|
79
|
+
const toHex = /* @__PURE__ */ __name((n) => `#${n.toString(16).padStart(6, "0")}`, "toHex");
|
|
80
|
+
const num = Number(raw);
|
|
81
|
+
if (!Number.isNaN(num) && num >= 0) return toHex(num);
|
|
82
|
+
if (raw.startsWith("#")) return raw;
|
|
83
|
+
if (/^[0-9A-Fa-f]{6}$/.test(raw)) return `#${raw}`;
|
|
84
|
+
const colorKey = Object.keys(Colors).find((key) => key.toLowerCase() === raw.toLowerCase());
|
|
85
|
+
if (colorKey) return toHex(Colors[colorKey]);
|
|
86
|
+
return fallback;
|
|
87
|
+
}
|
|
88
|
+
__name(parseEnvColor, "parseEnvColor");
|
|
89
|
+
|
|
90
|
+
// src/interfaces/Components.ts
|
|
77
91
|
function _ts_decorate(decorators, target, key, desc) {
|
|
78
92
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
79
93
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -86,8 +100,18 @@ function _ts_metadata(k, v) {
|
|
|
86
100
|
}
|
|
87
101
|
__name(_ts_metadata, "_ts_metadata");
|
|
88
102
|
var BuilderTypes = {
|
|
103
|
+
// Command Components
|
|
89
104
|
command: SlashCommandBuilder,
|
|
105
|
+
context_menu: ContextMenuCommandBuilder,
|
|
106
|
+
subcommand: SlashCommandSubcommandBuilder,
|
|
107
|
+
group: SlashCommandSubcommandGroupBuilder,
|
|
108
|
+
// Embed Components
|
|
90
109
|
embed: EmbedBuilder,
|
|
110
|
+
// Modal Components
|
|
111
|
+
modal: ModalBuilder,
|
|
112
|
+
label: LabelBuilder,
|
|
113
|
+
text_input: TextInputBuilder,
|
|
114
|
+
// Action Row Components
|
|
91
115
|
button: ButtonBuilder,
|
|
92
116
|
menu_string: StringSelectMenuBuilder,
|
|
93
117
|
menu_option_string: StringSelectMenuOptionBuilder,
|
|
@@ -95,10 +119,7 @@ var BuilderTypes = {
|
|
|
95
119
|
menu_channel: ChannelSelectMenuBuilder,
|
|
96
120
|
menu_mentionable: MentionableSelectMenuBuilder,
|
|
97
121
|
menu_role: RoleSelectMenuBuilder,
|
|
98
|
-
|
|
99
|
-
context_menu: ContextMenuCommandBuilder,
|
|
100
|
-
subcommand: SlashCommandSubcommandBuilder,
|
|
101
|
-
group: SlashCommandSubcommandGroupBuilder,
|
|
122
|
+
// ComponentsV2
|
|
102
123
|
container: ContainerBuilder,
|
|
103
124
|
text_display: TextDisplayBuilder,
|
|
104
125
|
file: FileBuilder,
|
|
@@ -112,13 +133,9 @@ var RowTypes = {
|
|
|
112
133
|
menu_user: ActionRowBuilder,
|
|
113
134
|
menu_channel: ActionRowBuilder,
|
|
114
135
|
menu_mentionable: ActionRowBuilder,
|
|
115
|
-
menu_role: ActionRowBuilder
|
|
116
|
-
modal: ActionRowBuilder
|
|
117
|
-
};
|
|
118
|
-
var ModalTypes = {
|
|
119
|
-
text: TextInputBuilder
|
|
136
|
+
menu_role: ActionRowBuilder
|
|
120
137
|
};
|
|
121
|
-
var BaseComponent = class
|
|
138
|
+
var BaseComponent = class {
|
|
122
139
|
static {
|
|
123
140
|
__name(this, "BaseComponent");
|
|
124
141
|
}
|
|
@@ -128,26 +145,26 @@ var BaseComponent = class BaseComponent2 {
|
|
|
128
145
|
this._component = new ComponentClass();
|
|
129
146
|
}
|
|
130
147
|
/**
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
148
|
+
* Gets the component instance for configuration
|
|
149
|
+
*
|
|
150
|
+
* Use this to access Discord.js builder methods like setTitle(), setDescription(), etc.
|
|
151
|
+
*
|
|
152
|
+
* Use this in your component classes to configure the builder
|
|
153
|
+
* @example this.instance.setTitle('My Modal')
|
|
154
|
+
*/
|
|
138
155
|
get instance() {
|
|
139
156
|
return this._component;
|
|
140
157
|
}
|
|
141
158
|
/**
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
159
|
+
* Builds a customId string for interactive components
|
|
160
|
+
*
|
|
161
|
+
* Creates customIds in the format `prefix:arg1-arg2-arg3` for buttons, modals, etc.
|
|
162
|
+
* Arguments are joined with hyphens and separated from prefix with a colon.
|
|
163
|
+
*
|
|
164
|
+
* @param prefix - The route prefix that handlers will match against
|
|
165
|
+
* @param args - Additional arguments to encode in the customId
|
|
166
|
+
* @returns Formatted customId string
|
|
167
|
+
*/
|
|
151
168
|
buildCustomId(prefix, ...args) {
|
|
152
169
|
if (args.length === 0) return prefix;
|
|
153
170
|
return `${prefix}:${args.join("-")}`;
|
|
@@ -161,6 +178,9 @@ var BuilderComponent = class extends BaseComponent {
|
|
|
161
178
|
const ComponentClass = BuilderTypes[type];
|
|
162
179
|
super(ComponentClass);
|
|
163
180
|
if (this.instance instanceof EmbedBuilder) this.instance.setColor(this.botColor);
|
|
181
|
+
if (this.instance instanceof ContainerBuilder) {
|
|
182
|
+
this.instance.setAccentColor(this.botColor === "Default" ? void 0 : hexToNumber(this.botColor.toString()));
|
|
183
|
+
}
|
|
164
184
|
if (this.instance instanceof SlashCommandBuilder || this.instance instanceof ContextMenuCommandBuilder) {
|
|
165
185
|
this.instance.setContexts(InteractionContextType.Guild);
|
|
166
186
|
}
|
|
@@ -171,7 +191,8 @@ var BuilderComponent = class extends BaseComponent {
|
|
|
171
191
|
};
|
|
172
192
|
_ts_decorate([
|
|
173
193
|
Envapt("DEFAULT_BOT_COLOR", {
|
|
174
|
-
fallback: "Default"
|
|
194
|
+
fallback: "Default",
|
|
195
|
+
converter: /* @__PURE__ */ __name((raw, fallback) => parseEnvColor(raw, fallback), "converter")
|
|
175
196
|
}),
|
|
176
197
|
_ts_metadata("design:type", typeof ColorResolvable === "undefined" ? Object : ColorResolvable)
|
|
177
198
|
], BuilderComponent.prototype, "botColor", void 0);
|
|
@@ -187,39 +208,13 @@ var RowComponent = class extends BaseComponent {
|
|
|
187
208
|
return this.instance;
|
|
188
209
|
}
|
|
189
210
|
};
|
|
190
|
-
var ModalRow = class ModalRow2 extends RowComponent {
|
|
191
|
-
static {
|
|
192
|
-
__name(this, "ModalRow");
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Creates a new modal action row with the specified component.
|
|
196
|
-
*
|
|
197
|
-
* @param component - The modal field component to wrap in an action row
|
|
198
|
-
*/
|
|
199
|
-
constructor(component) {
|
|
200
|
-
super("modal");
|
|
201
|
-
this.instance.addComponents(component);
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
var ModalComponent = class extends BaseComponent {
|
|
205
|
-
static {
|
|
206
|
-
__name(this, "ModalComponent");
|
|
207
|
-
}
|
|
208
|
-
constructor(type) {
|
|
209
|
-
const ComponentClass = ModalTypes[type];
|
|
210
|
-
super(ComponentClass);
|
|
211
|
-
}
|
|
212
|
-
get component() {
|
|
213
|
-
return new ModalRow(this.instance).component;
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
211
|
var BaseErrorEmbed = class extends BuilderComponent {
|
|
217
212
|
static {
|
|
218
213
|
__name(this, "BaseErrorEmbed");
|
|
219
214
|
}
|
|
220
215
|
/**
|
|
221
|
-
|
|
222
|
-
|
|
216
|
+
* Creates a new error embed with default configuration.
|
|
217
|
+
*/
|
|
223
218
|
constructor() {
|
|
224
219
|
super("embed");
|
|
225
220
|
this.instance.setTitle("Cannot Proceed");
|
|
@@ -237,27 +232,25 @@ var CustomError = class extends Error {
|
|
|
237
232
|
Error.captureStackTrace(this, this.constructor);
|
|
238
233
|
}
|
|
239
234
|
/**
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
235
|
+
* Whether this error should be emitted to logs
|
|
236
|
+
*
|
|
237
|
+
* Controls logging behavior. Errors with emit=true will always be logged,
|
|
238
|
+
* while emit=false errors may be suppressed in production.
|
|
239
|
+
*
|
|
240
|
+
* @returns True if the error should be logged
|
|
241
|
+
*/
|
|
247
242
|
get emit() {
|
|
248
243
|
return this._emit;
|
|
249
244
|
}
|
|
250
245
|
/**
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
* @see {@link emit}
|
|
254
|
-
*/
|
|
246
|
+
* Sets whether this error should be emitted to logs
|
|
247
|
+
*/
|
|
255
248
|
set emit(value) {
|
|
256
249
|
this._emit = value;
|
|
257
250
|
}
|
|
258
251
|
};
|
|
259
252
|
|
|
260
|
-
// src/bot/decorators/
|
|
253
|
+
// src/bot/decorators/Command.ts
|
|
261
254
|
var CommandMetadataKey = Symbol("command:metadata");
|
|
262
255
|
function RegisterCommand(scope, guilds = []) {
|
|
263
256
|
return (ctor) => {
|
|
@@ -288,9 +281,9 @@ var CommandRegistry = class {
|
|
|
288
281
|
async init() {
|
|
289
282
|
if (this.isInitialised) return;
|
|
290
283
|
this.isInitialised = true;
|
|
291
|
-
this.logger.info(
|
|
284
|
+
this.logger.info(chalk4.bold(this.core.config.bot.commands.path));
|
|
292
285
|
await this.loadCommands(this.core.config.bot.commands.path);
|
|
293
|
-
this.logger.info(`${
|
|
286
|
+
this.logger.info(`${chalk4.bold.green("Loaded")}: ${chalk4.magenta.bold(this.globalCommands.length)} global, ${chalk4.magenta.bold(this.guildCommands.size)} guild groups`);
|
|
294
287
|
}
|
|
295
288
|
async loadCommands(dir) {
|
|
296
289
|
await traverseDirectory(dir, (_full, rel, mod) => {
|
|
@@ -309,24 +302,24 @@ var CommandRegistry = class {
|
|
|
309
302
|
const commandType = comp instanceof SlashCommandBuilder ? "slash command" : "context menu command";
|
|
310
303
|
if (meta.scope === "global") {
|
|
311
304
|
this.globalCommands.push(comp);
|
|
312
|
-
this.logger.info(`${
|
|
313
|
-
this.logger.info(` \u2192 Global ${commandType}: ${
|
|
305
|
+
this.logger.info(`${chalk4.italic("Registered")} ${chalk4.bold.yellow(ctor.name)} from ${chalk4.gray(rel)}`);
|
|
306
|
+
this.logger.info(` \u2192 Global ${commandType}: ${chalk4.bold.cyan(comp.name)}`);
|
|
314
307
|
} else {
|
|
315
308
|
for (const g of meta.guilds) {
|
|
316
309
|
const arr = this.guildCommands.get(g) ?? [];
|
|
317
310
|
arr.push(comp);
|
|
318
311
|
this.guildCommands.set(g, arr);
|
|
319
312
|
}
|
|
320
|
-
this.logger.info(`${
|
|
321
|
-
this.logger.info(` \u2192 Guild ${commandType}: ${
|
|
313
|
+
this.logger.info(`${chalk4.italic("Registered")} ${chalk4.bold.yellow(ctor.name)} from ${chalk4.gray(rel)}`);
|
|
314
|
+
this.logger.info(` \u2192 Guild ${commandType}: ${chalk4.bold.cyan(comp.name)} for ${chalk4.magenta.bold(meta.guilds.length)} guild(s)`);
|
|
322
315
|
}
|
|
323
316
|
}
|
|
324
317
|
async setCommands() {
|
|
325
318
|
if (this.globalCommands.length > 0) {
|
|
326
319
|
await this.core.bot.client.application?.commands.set(this.globalCommands);
|
|
327
320
|
const tag = this.globalCommands.length === 1 ? "command" : "commands";
|
|
328
|
-
this.logger.info(`${
|
|
329
|
-
this.logger.info(` \u2192 ${this.globalCommands.map((command) =>
|
|
321
|
+
this.logger.info(`${chalk4.bold.green("Configured")} ${chalk4.magenta.bold(this.globalCommands.length)} global ${tag}`);
|
|
322
|
+
this.logger.info(` \u2192 ${this.globalCommands.map((command) => chalk4.bold.cyan(command.name)).join(", ")}`);
|
|
330
323
|
}
|
|
331
324
|
for (const [guildId, commands] of this.guildCommands.entries()) {
|
|
332
325
|
const guild = this.core.bot.client.guilds.cache.get(guildId);
|
|
@@ -336,14 +329,14 @@ var CommandRegistry = class {
|
|
|
336
329
|
}
|
|
337
330
|
await guild.commands.set(commands);
|
|
338
331
|
const tag = commands.length === 1 ? "command" : "commands";
|
|
339
|
-
this.logger.info(`${
|
|
340
|
-
this.logger.info(` \u2192 ${commands.map((command) =>
|
|
332
|
+
this.logger.info(`${chalk4.bold.green("Configured")} ${chalk4.magenta.bold(commands.length)} ${tag} for guild ${chalk4.bold.yellow(guild.name)}`);
|
|
333
|
+
this.logger.info(` \u2192 ${commands.map((command) => chalk4.bold.cyan(command.name)).join(", ")}`);
|
|
341
334
|
}
|
|
342
335
|
}
|
|
343
336
|
};
|
|
344
337
|
|
|
345
338
|
// src/interfaces/Handler.ts
|
|
346
|
-
var BaseHandler = class
|
|
339
|
+
var BaseHandler = class {
|
|
347
340
|
static {
|
|
348
341
|
__name(this, "BaseHandler");
|
|
349
342
|
}
|
|
@@ -374,19 +367,19 @@ var BaseHandler = class BaseHandler2 {
|
|
|
374
367
|
return this.event;
|
|
375
368
|
}
|
|
376
369
|
/**
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
370
|
+
* Gets arguments parsed from interaction customId
|
|
371
|
+
*
|
|
372
|
+
* Arguments are extracted from customId using `:` and `-` separators.
|
|
373
|
+
* For customId `accept:user123-guild456`, returns `["user123", "guild456"]`
|
|
374
|
+
*/
|
|
382
375
|
getArgs() {
|
|
383
376
|
return this.args;
|
|
384
377
|
}
|
|
385
378
|
/**
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
379
|
+
* Gets a specific argument by index from parsed customId
|
|
380
|
+
* @param index - Zero-based index of the argument to retrieve
|
|
381
|
+
* @returns The argument at the specified index, or undefined if not found
|
|
382
|
+
*/
|
|
390
383
|
getArg(index) {
|
|
391
384
|
return this.args[index];
|
|
392
385
|
}
|
|
@@ -407,11 +400,19 @@ var InteractionMiddleware = class extends BaseHandler {
|
|
|
407
400
|
super(event, core, args);
|
|
408
401
|
}
|
|
409
402
|
};
|
|
403
|
+
var EventMiddleware = class extends BaseHandler {
|
|
404
|
+
static {
|
|
405
|
+
__name(this, "EventMiddleware");
|
|
406
|
+
}
|
|
407
|
+
constructor(event, core, args) {
|
|
408
|
+
super(event, core, args);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
410
411
|
var AutocompleteHandler = class extends BaseHandler {
|
|
411
412
|
static {
|
|
412
413
|
__name(this, "AutocompleteHandler");
|
|
413
414
|
}
|
|
414
|
-
/** The currently focused autocomplete option (Based on what you set in
|
|
415
|
+
/** The currently focused autocomplete option (Based on what you set in `@AutocompleteRoute`) */
|
|
415
416
|
focused;
|
|
416
417
|
constructor(event, core, args) {
|
|
417
418
|
super(event, core, args);
|
|
@@ -427,15 +428,57 @@ var EventHandler = class extends BaseHandler {
|
|
|
427
428
|
}
|
|
428
429
|
};
|
|
429
430
|
|
|
430
|
-
// src/
|
|
431
|
+
// src/miscellaneous/areRoutes.ts
|
|
432
|
+
function areRoutes(routes) {
|
|
433
|
+
return Array.isArray(routes) && routes.every((r) => typeof r === "string");
|
|
434
|
+
}
|
|
435
|
+
__name(areRoutes, "areRoutes");
|
|
436
|
+
|
|
437
|
+
// src/bot/decorators/Events.ts
|
|
431
438
|
var EventMetadataKey = Symbol("event:metadata");
|
|
432
|
-
function RegisterEvent(
|
|
439
|
+
function RegisterEvent(events) {
|
|
433
440
|
return function(constructor) {
|
|
434
|
-
Reflect.
|
|
441
|
+
const saved = Reflect.getMetadata(EventMetadataKey, constructor);
|
|
442
|
+
const existing = areRoutes(saved) ? saved : [];
|
|
443
|
+
const toStore = Array.isArray(events) ? events : [
|
|
444
|
+
events
|
|
445
|
+
];
|
|
446
|
+
Reflect.defineMetadata(EventMetadataKey, [
|
|
447
|
+
...existing,
|
|
448
|
+
...toStore
|
|
449
|
+
], constructor);
|
|
435
450
|
};
|
|
436
451
|
}
|
|
437
452
|
__name(RegisterEvent, "RegisterEvent");
|
|
438
453
|
|
|
454
|
+
// src/bot/decorators/Middlewares.ts
|
|
455
|
+
var MiddlewareType = /* @__PURE__ */ (function(MiddlewareType2) {
|
|
456
|
+
MiddlewareType2["Interaction"] = "middleware:interaction";
|
|
457
|
+
MiddlewareType2["Event"] = "middleware:event";
|
|
458
|
+
return MiddlewareType2;
|
|
459
|
+
})({});
|
|
460
|
+
var MiddlewareMetadataKey = Symbol("middleware:metadata");
|
|
461
|
+
function Middleware(type, priority = 0, options = {}) {
|
|
462
|
+
return (ctor) => {
|
|
463
|
+
const normalizedPriority = Number(priority);
|
|
464
|
+
if (!Number.isFinite(normalizedPriority)) {
|
|
465
|
+
throw new TypeError("Middleware priority must be a finite number");
|
|
466
|
+
}
|
|
467
|
+
if (type === "middleware:interaction" && options.events?.length) {
|
|
468
|
+
throw new Error("Interaction middleware cannot specify event filters");
|
|
469
|
+
}
|
|
470
|
+
const metadata = {
|
|
471
|
+
priority: normalizedPriority,
|
|
472
|
+
type,
|
|
473
|
+
...options.events ? {
|
|
474
|
+
events: options.events
|
|
475
|
+
} : {}
|
|
476
|
+
};
|
|
477
|
+
Reflect.defineMetadata(MiddlewareMetadataKey, metadata, ctor);
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
__name(Middleware, "Middleware");
|
|
481
|
+
|
|
439
482
|
// src/bot/controllers/EventController.ts
|
|
440
483
|
var EventController = class {
|
|
441
484
|
static {
|
|
@@ -445,6 +488,7 @@ var EventController = class {
|
|
|
445
488
|
logger = new Logger("Events");
|
|
446
489
|
isInitialized = false;
|
|
447
490
|
eventMap = new Collection();
|
|
491
|
+
middlewares = [];
|
|
448
492
|
constructor(core) {
|
|
449
493
|
this.core = core;
|
|
450
494
|
}
|
|
@@ -454,42 +498,96 @@ var EventController = class {
|
|
|
454
498
|
}
|
|
455
499
|
this.isInitialized = true;
|
|
456
500
|
const handlersDir = this.core.config.bot.events.path;
|
|
457
|
-
this.logger.info(
|
|
501
|
+
this.logger.info(chalk4.bold(handlersDir));
|
|
502
|
+
const middlewareDir = this.core.config.bot.events.middlewares;
|
|
503
|
+
if (middlewareDir) {
|
|
504
|
+
this.logger.info(`${chalk4.bold(middlewareDir)} ${chalk4.gray("(middlewares)")}`);
|
|
505
|
+
await this.loadMiddlewares(middlewareDir);
|
|
506
|
+
}
|
|
458
507
|
await this.loadHandlers(handlersDir);
|
|
459
508
|
this.attachToClient();
|
|
509
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.middlewares.length)} middlewares`);
|
|
460
510
|
const loadedEventsArray = [];
|
|
461
511
|
this.eventMap.forEach((handlers, eventName) => {
|
|
462
|
-
loadedEventsArray.push(`${
|
|
512
|
+
loadedEventsArray.push(`${chalk4.magenta.bold(handlers.length)} ${eventName}`);
|
|
463
513
|
});
|
|
464
|
-
this.logger.info(`${
|
|
514
|
+
this.logger.info(`${chalk4.bold.green("Loaded")}: ${this.eventMap.size > 0 ? loadedEventsArray.join(", ") : "none"}`);
|
|
465
515
|
}
|
|
466
516
|
async loadHandlers(dir) {
|
|
467
517
|
await traverseDirectory(dir, (_fullPath, relativePath, imported) => {
|
|
468
518
|
for (const val of Object.values(imported)) {
|
|
469
|
-
if (this.isEventHandlerClass(val))
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
519
|
+
if (!this.isEventHandlerClass(val)) continue;
|
|
520
|
+
this.registerHandler(val);
|
|
521
|
+
this.logger.info(`${chalk4.italic("Registered")} ${chalk4.bold.yellow(val.name)} from ${chalk4.gray(relativePath)}`);
|
|
522
|
+
}
|
|
523
|
+
}, this.logger);
|
|
524
|
+
}
|
|
525
|
+
async loadMiddlewares(dir) {
|
|
526
|
+
await traverseDirectory(dir, (_fullPath, relativePath, imported) => {
|
|
527
|
+
for (const val of Object.values(imported)) {
|
|
528
|
+
if (!this.isMiddlewareClass(val)) continue;
|
|
529
|
+
const metadata = Reflect.getMetadata(MiddlewareMetadataKey, val);
|
|
530
|
+
if (metadata?.type !== MiddlewareType.Event) continue;
|
|
531
|
+
this.registerMiddleware(val, metadata, relativePath);
|
|
473
532
|
}
|
|
474
533
|
}, this.logger);
|
|
475
534
|
}
|
|
535
|
+
registerMiddleware(middlewareCtor, metadata, relativePath) {
|
|
536
|
+
const alreadyRegistered = this.middlewares.some((entry) => entry.ctor === middlewareCtor);
|
|
537
|
+
if (alreadyRegistered) return;
|
|
538
|
+
this.middlewares.push({
|
|
539
|
+
ctor: middlewareCtor,
|
|
540
|
+
priority: metadata.priority,
|
|
541
|
+
...metadata.events ? {
|
|
542
|
+
events: metadata.events
|
|
543
|
+
} : {}
|
|
544
|
+
});
|
|
545
|
+
this.middlewares.sort((a, b) => a.priority - b.priority);
|
|
546
|
+
this.logger.info(`${chalk4.italic("Registered event middleware")} ${chalk4.bold.yellow(middlewareCtor.name)} ${chalk4.gray(`(priority ${metadata.priority})`)} from ${chalk4.gray(relativePath)}`);
|
|
547
|
+
}
|
|
548
|
+
async runMiddlewares(eventName, args) {
|
|
549
|
+
for (const { ctor, events } of this.middlewares) {
|
|
550
|
+
if (events && !events.includes(eventName)) continue;
|
|
551
|
+
try {
|
|
552
|
+
const middleware = new ctor(args, this.core);
|
|
553
|
+
if (middleware.hasChecks()) await middleware.runChecks();
|
|
554
|
+
if (middleware.shouldBreak() || middleware.hasErrors()) return false;
|
|
555
|
+
await middleware.execute();
|
|
556
|
+
if (middleware.shouldBreak() || middleware.hasErrors()) return false;
|
|
557
|
+
} catch (err) {
|
|
558
|
+
this.logger.error(`Error in event middleware ${ctor.name} for event ${String(eventName)}:`, err);
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
476
564
|
isEventHandlerClass(obj) {
|
|
477
565
|
if (typeof obj !== "function") return false;
|
|
478
566
|
return obj.prototype instanceof EventHandler && Reflect.hasMetadata(EventMetadataKey, obj);
|
|
479
567
|
}
|
|
568
|
+
isMiddlewareClass(obj) {
|
|
569
|
+
if (typeof obj !== "function") return false;
|
|
570
|
+
return obj.prototype instanceof EventMiddleware && Reflect.hasMetadata(MiddlewareMetadataKey, obj);
|
|
571
|
+
}
|
|
480
572
|
registerHandler(handlerClass) {
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
573
|
+
const raw = Reflect.getMetadata(EventMetadataKey, handlerClass);
|
|
574
|
+
const names = areRoutes(raw) ? raw : typeof raw === "string" ? [
|
|
575
|
+
raw
|
|
576
|
+
] : [];
|
|
577
|
+
if (names.length === 0) return;
|
|
578
|
+
for (const name of names) {
|
|
579
|
+
const key = name;
|
|
580
|
+
let handlers = this.eventMap.get(key);
|
|
581
|
+
if (!handlers) {
|
|
582
|
+
handlers = [];
|
|
583
|
+
this.eventMap.set(key, handlers);
|
|
584
|
+
}
|
|
585
|
+
handlers.push(handlerClass);
|
|
487
586
|
}
|
|
488
|
-
handlers.push(handlerClass);
|
|
489
587
|
}
|
|
490
588
|
attachToClient() {
|
|
491
589
|
for (const [eventName] of this.eventMap) {
|
|
492
|
-
this.logger.debug(`Attaching ${
|
|
590
|
+
this.logger.debug(`Attaching ${chalk4.bold.green(eventName)} to ${chalk4.bold.yellow(this.core.bot.client.user?.username)}`);
|
|
493
591
|
this.core.bot.client.on(eventName, (...args) => {
|
|
494
592
|
void (async () => {
|
|
495
593
|
await this.processEvent(eventName, args);
|
|
@@ -498,11 +596,13 @@ var EventController = class {
|
|
|
498
596
|
}
|
|
499
597
|
}
|
|
500
598
|
async processEvent(eventName, args) {
|
|
599
|
+
const shouldContinue = await this.runMiddlewares(eventName, args);
|
|
600
|
+
if (!shouldContinue) return;
|
|
501
601
|
const handlerCtors = this.eventMap.get(eventName);
|
|
502
602
|
if (!handlerCtors || handlerCtors.length === 0) return;
|
|
503
603
|
for (const HandlerCtor of handlerCtors) {
|
|
504
604
|
try {
|
|
505
|
-
this.logger.debug(`Processing ${
|
|
605
|
+
this.logger.debug(`Processing ${chalk4.bold.green(eventName)} with ${chalk4.gray(HandlerCtor.name)}`);
|
|
506
606
|
const handler = new HandlerCtor(args, this.core);
|
|
507
607
|
if (handler.hasChecks()) {
|
|
508
608
|
await handler.runChecks();
|
|
@@ -518,7 +618,7 @@ var EventController = class {
|
|
|
518
618
|
}
|
|
519
619
|
};
|
|
520
620
|
|
|
521
|
-
// src/bot/decorators/
|
|
621
|
+
// src/bot/decorators/Interactions.ts
|
|
522
622
|
var InteractionRoutes = /* @__PURE__ */ (function(InteractionRoutes2) {
|
|
523
623
|
InteractionRoutes2["Slash"] = "interaction:slash";
|
|
524
624
|
InteractionRoutes2["Button"] = "interaction:button";
|
|
@@ -598,9 +698,6 @@ function SelectMenuRoute(type, routeOrRoutes) {
|
|
|
598
698
|
}
|
|
599
699
|
__name(SelectMenuRoute, "SelectMenuRoute");
|
|
600
700
|
function storeMetadata(symbol, routes, constructor) {
|
|
601
|
-
const areRoutes = /* @__PURE__ */ __name((routes2) => {
|
|
602
|
-
return Array.isArray(routes2) && routes2.every((r) => typeof r === "string");
|
|
603
|
-
}, "areRoutes");
|
|
604
701
|
const savedRoutes = Reflect.getMetadata(symbol, constructor);
|
|
605
702
|
const existing = areRoutes(savedRoutes) ? savedRoutes : [];
|
|
606
703
|
const toStore = Array.isArray(routes) ? routes : [
|
|
@@ -621,11 +718,11 @@ var DatabaseError = class extends CustomError {
|
|
|
621
718
|
}
|
|
622
719
|
uuid;
|
|
623
720
|
/**
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
721
|
+
* Creates a new DatabaseError.
|
|
722
|
+
*
|
|
723
|
+
* @param message - The error message describing what went wrong
|
|
724
|
+
* @param uuid - A unique identifier for this specific error instance
|
|
725
|
+
*/
|
|
629
726
|
constructor(message, uuid) {
|
|
630
727
|
super(message), this.uuid = uuid;
|
|
631
728
|
this.emit = true;
|
|
@@ -635,69 +732,71 @@ var DatabaseError = class extends CustomError {
|
|
|
635
732
|
}
|
|
636
733
|
};
|
|
637
734
|
|
|
638
|
-
// src/bot/utilities/
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
static extractErrorResponse(error, core, guild, user) {
|
|
657
|
-
const uuid = crypto2.randomUUID();
|
|
658
|
-
if (error instanceof CustomError) {
|
|
659
|
-
if (error instanceof DatabaseError) {
|
|
660
|
-
core.effects.emit("unknownException", {
|
|
661
|
-
uuid,
|
|
662
|
-
error,
|
|
663
|
-
guild,
|
|
664
|
-
user
|
|
665
|
-
});
|
|
666
|
-
this.logger.error(`DatabaseError: ${error.uuid}`);
|
|
667
|
-
} else if (error.emit) {
|
|
668
|
-
this.logger.error(`${error.name}: ${error.message}`, error);
|
|
669
|
-
}
|
|
670
|
-
return {
|
|
735
|
+
// src/bot/utilities/errors/extractErrorResponse.ts
|
|
736
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
737
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
738
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
739
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
740
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
741
|
+
}
|
|
742
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
743
|
+
function _ts_metadata2(k, v) {
|
|
744
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
745
|
+
}
|
|
746
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
747
|
+
var logger = new Logger("ErrorsHandling");
|
|
748
|
+
function extractErrorResponse(error, core, guild, user, metadata) {
|
|
749
|
+
const uuid = crypto2.randomUUID();
|
|
750
|
+
if (error instanceof CustomError) {
|
|
751
|
+
if (error instanceof DatabaseError) {
|
|
752
|
+
core.effects.emit("unknownException", {
|
|
671
753
|
uuid,
|
|
672
|
-
|
|
673
|
-
|
|
754
|
+
error,
|
|
755
|
+
guild,
|
|
756
|
+
user,
|
|
757
|
+
metadata
|
|
758
|
+
});
|
|
759
|
+
logger.error(`DatabaseError: ${error.uuid}`);
|
|
760
|
+
} else if (error.emit) {
|
|
761
|
+
logger.error(`${error.name}: ${error.message}`, error);
|
|
674
762
|
}
|
|
675
|
-
const showStack = core.config.bot.errorStack;
|
|
676
|
-
if (showStack) this.logger.error(uuid, error);
|
|
677
|
-
else this.logger.error(`${uuid} | ${error.message}`);
|
|
678
|
-
core.effects.emit("unknownException", {
|
|
679
|
-
uuid,
|
|
680
|
-
error,
|
|
681
|
-
guild,
|
|
682
|
-
user
|
|
683
|
-
});
|
|
684
763
|
return {
|
|
685
764
|
uuid,
|
|
686
|
-
response:
|
|
765
|
+
response: error.response
|
|
687
766
|
};
|
|
688
767
|
}
|
|
689
|
-
|
|
690
|
-
|
|
768
|
+
const showStack = core.config.bot.errorStack;
|
|
769
|
+
if (showStack) logger.error(uuid, error);
|
|
770
|
+
else logger.error(`${uuid} | ${error.message}`);
|
|
771
|
+
core.effects.emit("unknownException", {
|
|
772
|
+
uuid,
|
|
773
|
+
error,
|
|
774
|
+
guild,
|
|
775
|
+
user,
|
|
776
|
+
metadata
|
|
777
|
+
});
|
|
778
|
+
return {
|
|
779
|
+
uuid,
|
|
780
|
+
response: new GenericError(uuid).response
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
__name(extractErrorResponse, "extractErrorResponse");
|
|
784
|
+
var GenericError = class extends CustomError {
|
|
691
785
|
static {
|
|
692
786
|
__name(this, "GenericError");
|
|
693
787
|
}
|
|
694
788
|
uuid;
|
|
789
|
+
developerUsername = "the developer";
|
|
695
790
|
constructor(uuid) {
|
|
696
791
|
super("An unknown error occurred"), this.uuid = uuid;
|
|
697
|
-
this.response.setTitle("Error").setDescription(`An unknown error occurred. Please reach out to
|
|
792
|
+
this.response.setTitle("Error").setDescription(`An unknown error occurred. Please reach out to ${this.developerUsername} with a way to reproduce the error and the following:
|
|
698
793
|
### UUID: \`${this.uuid}\``);
|
|
699
794
|
}
|
|
700
795
|
};
|
|
796
|
+
_ts_decorate2([
|
|
797
|
+
Envapt("DEVELOPER_DISCORD_USERNAME"),
|
|
798
|
+
_ts_metadata2("design:type", String)
|
|
799
|
+
], GenericError.prototype, "developerUsername", void 0);
|
|
701
800
|
|
|
702
801
|
// src/bot/decorators/Catchable.ts
|
|
703
802
|
function Catchable(options) {
|
|
@@ -714,7 +813,7 @@ function Catchable(options) {
|
|
|
714
813
|
if (!(error instanceof Error)) throw error;
|
|
715
814
|
this.setErrored();
|
|
716
815
|
if (log) console.error(error);
|
|
717
|
-
const { response } =
|
|
816
|
+
const { response } = extractErrorResponse(error, this.core, interaction.guild, interaction.user, interaction);
|
|
718
817
|
const res = {
|
|
719
818
|
embeds: [
|
|
720
819
|
response
|
|
@@ -748,17 +847,17 @@ function Catchable(options) {
|
|
|
748
847
|
__name(Catchable, "Catchable");
|
|
749
848
|
|
|
750
849
|
// src/bot/defaults/UnhandledEvent.ts
|
|
751
|
-
function
|
|
850
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
752
851
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
753
852
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
754
853
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
755
854
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
756
855
|
}
|
|
757
|
-
__name(
|
|
758
|
-
function
|
|
856
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
857
|
+
function _ts_metadata3(k, v) {
|
|
759
858
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
760
859
|
}
|
|
761
|
-
__name(
|
|
860
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
762
861
|
var UnhandledEvent = class extends InteractionHandler {
|
|
763
862
|
static {
|
|
764
863
|
__name(this, "UnhandledEvent");
|
|
@@ -770,12 +869,32 @@ var UnhandledEvent = class extends InteractionHandler {
|
|
|
770
869
|
});
|
|
771
870
|
}
|
|
772
871
|
};
|
|
773
|
-
|
|
872
|
+
_ts_decorate3([
|
|
774
873
|
Catchable(),
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
874
|
+
_ts_metadata3("design:type", Function),
|
|
875
|
+
_ts_metadata3("design:paramtypes", []),
|
|
876
|
+
_ts_metadata3("design:returntype", Promise)
|
|
778
877
|
], UnhandledEvent.prototype, "execute", null);
|
|
878
|
+
function buildSlashRoute(arg1, arg2, arg3) {
|
|
879
|
+
let command;
|
|
880
|
+
let sub;
|
|
881
|
+
let group;
|
|
882
|
+
if (typeof arg1 === "string") {
|
|
883
|
+
command = arg1;
|
|
884
|
+
sub = arg2;
|
|
885
|
+
group = arg3;
|
|
886
|
+
} else if (arg1 instanceof ChatInputCommandInteraction || arg1 instanceof AutocompleteInteraction) {
|
|
887
|
+
command = arg1.commandName;
|
|
888
|
+
group = arg1.options.getSubcommandGroup(false) ?? void 0;
|
|
889
|
+
sub = arg1.options.getSubcommand(false) ?? void 0;
|
|
890
|
+
} else {
|
|
891
|
+
throw new TypeError("Invalid argument passed to buildSlashRoute");
|
|
892
|
+
}
|
|
893
|
+
if (sub && group) return `${command}/${group}/${sub}`;
|
|
894
|
+
if (sub) return `${command}/${sub}`;
|
|
895
|
+
return command;
|
|
896
|
+
}
|
|
897
|
+
__name(buildSlashRoute, "buildSlashRoute");
|
|
779
898
|
|
|
780
899
|
// src/bot/controllers/InteractionController.ts
|
|
781
900
|
var InteractionController = class {
|
|
@@ -809,40 +928,66 @@ var InteractionController = class {
|
|
|
809
928
|
if (this.isInitialized) return;
|
|
810
929
|
this.isInitialized = true;
|
|
811
930
|
const handlersDir = this.core.config.bot.interactions.path;
|
|
812
|
-
this.logger.info(
|
|
931
|
+
this.logger.info(chalk4.bold(handlersDir));
|
|
932
|
+
const middlewareDir = this.core.config.bot.interactions.middlewares;
|
|
933
|
+
if (middlewareDir) {
|
|
934
|
+
this.logger.info(`${chalk4.bold(middlewareDir)} ${chalk4.gray("(middlewares)")}`);
|
|
935
|
+
await this.loadMiddlewares(middlewareDir);
|
|
936
|
+
}
|
|
813
937
|
await this.loadHandlers(handlersDir);
|
|
814
938
|
this.attachToClient();
|
|
815
|
-
this.logger.info(`${
|
|
816
|
-
this.logger.info(`\u2192 ${
|
|
817
|
-
this.logger.info(`\u2192 ${
|
|
818
|
-
this.logger.info(`\u2192 ${
|
|
819
|
-
this.logger.info(`\u2192 ${
|
|
820
|
-
this.logger.info(`\u2192 ${
|
|
821
|
-
this.logger.info(`\u2192 ${
|
|
822
|
-
this.logger.info(`\u2192 ${
|
|
823
|
-
this.logger.info(`\u2192 ${
|
|
824
|
-
this.logger.info(`\u2192 ${
|
|
825
|
-
this.logger.info(`\u2192 ${
|
|
826
|
-
this.logger.info(`\u2192 ${
|
|
939
|
+
this.logger.info(`${chalk4.bold.green("Loaded interaction handlers:")}`);
|
|
940
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.middlewares.length)} middlewares`);
|
|
941
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.slashMap.size)} slash commands`);
|
|
942
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.buttonMap.size)} buttons`);
|
|
943
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.modalMap.size)} modals`);
|
|
944
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.stringSelectMap.size)} string selects`);
|
|
945
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.userSelectMap.size)} user selects`);
|
|
946
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.roleSelectMap.size)} role selects`);
|
|
947
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.channelSelectMap.size)} channel selects`);
|
|
948
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.mentionableSelectMap.size)} mentionable selects`);
|
|
949
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.messageContextMenuMap.size)} message context menus`);
|
|
950
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.userContextMenuMap.size)} user context menus`);
|
|
951
|
+
this.logger.info(`\u2192 ${chalk4.magenta.bold(this.autocompleteMap.size)} autocomplete`);
|
|
827
952
|
}
|
|
828
953
|
async loadHandlers(dir) {
|
|
829
954
|
await traverseDirectory(dir, (_fullPath, relativePath, imported) => {
|
|
830
955
|
for (const val of Object.values(imported)) {
|
|
831
|
-
if (this.isHandlerClass(val))
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
}
|
|
956
|
+
if (!this.isHandlerClass(val)) continue;
|
|
957
|
+
this.registerHandler(val);
|
|
958
|
+
this.logger.info(`${chalk4.italic("Registered")} ${chalk4.bold.yellow(val.name)} from ${chalk4.gray(relativePath)}`);
|
|
835
959
|
}
|
|
836
960
|
}, this.logger);
|
|
837
961
|
}
|
|
962
|
+
async loadMiddlewares(dir) {
|
|
963
|
+
await traverseDirectory(dir, (_fullPath, relativePath, imported) => {
|
|
964
|
+
for (const val of Object.values(imported)) {
|
|
965
|
+
if (!this.isMiddlewareClass(val)) continue;
|
|
966
|
+
const metadata = Reflect.getMetadata(MiddlewareMetadataKey, val);
|
|
967
|
+
if (metadata?.type !== MiddlewareType.Interaction) continue;
|
|
968
|
+
this.registerMiddleware(val, metadata, relativePath);
|
|
969
|
+
}
|
|
970
|
+
}, this.logger);
|
|
971
|
+
}
|
|
972
|
+
registerMiddleware(middlewareCtor, metadata, relativePath) {
|
|
973
|
+
const alreadyRegistered = this.middlewares.some((entry) => entry.ctor === middlewareCtor);
|
|
974
|
+
if (alreadyRegistered) return;
|
|
975
|
+
this.middlewares.push({
|
|
976
|
+
ctor: middlewareCtor,
|
|
977
|
+
priority: metadata.priority
|
|
978
|
+
});
|
|
979
|
+
this.middlewares.sort((a, b) => a.priority - b.priority);
|
|
980
|
+
this.logger.info(`${chalk4.italic("Registered middleware")} ${chalk4.bold.yellow(middlewareCtor.name)} ${chalk4.gray(`(priority ${metadata.priority})`)} from ${chalk4.gray(relativePath)}`);
|
|
981
|
+
}
|
|
838
982
|
isHandlerClass(obj) {
|
|
839
983
|
if (typeof obj !== "function") return false;
|
|
840
984
|
return obj.prototype instanceof InteractionHandler && Reflect.hasMetadata(InteractionMetadataKey, obj) || obj.prototype instanceof AutocompleteHandler && Reflect.hasMetadata(InteractionMetadataKey, obj);
|
|
841
985
|
}
|
|
986
|
+
isMiddlewareClass(obj) {
|
|
987
|
+
if (typeof obj !== "function") return false;
|
|
988
|
+
return obj.prototype instanceof InteractionMiddleware && Reflect.hasMetadata(MiddlewareMetadataKey, obj);
|
|
989
|
+
}
|
|
842
990
|
registerHandler(handlerClass) {
|
|
843
|
-
const areRoutes = /* @__PURE__ */ __name((routes) => {
|
|
844
|
-
return Array.isArray(routes) && routes.every((r) => typeof r === "string");
|
|
845
|
-
}, "areRoutes");
|
|
846
991
|
const routeTypes = [
|
|
847
992
|
[
|
|
848
993
|
InteractionRoutes.Slash,
|
|
@@ -899,7 +1044,7 @@ var InteractionController = class {
|
|
|
899
1044
|
attachToClient() {
|
|
900
1045
|
this.core.bot.client.on(Events.InteractionCreate, (interaction) => {
|
|
901
1046
|
this.handleInteraction(interaction).catch((err) => {
|
|
902
|
-
this.logger.error(`[${
|
|
1047
|
+
this.logger.error(`[${chalk4.bold.red("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
|
|
903
1048
|
});
|
|
904
1049
|
});
|
|
905
1050
|
}
|
|
@@ -921,17 +1066,19 @@ var InteractionController = class {
|
|
|
921
1066
|
async processInteraction(interaction, extractKey, getHandler, args) {
|
|
922
1067
|
const key = extractKey(interaction);
|
|
923
1068
|
if (this.keysToIgnore.has(key)) return;
|
|
924
|
-
for (const
|
|
925
|
-
const middleware = new
|
|
1069
|
+
for (const { ctor } of this.middlewares) {
|
|
1070
|
+
const middleware = new ctor(interaction, this.core, args);
|
|
1071
|
+
if (middleware.hasChecks()) await middleware.runChecks();
|
|
1072
|
+
if (middleware.shouldBreak() || middleware.hasErrors()) return;
|
|
926
1073
|
await middleware.execute();
|
|
927
|
-
if (middleware.hasErrors()) return;
|
|
1074
|
+
if (middleware.shouldBreak() || middleware.hasErrors()) return;
|
|
928
1075
|
}
|
|
929
1076
|
let HandlerCtor = getHandler(key);
|
|
930
1077
|
if (!HandlerCtor) {
|
|
931
|
-
this.logger.warn(`No handler found for key ${
|
|
1078
|
+
this.logger.warn(`No handler found for key ${chalk4.bold.cyan(key)}. Falling back to UnhandledEvent.`);
|
|
932
1079
|
HandlerCtor = UnhandledEvent;
|
|
933
1080
|
}
|
|
934
|
-
this.logger.debug(`Processing ${
|
|
1081
|
+
this.logger.debug(`Processing ${chalk4.bold.green(key)} with ${chalk4.gray(HandlerCtor.name)}`);
|
|
935
1082
|
const handler = new HandlerCtor(interaction, this.core, args);
|
|
936
1083
|
if (handler.hasChecks()) await handler.runChecks();
|
|
937
1084
|
if (handler.shouldBreak()) return;
|
|
@@ -978,7 +1125,7 @@ var InteractionController = class {
|
|
|
978
1125
|
}
|
|
979
1126
|
}
|
|
980
1127
|
async handleSlashCommand(interaction) {
|
|
981
|
-
const route =
|
|
1128
|
+
const route = buildSlashRoute(interaction);
|
|
982
1129
|
await this.processInteraction(interaction, () => route, (key) => this.slashMap.get(key));
|
|
983
1130
|
}
|
|
984
1131
|
async handleButton(interaction) {
|
|
@@ -1009,26 +1156,11 @@ var InteractionController = class {
|
|
|
1009
1156
|
await this.processInteraction(interaction, () => interaction.commandName, (key) => this.userContextMenuMap.get(key));
|
|
1010
1157
|
}
|
|
1011
1158
|
async handleAutocomplete(interaction) {
|
|
1012
|
-
const route =
|
|
1159
|
+
const route = buildSlashRoute(interaction);
|
|
1013
1160
|
const focused = interaction.options.getFocused(true);
|
|
1014
1161
|
const autocompleteKey = `${route}:${focused.name}`;
|
|
1015
1162
|
await this.processInteraction(interaction, () => autocompleteKey, (key) => this.autocompleteMap.get(key));
|
|
1016
1163
|
}
|
|
1017
|
-
// Build the route from commandName, subcommandGroup, subcommand
|
|
1018
|
-
buildSlashRoute(interaction) {
|
|
1019
|
-
const command = interaction.commandName;
|
|
1020
|
-
const group = interaction.options.getSubcommandGroup(false);
|
|
1021
|
-
const sub = interaction.options.getSubcommand(false);
|
|
1022
|
-
let route = command;
|
|
1023
|
-
if (group && sub) {
|
|
1024
|
-
route = `${route}/${group}/${sub}`;
|
|
1025
|
-
} else if (group) {
|
|
1026
|
-
route = `${route}/${group}`;
|
|
1027
|
-
} else if (sub) {
|
|
1028
|
-
route = `${route}/${sub}`;
|
|
1029
|
-
}
|
|
1030
|
-
return route;
|
|
1031
|
-
}
|
|
1032
1164
|
};
|
|
1033
1165
|
var EmojiInjector = class {
|
|
1034
1166
|
static {
|
|
@@ -1041,7 +1173,7 @@ var EmojiInjector = class {
|
|
|
1041
1173
|
}
|
|
1042
1174
|
async init() {
|
|
1043
1175
|
if (!this.core.config.bot.emojis || Object.keys(this.core.config.bot.emojis).length === 0) {
|
|
1044
|
-
this.logger.info(`${
|
|
1176
|
+
this.logger.info(`${chalk4.bold.green("Loaded")}: ${chalk4.magenta.bold("0")} emojis`);
|
|
1045
1177
|
return;
|
|
1046
1178
|
}
|
|
1047
1179
|
const configEmojis = this.core.config.bot.emojis;
|
|
@@ -1052,25 +1184,25 @@ var EmojiInjector = class {
|
|
|
1052
1184
|
if (emoji) {
|
|
1053
1185
|
configEmojis[key] = `<${emoji.identifier}>`;
|
|
1054
1186
|
foundCount++;
|
|
1055
|
-
this.logger.debug(`${
|
|
1187
|
+
this.logger.debug(`${chalk4.bold.green("Found")}: ${chalk4.magenta.bold(emojiName)} (${emoji.id})`);
|
|
1056
1188
|
}
|
|
1057
1189
|
});
|
|
1058
|
-
this.logger.info(`${
|
|
1190
|
+
this.logger.info(`${chalk4.bold.green("Loaded")}: ${chalk4.magenta.bold(foundCount)} emojis`);
|
|
1059
1191
|
}
|
|
1060
1192
|
};
|
|
1061
1193
|
|
|
1062
1194
|
// src/bot/Bot.ts
|
|
1063
|
-
function
|
|
1195
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
1064
1196
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1065
1197
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1066
1198
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1067
1199
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1068
1200
|
}
|
|
1069
|
-
__name(
|
|
1070
|
-
function
|
|
1201
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
1202
|
+
function _ts_metadata4(k, v) {
|
|
1071
1203
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1072
1204
|
}
|
|
1073
|
-
__name(
|
|
1205
|
+
__name(_ts_metadata4, "_ts_metadata");
|
|
1074
1206
|
var Bot = class extends Plugin {
|
|
1075
1207
|
static {
|
|
1076
1208
|
__name(this, "Bot");
|
|
@@ -1083,10 +1215,6 @@ var Bot = class extends Plugin {
|
|
|
1083
1215
|
events;
|
|
1084
1216
|
commands;
|
|
1085
1217
|
emojiInjector;
|
|
1086
|
-
/**
|
|
1087
|
-
* @param core - Seedcord core instance
|
|
1088
|
-
* @internal
|
|
1089
|
-
*/
|
|
1090
1218
|
constructor(core) {
|
|
1091
1219
|
super(core), this.core = core;
|
|
1092
1220
|
this._client = new Client(core.config.bot.clientOptions);
|
|
@@ -1097,9 +1225,9 @@ var Bot = class extends Plugin {
|
|
|
1097
1225
|
this.core.shutdown.addTask(ShutdownPhase.DiscordCleanup, "stop-bot", async () => await this.stop());
|
|
1098
1226
|
}
|
|
1099
1227
|
/**
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1228
|
+
* Initializes Discord client and all controllers
|
|
1229
|
+
* @internal
|
|
1230
|
+
*/
|
|
1103
1231
|
async init() {
|
|
1104
1232
|
if (this.isInitialized) {
|
|
1105
1233
|
return;
|
|
@@ -1113,40 +1241,40 @@ var Bot = class extends Plugin {
|
|
|
1113
1241
|
await this.emojiInjector.init();
|
|
1114
1242
|
}
|
|
1115
1243
|
/**
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1244
|
+
* Stops the bot and cleans up connections
|
|
1245
|
+
* @internal
|
|
1246
|
+
*/
|
|
1119
1247
|
async stop() {
|
|
1120
1248
|
this._client.removeAllListeners();
|
|
1121
1249
|
await this.logout();
|
|
1122
1250
|
}
|
|
1123
1251
|
/**
|
|
1124
|
-
|
|
1125
|
-
|
|
1252
|
+
* Logs the bot into Discord using the configured token
|
|
1253
|
+
*/
|
|
1126
1254
|
async login() {
|
|
1127
1255
|
await this._client.login(this.botToken);
|
|
1128
|
-
this.logger.info(`Logged in as ${
|
|
1256
|
+
this.logger.info(`Logged in as ${chalk4.bold.magenta(this._client.user?.username)}!`);
|
|
1129
1257
|
return this;
|
|
1130
1258
|
}
|
|
1131
1259
|
/**
|
|
1132
|
-
|
|
1133
|
-
|
|
1260
|
+
* Logs out and destroys the Discord client connection
|
|
1261
|
+
*/
|
|
1134
1262
|
async logout() {
|
|
1135
1263
|
await this._client.destroy();
|
|
1136
|
-
this.logger.info(
|
|
1264
|
+
this.logger.info(chalk4.bold.red("Logged out of Discord!"));
|
|
1137
1265
|
}
|
|
1138
1266
|
get client() {
|
|
1139
1267
|
return this._client;
|
|
1140
1268
|
}
|
|
1141
1269
|
};
|
|
1142
|
-
|
|
1270
|
+
_ts_decorate4([
|
|
1143
1271
|
Envapt("DISCORD_BOT_TOKEN", {
|
|
1144
1272
|
converter(raw, _fallback) {
|
|
1145
1273
|
if (typeof raw !== "string") throw new Error("Missing DISCORD_BOT_TOKEN");
|
|
1146
1274
|
return raw;
|
|
1147
1275
|
}
|
|
1148
1276
|
}),
|
|
1149
|
-
|
|
1277
|
+
_ts_metadata4("design:type", String)
|
|
1150
1278
|
], Bot.prototype, "botToken", void 0);
|
|
1151
1279
|
|
|
1152
1280
|
// src/effects/decorators/RegisterEffect.ts
|
|
@@ -1166,11 +1294,11 @@ var EffectsHandler = class {
|
|
|
1166
1294
|
data;
|
|
1167
1295
|
core;
|
|
1168
1296
|
/**
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1297
|
+
* Creates a new effects handler instance.
|
|
1298
|
+
*
|
|
1299
|
+
* @param data - The effect event data
|
|
1300
|
+
* @param core - The core framework instance
|
|
1301
|
+
*/
|
|
1174
1302
|
constructor(data, core) {
|
|
1175
1303
|
this.data = data;
|
|
1176
1304
|
this.core = core;
|
|
@@ -1190,35 +1318,55 @@ var WebhookLog = class extends EffectsHandler {
|
|
|
1190
1318
|
};
|
|
1191
1319
|
|
|
1192
1320
|
// src/effects/default/UnknownException.ts
|
|
1193
|
-
function
|
|
1321
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
1194
1322
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1195
1323
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1196
1324
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1197
1325
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1198
1326
|
}
|
|
1199
|
-
__name(
|
|
1200
|
-
function
|
|
1327
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
1328
|
+
function _ts_metadata5(k, v) {
|
|
1201
1329
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1202
1330
|
}
|
|
1203
|
-
__name(
|
|
1331
|
+
__name(_ts_metadata5, "_ts_metadata");
|
|
1204
1332
|
var UnknownException = class _UnknownException extends WebhookLog {
|
|
1205
1333
|
static {
|
|
1206
1334
|
__name(this, "UnknownException");
|
|
1207
1335
|
}
|
|
1336
|
+
static logger = new Logger("Effect: UnknownException");
|
|
1208
1337
|
webhook = new WebhookClient({
|
|
1209
1338
|
url: _UnknownException.unknownExceptionWebhookUrl
|
|
1210
1339
|
});
|
|
1211
1340
|
async execute() {
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1341
|
+
const metadataFile = this.prepareMetadataFile();
|
|
1342
|
+
try {
|
|
1343
|
+
await this.webhook.send({
|
|
1344
|
+
flags: "IsComponentsV2",
|
|
1345
|
+
withComponents: true,
|
|
1346
|
+
username: "Unknown Exception",
|
|
1347
|
+
avatarURL: "https://cdn.discordapp.com/attachments/1351446034827579466/1351446912947191830/warning-2.png",
|
|
1348
|
+
components: [
|
|
1349
|
+
new UnhandledErrorContainer(this.data).component
|
|
1350
|
+
],
|
|
1351
|
+
files: metadataFile ? [
|
|
1352
|
+
metadataFile
|
|
1353
|
+
] : []
|
|
1354
|
+
});
|
|
1355
|
+
} catch (error) {
|
|
1356
|
+
_UnknownException.logger.error("Failed to send unknown exception webhook", error);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
prepareMetadataFile() {
|
|
1360
|
+
const { metadata } = this.data;
|
|
1361
|
+
if (!metadata) return null;
|
|
1362
|
+
const content = filterCirculars(metadata);
|
|
1363
|
+
return new AttachmentBuilder(Buffer.from(JSON.stringify(content, void 0, 2), "utf-8"), {
|
|
1364
|
+
name: "metadata.json",
|
|
1365
|
+
description: "Metadata associated with the error"
|
|
1218
1366
|
});
|
|
1219
1367
|
}
|
|
1220
1368
|
};
|
|
1221
|
-
|
|
1369
|
+
_ts_decorate5([
|
|
1222
1370
|
Envapt("UNKNOWN_EXCEPTION_WEBHOOK_URL", {
|
|
1223
1371
|
converter(raw, _fallback) {
|
|
1224
1372
|
if (!raw) throw new Error("Missing UNKNOWN_EXCEPTION_WEBHOOK_URL");
|
|
@@ -1226,27 +1374,38 @@ _ts_decorate4([
|
|
|
1226
1374
|
return raw;
|
|
1227
1375
|
}
|
|
1228
1376
|
}),
|
|
1229
|
-
|
|
1377
|
+
_ts_metadata5("design:type", String)
|
|
1230
1378
|
], UnknownException, "unknownExceptionWebhookUrl", void 0);
|
|
1231
|
-
UnknownException =
|
|
1379
|
+
UnknownException = _ts_decorate5([
|
|
1232
1380
|
RegisterEffect("unknownException")
|
|
1233
1381
|
], UnknownException);
|
|
1234
|
-
var
|
|
1382
|
+
var DefaultSeparator = class DefaultSeparator2 extends BuilderComponent {
|
|
1235
1383
|
static {
|
|
1236
|
-
__name(this, "
|
|
1384
|
+
__name(this, "DefaultSeparator");
|
|
1385
|
+
}
|
|
1386
|
+
constructor() {
|
|
1387
|
+
super("separator");
|
|
1388
|
+
this.instance.setSpacing(SeparatorSpacingSize.Small).setDivider(true);
|
|
1389
|
+
}
|
|
1390
|
+
};
|
|
1391
|
+
var UnhandledErrorContainer = class UnhandledErrorContainer2 extends BuilderComponent {
|
|
1392
|
+
static {
|
|
1393
|
+
__name(this, "UnhandledErrorContainer");
|
|
1237
1394
|
}
|
|
1238
1395
|
constructor(data) {
|
|
1239
|
-
super("
|
|
1240
|
-
const { uuid, error, guild, user } = data;
|
|
1241
|
-
this.instance.
|
|
1396
|
+
super("container");
|
|
1397
|
+
const { uuid, error, guild, user, metadata } = data;
|
|
1398
|
+
this.instance.addTextDisplayComponents((text) => text.setContent(`### An unknown exception was thrown
|
|
1399
|
+
**Guild ID:** \`${guild?.id ?? "Not used in a guild"}\`
|
|
1242
1400
|
**Guild Name:** ${guild?.name ?? "Not used in a guild"}
|
|
1243
1401
|
**User ID:** \`${user?.id ?? "Missing user info"}\`
|
|
1244
1402
|
**Username:** ${user?.username ?? "Missing user info"}
|
|
1245
|
-
|
|
1246
|
-
\`\`\`${error.stack}\`\`\``);
|
|
1247
|
-
this.
|
|
1403
|
+
`)).addSeparatorComponents(new DefaultSeparator().component).addTextDisplayComponents((text) => text.setContent(`### UUID \`${uuid}\`
|
|
1404
|
+
\`\`\`${error.stack}\`\`\``));
|
|
1405
|
+
this.addTimestampsIfAvailable(error);
|
|
1406
|
+
this.addMetadataIfAvailable(metadata);
|
|
1248
1407
|
}
|
|
1249
|
-
|
|
1408
|
+
addTimestampsIfAvailable(error) {
|
|
1250
1409
|
if (!(error instanceof DiscordAPIError)) return;
|
|
1251
1410
|
const now = Date.now();
|
|
1252
1411
|
const snowflake = error.url.match(/\/interactions\/(\d+)\//)?.[1];
|
|
@@ -1255,15 +1414,14 @@ var UnhandledErrorEmbed = class UnhandledErrorEmbed2 extends BuilderComponent {
|
|
|
1255
1414
|
const diff = now - interactionTs;
|
|
1256
1415
|
const seconds = Math.floor(diff / 1e3);
|
|
1257
1416
|
const millis = diff % 1e3;
|
|
1258
|
-
this.instance.
|
|
1259
|
-
|
|
1260
|
-
name: "Timestamps",
|
|
1261
|
-
value: `- **\`Interaction sent\` :** ${new Date(interactionTs).toISOString()} (${interactionTs})
|
|
1417
|
+
this.instance.addSeparatorComponents(new DefaultSeparator().component).addTextDisplayComponents((text) => text.setContent(`### Timestamps
|
|
1418
|
+
- **\`Interaction sent\` :** ${new Date(interactionTs).toISOString()} (${interactionTs})
|
|
1262
1419
|
- **\`Error logged \` :** ${new Date(now).toISOString()} (${now})
|
|
1263
|
-
- **\`Offset \` :** ${seconds}s ${millis}ms
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1420
|
+
- **\`Offset \` :** ${seconds}s ${millis}ms`));
|
|
1421
|
+
}
|
|
1422
|
+
addMetadataIfAvailable(metadata) {
|
|
1423
|
+
if (!metadata) return;
|
|
1424
|
+
this.instance.addSeparatorComponents(new DefaultSeparator().component).addTextDisplayComponents((text) => text.setContent("### Metadata")).addFileComponents((file) => file.setURL("attachment://metadata.json"));
|
|
1267
1425
|
}
|
|
1268
1426
|
};
|
|
1269
1427
|
var EffectsEmitter = class {
|
|
@@ -1272,37 +1430,37 @@ var EffectsEmitter = class {
|
|
|
1272
1430
|
}
|
|
1273
1431
|
emitter = new EventEmitter();
|
|
1274
1432
|
/**
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1433
|
+
* Registers a listener for the specified side effect.
|
|
1434
|
+
*
|
|
1435
|
+
* @typeParam KeyOfEffects - The side effect name type
|
|
1436
|
+
* @param event - The side effect name to listen for
|
|
1437
|
+
* @param listener - Function to call when the event is emitted
|
|
1438
|
+
* @returns This EffectsEmitter instance for chaining
|
|
1439
|
+
*/
|
|
1282
1440
|
on(event, listener) {
|
|
1283
1441
|
this.emitter.on(event, listener);
|
|
1284
1442
|
return this;
|
|
1285
1443
|
}
|
|
1286
1444
|
/**
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1445
|
+
* Registers a one-time listener for the specified side effect.
|
|
1446
|
+
*
|
|
1447
|
+
* @typeParam KeyOfEffects - The side effect name type
|
|
1448
|
+
* @param event - The side effect name to listen for once
|
|
1449
|
+
* @param listener - Function to call when the event is emitted
|
|
1450
|
+
* @returns This EffectsEmitter instance for chaining
|
|
1451
|
+
*/
|
|
1294
1452
|
once(event, listener) {
|
|
1295
1453
|
this.emitter.once(event, listener);
|
|
1296
1454
|
return this;
|
|
1297
1455
|
}
|
|
1298
1456
|
/**
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1457
|
+
* Emits a side effect with the provided data.
|
|
1458
|
+
*
|
|
1459
|
+
* @typeParam KeyOfEffects - The side effect name type
|
|
1460
|
+
* @param event - The side effect name to emit
|
|
1461
|
+
* @param data - The data to pass to registered listeners
|
|
1462
|
+
* @returns True if the event had listeners, false otherwise
|
|
1463
|
+
*/
|
|
1306
1464
|
emit(event, data) {
|
|
1307
1465
|
return this.emitter.emit(event, data);
|
|
1308
1466
|
}
|
|
@@ -1325,12 +1483,12 @@ var EffectsRegistry = class extends Plugin {
|
|
|
1325
1483
|
if (this.isInitialized) return;
|
|
1326
1484
|
this.isInitialized = true;
|
|
1327
1485
|
const effectsDir = this.core.config.effects.path;
|
|
1328
|
-
this.logger.info(
|
|
1486
|
+
this.logger.info(chalk4.bold(effectsDir));
|
|
1329
1487
|
this.registerEffect("unknownException", UnknownException);
|
|
1330
1488
|
await this.loadEffects(effectsDir);
|
|
1331
1489
|
this.attachEffects();
|
|
1332
1490
|
const totalEffects = Array.from(this.effectsMap.values()).reduce((acc, handlers) => acc + handlers.length, 0);
|
|
1333
|
-
this.logger.info(`${
|
|
1491
|
+
this.logger.info(`${chalk4.bold.green("Loaded")}: ${chalk4.bold.magenta(totalEffects)} side effects`);
|
|
1334
1492
|
}
|
|
1335
1493
|
async loadEffects(dir) {
|
|
1336
1494
|
await traverseDirectory(dir, (_fullPath, relativePath, imported) => {
|
|
@@ -1340,7 +1498,7 @@ var EffectsRegistry = class extends Plugin {
|
|
|
1340
1498
|
const effectName = Reflect.getMetadata(EffectMetadataKey, val);
|
|
1341
1499
|
if (effectName) {
|
|
1342
1500
|
this.registerEffect(effectName, val);
|
|
1343
|
-
this.logger.info(`${
|
|
1501
|
+
this.logger.info(`${chalk4.italic("Registered")} ${chalk4.bold.yellow(val.name)} from ${chalk4.gray(relativePath)}`);
|
|
1344
1502
|
}
|
|
1345
1503
|
}
|
|
1346
1504
|
}
|
|
@@ -1395,11 +1553,11 @@ var Seedcord = class _Seedcord extends Pluggable {
|
|
|
1395
1553
|
/** @see {@link HealthCheck} */
|
|
1396
1554
|
healthCheck;
|
|
1397
1555
|
/**
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1556
|
+
* Creates a new Seedcord instance
|
|
1557
|
+
*
|
|
1558
|
+
* @param config - Bot configuration including paths and Discord client options
|
|
1559
|
+
* @throws An {@link Error} When attempting to create multiple instances (singleton)
|
|
1560
|
+
*/
|
|
1403
1561
|
constructor(config) {
|
|
1404
1562
|
const shutdown = new CoordinatedShutdown();
|
|
1405
1563
|
const startup = new CoordinatedStartup();
|
|
@@ -1416,31 +1574,31 @@ var Seedcord = class _Seedcord extends Pluggable {
|
|
|
1416
1574
|
this.registerStartupTasks();
|
|
1417
1575
|
}
|
|
1418
1576
|
/**
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1577
|
+
* Registers default startup tasks
|
|
1578
|
+
* @internal
|
|
1579
|
+
*/
|
|
1422
1580
|
registerStartupTasks() {
|
|
1423
1581
|
this.startup.addTask(StartupPhase.Configuration, "Effect Initialization", async () => {
|
|
1424
|
-
this.effects.logger.info(
|
|
1582
|
+
this.effects.logger.info(chalk4.bold("Initializing"));
|
|
1425
1583
|
await this.effects.init();
|
|
1426
|
-
this.effects.logger.info(
|
|
1584
|
+
this.effects.logger.info(chalk4.bold("Initialized"));
|
|
1427
1585
|
});
|
|
1428
1586
|
this.startup.addTask(StartupPhase.Instantiation, "Bot Initialization", async () => {
|
|
1429
|
-
this.bot.logger.info(
|
|
1587
|
+
this.bot.logger.info(chalk4.bold("Initializing"));
|
|
1430
1588
|
await this.bot.init();
|
|
1431
|
-
this.bot.logger.info(
|
|
1589
|
+
this.bot.logger.info(chalk4.bold("Initialized"));
|
|
1432
1590
|
});
|
|
1433
1591
|
this.startup.addTask(StartupPhase.Ready, "Health Check", async () => {
|
|
1434
|
-
this.healthCheck.logger.info(
|
|
1592
|
+
this.healthCheck.logger.info(chalk4.bold("Initializing"));
|
|
1435
1593
|
await this.healthCheck.init();
|
|
1436
|
-
this.healthCheck.logger.info(
|
|
1594
|
+
this.healthCheck.logger.info(chalk4.bold("Initialized"));
|
|
1437
1595
|
});
|
|
1438
1596
|
}
|
|
1439
1597
|
/**
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1598
|
+
* Starts the bot and runs all initialization tasks
|
|
1599
|
+
*
|
|
1600
|
+
* @returns This Seedcord instance when fully initialized
|
|
1601
|
+
*/
|
|
1444
1602
|
async start() {
|
|
1445
1603
|
await super.init();
|
|
1446
1604
|
return this;
|
|
@@ -1470,7 +1628,7 @@ function EventCatchable(log) {
|
|
|
1470
1628
|
this.getEvent()
|
|
1471
1629
|
];
|
|
1472
1630
|
const msg = eventArgs.find((x) => x instanceof Message);
|
|
1473
|
-
const { response } =
|
|
1631
|
+
const { response } = extractErrorResponse(err, this.core, msg?.guild ?? null, msg?.author ?? null, eventArgs);
|
|
1474
1632
|
if (!msg) return;
|
|
1475
1633
|
await msg.reply({
|
|
1476
1634
|
embeds: [
|
|
@@ -1483,6 +1641,232 @@ function EventCatchable(log) {
|
|
|
1483
1641
|
};
|
|
1484
1642
|
}
|
|
1485
1643
|
__name(EventCatchable, "EventCatchable");
|
|
1644
|
+
|
|
1645
|
+
// src/bot/errors/Channels.ts
|
|
1646
|
+
var ChannelNotFoundError = class extends CustomError {
|
|
1647
|
+
static {
|
|
1648
|
+
__name(this, "ChannelNotFoundError");
|
|
1649
|
+
}
|
|
1650
|
+
channelId;
|
|
1651
|
+
/**
|
|
1652
|
+
* Creates a new ChannelNotFoundError.
|
|
1653
|
+
*
|
|
1654
|
+
* @param message - The error message
|
|
1655
|
+
* @param channelId - The ID of the channel that could not be found
|
|
1656
|
+
*/
|
|
1657
|
+
constructor(message, channelId) {
|
|
1658
|
+
super(message), this.channelId = channelId;
|
|
1659
|
+
this.response.setDescription(`Channel with ID \`${this.channelId}\` not found.`);
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
var CannotSendEmbedsError = class extends CustomError {
|
|
1663
|
+
static {
|
|
1664
|
+
__name(this, "CannotSendEmbedsError");
|
|
1665
|
+
}
|
|
1666
|
+
channelId;
|
|
1667
|
+
/**
|
|
1668
|
+
* Creates a new CannotSendEmbedsError.
|
|
1669
|
+
*
|
|
1670
|
+
* @param message - The error message
|
|
1671
|
+
* @param channelId - The ID of the channel where embeds cannot be sent
|
|
1672
|
+
*/
|
|
1673
|
+
constructor(message, channelId) {
|
|
1674
|
+
super(message), this.channelId = channelId;
|
|
1675
|
+
this.response.setDescription(`Cannot send embeds in <#${this.channelId}>.
|
|
1676
|
+
|
|
1677
|
+
Please ensure I have the following permissions:
|
|
1678
|
+
\u2022 View Channel
|
|
1679
|
+
\u2022 Send Messages
|
|
1680
|
+
\u2022 Embed Links
|
|
1681
|
+
\u2022 Attach Files
|
|
1682
|
+
\u2022 Read Message History
|
|
1683
|
+
\u2022 Use External Emojis
|
|
1684
|
+
`);
|
|
1685
|
+
}
|
|
1686
|
+
};
|
|
1687
|
+
var CouldNotFindChannel = class extends CustomError {
|
|
1688
|
+
static {
|
|
1689
|
+
__name(this, "CouldNotFindChannel");
|
|
1690
|
+
}
|
|
1691
|
+
channelId;
|
|
1692
|
+
/**
|
|
1693
|
+
* Creates a new CouldNotFindChannel error.
|
|
1694
|
+
*
|
|
1695
|
+
* @param message - The error message
|
|
1696
|
+
* @param channelId - The ID of the channel that could not be found
|
|
1697
|
+
*/
|
|
1698
|
+
constructor(message, channelId) {
|
|
1699
|
+
super(message), this.channelId = channelId;
|
|
1700
|
+
this.response.setDescription(`Could not find channel with ID \`${this.channelId}\`. It could also be that the channel is not a text channel.`);
|
|
1701
|
+
}
|
|
1702
|
+
};
|
|
1703
|
+
var ChannelNotTextChannel = class extends CustomError {
|
|
1704
|
+
static {
|
|
1705
|
+
__name(this, "ChannelNotTextChannel");
|
|
1706
|
+
}
|
|
1707
|
+
channelId;
|
|
1708
|
+
/**
|
|
1709
|
+
* Creates a new ChannelNotTextChannel error.
|
|
1710
|
+
*
|
|
1711
|
+
* @param message - The error message
|
|
1712
|
+
* @param channelId - The ID of the channel that is not a text channel
|
|
1713
|
+
*/
|
|
1714
|
+
constructor(message, channelId) {
|
|
1715
|
+
super(message), this.channelId = channelId;
|
|
1716
|
+
this.response.setDescription(`Channel with ID \`${this.channelId}\` is not a text channel.`);
|
|
1717
|
+
}
|
|
1718
|
+
};
|
|
1719
|
+
var MissingPermissions = class extends CustomError {
|
|
1720
|
+
static {
|
|
1721
|
+
__name(this, "MissingPermissions");
|
|
1722
|
+
}
|
|
1723
|
+
missingPerms;
|
|
1724
|
+
roleOrChannel;
|
|
1725
|
+
/**
|
|
1726
|
+
* Creates a new BotMissingPermissionsError.
|
|
1727
|
+
*
|
|
1728
|
+
* @param message - The error message
|
|
1729
|
+
* @param missingPerms - Array of missing permission names
|
|
1730
|
+
* @param roleOrChannel - The role or channel where permissions are missing
|
|
1731
|
+
*/
|
|
1732
|
+
constructor(message, missingPerms, roleOrChannel) {
|
|
1733
|
+
super(message), this.missingPerms = missingPerms, this.roleOrChannel = roleOrChannel;
|
|
1734
|
+
const missing = this.missingPerms.map((perm) => `\u2022 ${perm}`).join("\n");
|
|
1735
|
+
const errorSubtext = this.roleOrChannel instanceof Role ? `My role, <@&${this.roleOrChannel.id}>, is missing the following permissions:` : `I am missing the following permissions in <#${this.roleOrChannel.id}>:`;
|
|
1736
|
+
this.response.setDescription(`${errorSubtext}
|
|
1737
|
+
|
|
1738
|
+
Please ensure I have the following missing permission(s):
|
|
1739
|
+
${missing}`);
|
|
1740
|
+
}
|
|
1741
|
+
};
|
|
1742
|
+
var RoleHigherThanMe = class extends CustomError {
|
|
1743
|
+
static {
|
|
1744
|
+
__name(this, "RoleHigherThanMe");
|
|
1745
|
+
}
|
|
1746
|
+
role;
|
|
1747
|
+
botRole;
|
|
1748
|
+
/**
|
|
1749
|
+
* Creates a new RoleHigherThanMe error.
|
|
1750
|
+
*
|
|
1751
|
+
* @param message - The error message
|
|
1752
|
+
*/
|
|
1753
|
+
constructor(message, role, botRole) {
|
|
1754
|
+
super(message), this.role = role, this.botRole = botRole;
|
|
1755
|
+
this.response.setDescription(`I cannot assign a role that is higher than me.
|
|
1756
|
+
|
|
1757
|
+
The role <@&${this.role.id}> is higher than my role <@&${this.botRole.id}> in the hierarchy.`);
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
var CannotAssignBotRole = class extends CustomError {
|
|
1761
|
+
static {
|
|
1762
|
+
__name(this, "CannotAssignBotRole");
|
|
1763
|
+
}
|
|
1764
|
+
/**
|
|
1765
|
+
* Creates a new CannotAssignBotRole error.
|
|
1766
|
+
*
|
|
1767
|
+
* @param message - The error message
|
|
1768
|
+
*/
|
|
1769
|
+
constructor(message = "I cannot assign a managed role.") {
|
|
1770
|
+
super(message);
|
|
1771
|
+
this.response.setDescription("I cannot assign a managed role.");
|
|
1772
|
+
}
|
|
1773
|
+
};
|
|
1774
|
+
var RoleDoesNotExist = class extends CustomError {
|
|
1775
|
+
static {
|
|
1776
|
+
__name(this, "RoleDoesNotExist");
|
|
1777
|
+
}
|
|
1778
|
+
roleId;
|
|
1779
|
+
/**
|
|
1780
|
+
* Creates a new RoleDoesNotExist error.
|
|
1781
|
+
*
|
|
1782
|
+
* @param message - The error message
|
|
1783
|
+
* @param roleId - The ID of the role that doesn't exist
|
|
1784
|
+
*/
|
|
1785
|
+
constructor(message, roleId) {
|
|
1786
|
+
super(message), this.roleId = roleId;
|
|
1787
|
+
this.response.setDescription(`The role with ID \`${this.roleId}\` does not exist.`);
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1790
|
+
var HasDangerousPermissions = class extends CustomError {
|
|
1791
|
+
static {
|
|
1792
|
+
__name(this, "HasDangerousPermissions");
|
|
1793
|
+
}
|
|
1794
|
+
role;
|
|
1795
|
+
dangerousPerms;
|
|
1796
|
+
/**
|
|
1797
|
+
* Creates a new HasDangerousPermissions error.
|
|
1798
|
+
*
|
|
1799
|
+
* @param message - The error message
|
|
1800
|
+
* @param role - The role with dangerous permissions
|
|
1801
|
+
* @param dangerousPerms - Array of dangerous permission names
|
|
1802
|
+
*/
|
|
1803
|
+
constructor(message, role, dangerousPerms) {
|
|
1804
|
+
super(message), this.role = role, this.dangerousPerms = dangerousPerms;
|
|
1805
|
+
const dangerous = this.dangerousPerms.map((perm) => `\u2022 ${perm}`).join("\n");
|
|
1806
|
+
this.response.setDescription(`The role <@&${this.role.id}> has the following dangerous permissions:
|
|
1807
|
+
|
|
1808
|
+
Please ensure the following dangerous permission(s) are not enabled:
|
|
1809
|
+
${dangerous}`);
|
|
1810
|
+
}
|
|
1811
|
+
};
|
|
1812
|
+
|
|
1813
|
+
// src/bot/errors/User.ts
|
|
1814
|
+
var UserNotInGuild = class extends CustomError {
|
|
1815
|
+
static {
|
|
1816
|
+
__name(this, "UserNotInGuild");
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Creates a new UserNotInGuild error.
|
|
1820
|
+
*
|
|
1821
|
+
* @param message - The error message
|
|
1822
|
+
*/
|
|
1823
|
+
constructor(message = "User is not in the guild.") {
|
|
1824
|
+
super(message);
|
|
1825
|
+
this.response.setDescription("User is not in the guild.");
|
|
1826
|
+
}
|
|
1827
|
+
};
|
|
1828
|
+
var UserNotFound = class extends CustomError {
|
|
1829
|
+
static {
|
|
1830
|
+
__name(this, "UserNotFound");
|
|
1831
|
+
}
|
|
1832
|
+
userArg;
|
|
1833
|
+
/**
|
|
1834
|
+
* Creates a new UserNotFound error.
|
|
1835
|
+
*
|
|
1836
|
+
* @param userArg - The user argument that could not be resolved
|
|
1837
|
+
*/
|
|
1838
|
+
constructor(userArg) {
|
|
1839
|
+
super(`User not found: ${userArg}`), this.userArg = userArg;
|
|
1840
|
+
this.response.setTitle("User Not Found").setDescription(`User probably doesn't exist or was deleted.
|
|
1841
|
+
**User Argument:** \`${this.userArg}\`
|
|
1842
|
+
Please check the user ID and try again. Only pass valid user IDs as the argument.`);
|
|
1843
|
+
}
|
|
1844
|
+
};
|
|
1845
|
+
async function fetchText(client, channelId) {
|
|
1846
|
+
if (channelId instanceof TextChannel) {
|
|
1847
|
+
return channelId;
|
|
1848
|
+
}
|
|
1849
|
+
let channel = client.channels.cache.get(channelId);
|
|
1850
|
+
if (!channel) {
|
|
1851
|
+
try {
|
|
1852
|
+
channel = await client.channels.fetch(channelId);
|
|
1853
|
+
} catch {
|
|
1854
|
+
throw new CouldNotFindChannel("Channel not found or not a text channel", channelId);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
if (channel?.isTextBased()) {
|
|
1858
|
+
return channel;
|
|
1859
|
+
}
|
|
1860
|
+
throw new CouldNotFindChannel("Channel not found or not a text channel", channelId);
|
|
1861
|
+
}
|
|
1862
|
+
__name(fetchText, "fetchText");
|
|
1863
|
+
|
|
1864
|
+
// src/bot/utilities/channels/sendInText.ts
|
|
1865
|
+
async function sendInText(client, channelId, message) {
|
|
1866
|
+
const channel = await fetchText(client, channelId);
|
|
1867
|
+
return await channel.send(message);
|
|
1868
|
+
}
|
|
1869
|
+
__name(sendInText, "sendInText");
|
|
1486
1870
|
function throwCustomError(error, message, CustomError2) {
|
|
1487
1871
|
const uuid = crypto.randomUUID();
|
|
1488
1872
|
Logger.Error("Throwing Custom Error", error.name);
|
|
@@ -1499,6 +1883,265 @@ function throwCustomError(error, message, CustomError2) {
|
|
|
1499
1883
|
}
|
|
1500
1884
|
__name(throwCustomError, "throwCustomError");
|
|
1501
1885
|
|
|
1502
|
-
|
|
1886
|
+
// src/bot/utilities/messages/attemptSendDM.ts
|
|
1887
|
+
async function attemptSendDM(user, content) {
|
|
1888
|
+
const payload = {
|
|
1889
|
+
...content.content !== void 0 && {
|
|
1890
|
+
content: content.content
|
|
1891
|
+
},
|
|
1892
|
+
...content.embeds !== void 0 && {
|
|
1893
|
+
embeds: [
|
|
1894
|
+
...content.embeds
|
|
1895
|
+
]
|
|
1896
|
+
},
|
|
1897
|
+
...content.components !== void 0 && {
|
|
1898
|
+
components: [
|
|
1899
|
+
...content.components
|
|
1900
|
+
]
|
|
1901
|
+
}
|
|
1902
|
+
};
|
|
1903
|
+
try {
|
|
1904
|
+
return await user.send(payload);
|
|
1905
|
+
} catch {
|
|
1906
|
+
return null;
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
__name(attemptSendDM, "attemptSendDM");
|
|
1910
|
+
var PermissionNames = new Map(Object.entries(PermissionFlagsBits).map(([key, bit]) => [
|
|
1911
|
+
bit,
|
|
1912
|
+
prettify(key)
|
|
1913
|
+
]));
|
|
1914
|
+
var PERM_GROUPS = {
|
|
1915
|
+
manage: /* @__PURE__ */ new Map([
|
|
1916
|
+
[
|
|
1917
|
+
PermissionFlagsBits.ManageChannels,
|
|
1918
|
+
"Manage Channels"
|
|
1919
|
+
],
|
|
1920
|
+
[
|
|
1921
|
+
PermissionFlagsBits.ManageRoles,
|
|
1922
|
+
"Manage Roles"
|
|
1923
|
+
],
|
|
1924
|
+
[
|
|
1925
|
+
PermissionFlagsBits.ManageWebhooks,
|
|
1926
|
+
"Manage Webhooks"
|
|
1927
|
+
],
|
|
1928
|
+
[
|
|
1929
|
+
PermissionFlagsBits.ManageMessages,
|
|
1930
|
+
"Manage Messages"
|
|
1931
|
+
],
|
|
1932
|
+
[
|
|
1933
|
+
PermissionFlagsBits.ManageNicknames,
|
|
1934
|
+
"Manage Nicknames"
|
|
1935
|
+
]
|
|
1936
|
+
]),
|
|
1937
|
+
embed: /* @__PURE__ */ new Map([
|
|
1938
|
+
[
|
|
1939
|
+
PermissionFlagsBits.ViewChannel,
|
|
1940
|
+
"View Channel"
|
|
1941
|
+
],
|
|
1942
|
+
[
|
|
1943
|
+
PermissionFlagsBits.SendMessages,
|
|
1944
|
+
"Send Messages"
|
|
1945
|
+
],
|
|
1946
|
+
[
|
|
1947
|
+
PermissionFlagsBits.EmbedLinks,
|
|
1948
|
+
"Embed Links"
|
|
1949
|
+
],
|
|
1950
|
+
[
|
|
1951
|
+
PermissionFlagsBits.AttachFiles,
|
|
1952
|
+
"Attach Files"
|
|
1953
|
+
],
|
|
1954
|
+
[
|
|
1955
|
+
PermissionFlagsBits.UseExternalEmojis,
|
|
1956
|
+
"Use External Emojis"
|
|
1957
|
+
],
|
|
1958
|
+
[
|
|
1959
|
+
PermissionFlagsBits.ReadMessageHistory,
|
|
1960
|
+
"Read Message History"
|
|
1961
|
+
]
|
|
1962
|
+
]),
|
|
1963
|
+
others: /* @__PURE__ */ new Map([
|
|
1964
|
+
[
|
|
1965
|
+
PermissionFlagsBits.AddReactions,
|
|
1966
|
+
"Add Reactions"
|
|
1967
|
+
],
|
|
1968
|
+
[
|
|
1969
|
+
PermissionFlagsBits.UseApplicationCommands,
|
|
1970
|
+
"Use Application Commands"
|
|
1971
|
+
]
|
|
1972
|
+
])
|
|
1973
|
+
};
|
|
1974
|
+
function checkPermissions(client, roleOrChannel, scope = "all", inverse = false) {
|
|
1975
|
+
let required;
|
|
1976
|
+
if (Array.isArray(scope)) {
|
|
1977
|
+
required = /* @__PURE__ */ new Map();
|
|
1978
|
+
for (const bit of scope) {
|
|
1979
|
+
const name = PermissionNames.get(bit);
|
|
1980
|
+
if (name) required.set(bit, name);
|
|
1981
|
+
}
|
|
1982
|
+
} else {
|
|
1983
|
+
switch (scope) {
|
|
1984
|
+
case "manage":
|
|
1985
|
+
required = PERM_GROUPS.manage;
|
|
1986
|
+
break;
|
|
1987
|
+
case "embed":
|
|
1988
|
+
required = PERM_GROUPS.embed;
|
|
1989
|
+
break;
|
|
1990
|
+
case "others":
|
|
1991
|
+
required = new Map([
|
|
1992
|
+
...PERM_GROUPS.others,
|
|
1993
|
+
...PERM_GROUPS.embed
|
|
1994
|
+
]);
|
|
1995
|
+
break;
|
|
1996
|
+
default:
|
|
1997
|
+
required = new Map([
|
|
1998
|
+
...PERM_GROUPS.manage,
|
|
1999
|
+
...PERM_GROUPS.others,
|
|
2000
|
+
...PERM_GROUPS.embed
|
|
2001
|
+
]);
|
|
2002
|
+
break;
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
let permissions;
|
|
2006
|
+
if (roleOrChannel instanceof Role) {
|
|
2007
|
+
permissions = roleOrChannel.permissions;
|
|
2008
|
+
} else {
|
|
2009
|
+
if (!client.user) throw new Error("Client user is not available");
|
|
2010
|
+
permissions = roleOrChannel.permissionsFor(client.user, true);
|
|
2011
|
+
}
|
|
2012
|
+
if (!permissions) {
|
|
2013
|
+
throw new MissingPermissions("Missing Permissions", Array.from(required.values()), roleOrChannel);
|
|
2014
|
+
}
|
|
2015
|
+
if (inverse) {
|
|
2016
|
+
const dangerous = Array.from(required.entries()).filter(([bit]) => permissions.has(bit, true)).map(([, name]) => name);
|
|
2017
|
+
if (dangerous.length > 0) {
|
|
2018
|
+
throw new HasDangerousPermissions("Role has dangerous permissions", roleOrChannel, dangerous);
|
|
2019
|
+
}
|
|
2020
|
+
} else {
|
|
2021
|
+
const missing = Array.from(required.entries()).filter(([bit]) => !permissions.has(bit, true)).map(([, name]) => name);
|
|
2022
|
+
if (missing.length > 0) {
|
|
2023
|
+
throw new MissingPermissions("Missing Permissions", missing, roleOrChannel);
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
__name(checkPermissions, "checkPermissions");
|
|
2028
|
+
|
|
2029
|
+
// src/bot/utilities/roles/getBotRole.ts
|
|
2030
|
+
function getBotRole(client, guild) {
|
|
2031
|
+
if (!client.user) throw new Error("Client user is not available");
|
|
2032
|
+
const botRole = guild.roles.botRoleFor(client.user);
|
|
2033
|
+
if (!botRole) throw new Error("Bot role not found in guild");
|
|
2034
|
+
return botRole;
|
|
2035
|
+
}
|
|
2036
|
+
__name(getBotRole, "getBotRole");
|
|
2037
|
+
|
|
2038
|
+
// src/bot/utilities/roles/checkBotPermissions.ts
|
|
2039
|
+
function checkBotPermissions(client, guildOrChannel, scope = "all", inverse = false) {
|
|
2040
|
+
if (guildOrChannel instanceof Guild) {
|
|
2041
|
+
const botRole = getBotRole(client, guildOrChannel);
|
|
2042
|
+
checkPermissions(client, botRole, scope, inverse);
|
|
2043
|
+
} else {
|
|
2044
|
+
checkPermissions(client, guildOrChannel, scope);
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
__name(checkBotPermissions, "checkBotPermissions");
|
|
2048
|
+
async function fetchRole(clientOrGuild, roleId) {
|
|
2049
|
+
let role;
|
|
2050
|
+
if (!roleId) {
|
|
2051
|
+
throw new RoleDoesNotExist("Role ID is null or undefined", roleId);
|
|
2052
|
+
}
|
|
2053
|
+
if (clientOrGuild instanceof Guild) {
|
|
2054
|
+
const guild = clientOrGuild;
|
|
2055
|
+
role = guild.roles.cache.get(roleId);
|
|
2056
|
+
if (!role) {
|
|
2057
|
+
try {
|
|
2058
|
+
role = await guild.roles.fetch(roleId);
|
|
2059
|
+
} catch {
|
|
2060
|
+
throw new RoleDoesNotExist("Role not found in specified guild", roleId);
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
} else {
|
|
2064
|
+
const client = clientOrGuild;
|
|
2065
|
+
role = client.guilds.cache.map((guild) => guild.roles.cache.get(roleId)).find((role2) => role2);
|
|
2066
|
+
if (!role) {
|
|
2067
|
+
const guilds = client.guilds.cache;
|
|
2068
|
+
for (const guild of guilds.values()) {
|
|
2069
|
+
try {
|
|
2070
|
+
role = await guild.roles.fetch(roleId);
|
|
2071
|
+
if (role) break;
|
|
2072
|
+
} catch {
|
|
2073
|
+
continue;
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
if (!role) {
|
|
2079
|
+
throw new RoleDoesNotExist("Role not found", roleId);
|
|
2080
|
+
}
|
|
2081
|
+
return role;
|
|
2082
|
+
}
|
|
2083
|
+
__name(fetchRole, "fetchRole");
|
|
2084
|
+
function hasPermsToAssign(targetRole) {
|
|
2085
|
+
const botRole = getBotRole(targetRole.client, targetRole.guild);
|
|
2086
|
+
if (targetRole.comparePositionTo(botRole) >= 0) {
|
|
2087
|
+
throw new RoleHigherThanMe("Role is higher than me", targetRole, botRole);
|
|
2088
|
+
}
|
|
2089
|
+
if (targetRole.managed) {
|
|
2090
|
+
throw new CannotAssignBotRole(`Cannot assign bot role ${targetRole.name}`);
|
|
2091
|
+
}
|
|
2092
|
+
checkBotPermissions(targetRole.client, targetRole.guild, [
|
|
2093
|
+
PermissionFlagsBits.ManageRoles
|
|
2094
|
+
]);
|
|
2095
|
+
}
|
|
2096
|
+
__name(hasPermsToAssign, "hasPermsToAssign");
|
|
2097
|
+
|
|
2098
|
+
// src/bot/utilities/users/fetchGuildMember.ts
|
|
2099
|
+
async function fetchGuildMember(guild, userId) {
|
|
2100
|
+
let user = guild.members.cache.get(userId);
|
|
2101
|
+
user ??= await guild.members.fetch(userId).catch(() => {
|
|
2102
|
+
throw new UserNotInGuild(`User with ID ${userId} not found in guild`);
|
|
2103
|
+
});
|
|
2104
|
+
return user;
|
|
2105
|
+
}
|
|
2106
|
+
__name(fetchGuildMember, "fetchGuildMember");
|
|
2107
|
+
|
|
2108
|
+
// src/bot/utilities/users/fetchManyGuildMembers.ts
|
|
2109
|
+
async function fetchManyGuildMembers(guild, userIds) {
|
|
2110
|
+
const results = await Promise.allSettled(userIds.map((userId) => fetchGuildMember(guild, userId)));
|
|
2111
|
+
return results.filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
2112
|
+
}
|
|
2113
|
+
__name(fetchManyGuildMembers, "fetchManyGuildMembers");
|
|
2114
|
+
async function fetchUser(client, userId) {
|
|
2115
|
+
let user = client.users.cache.get(userId);
|
|
2116
|
+
user ??= await client.users.fetch(userId).catch((err) => {
|
|
2117
|
+
if (err instanceof DiscordAPIError && err.code === RESTJSONErrorCodes.UnknownUser) {
|
|
2118
|
+
throw new UserNotFound(userId);
|
|
2119
|
+
}
|
|
2120
|
+
throw err;
|
|
2121
|
+
});
|
|
2122
|
+
return user;
|
|
2123
|
+
}
|
|
2124
|
+
__name(fetchUser, "fetchUser");
|
|
2125
|
+
|
|
2126
|
+
// src/bot/utilities/users/fetchManyUsers.ts
|
|
2127
|
+
async function fetchManyUsers(client, userIds) {
|
|
2128
|
+
const results = await Promise.allSettled(userIds.map((userId) => fetchUser(client, userId)));
|
|
2129
|
+
return results.filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
2130
|
+
}
|
|
2131
|
+
__name(fetchManyUsers, "fetchManyUsers");
|
|
2132
|
+
|
|
2133
|
+
// src/bot/utilities/users/updateMemberRoles.ts
|
|
2134
|
+
async function updateMemberRoles(rolesToAdd, rolesToRemove, member) {
|
|
2135
|
+
const current = new Set(member.roles.cache.map((r) => r.id));
|
|
2136
|
+
const toAdd = new Set(rolesToAdd);
|
|
2137
|
+
const toRemove = new Set(rolesToRemove);
|
|
2138
|
+
const updated = current.union(toAdd).difference(toRemove);
|
|
2139
|
+
await member.roles.set([
|
|
2140
|
+
...updated
|
|
2141
|
+
]);
|
|
2142
|
+
}
|
|
2143
|
+
__name(updateMemberRoles, "updateMemberRoles");
|
|
2144
|
+
|
|
2145
|
+
export { AutocompleteHandler, AutocompleteRoute, BaseComponent, BaseErrorEmbed, BaseHandler, Bot, BuilderComponent, BuilderTypes, ButtonRoute, CannotAssignBotRole, CannotSendEmbedsError, Catchable, ChannelNotFoundError, ChannelNotTextChannel, Checkable, CommandMetadataKey, CommandRegistry, ContextMenuRoute, CouldNotFindChannel, CustomError, DatabaseError, EffectMetadataKey, EffectsEmitter, EffectsHandler, EffectsRegistry, EmojiInjector, EventCatchable, EventController, EventHandler, EventMetadataKey, EventMiddleware, GenericError, HasDangerousPermissions, InteractionController, InteractionHandler, InteractionMetadataKey, InteractionMiddleware, InteractionRoutes, Middleware, MiddlewareMetadataKey, MiddlewareType, MissingPermissions, ModalRoute, PERM_GROUPS, PermissionNames, Pluggable, Plugin, RegisterCommand, RegisterEffect, RegisterEvent, RoleDoesNotExist, RoleHigherThanMe, RowComponent, RowTypes, Seedcord, SelectMenuRoute, SelectMenuType, SlashRoute, UnhandledEvent, UnknownException, UserNotFound, UserNotInGuild, WebhookLog, attemptSendDM, buildSlashRoute, checkBotPermissions, checkPermissions, extractErrorResponse, fetchGuildMember, fetchManyGuildMembers, fetchManyUsers, fetchRole, fetchText, fetchUser, getBotRole, hasPermsToAssign, sendInText, throwCustomError, updateMemberRoles };
|
|
1503
2146
|
//# sourceMappingURL=index.mjs.map
|
|
1504
2147
|
//# sourceMappingURL=index.mjs.map
|