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