seedcord 0.7.0 → 0.8.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 +314 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +332 -56
- package/dist/index.d.ts +332 -56
- package/dist/index.mjs +315 -47
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
-
import { Logger, ShutdownPhase, CoordinatedShutdown, CoordinatedStartup, HealthCheck, StartupPhase } from '@seedcord/services';
|
|
2
|
+
import { Logger, StrictEventEmitter, SeedcordError, SeedcordErrorCode, ShutdownPhase, CoordinatedShutdown, CoordinatedStartup, HealthCheck, StartupPhase, SeedcordTypeError } from '@seedcord/services';
|
|
3
3
|
export * from '@seedcord/services';
|
|
4
4
|
import chalk3 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';
|
|
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, ComponentType } from 'discord.js';
|
|
6
6
|
import { Envapt } from 'envapt';
|
|
7
7
|
import { hexToNumber, traverseDirectory, filterCirculars, prettify } from '@seedcord/utils';
|
|
8
8
|
export * from '@seedcord/utils';
|
|
@@ -11,8 +11,6 @@ import { EventEmitter } from 'events';
|
|
|
11
11
|
|
|
12
12
|
var __defProp = Object.defineProperty;
|
|
13
13
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
14
|
-
|
|
15
|
-
// src/bot/decorators/Command.ts
|
|
16
14
|
var CommandMetadataKey = Symbol("command:metadata");
|
|
17
15
|
function RegisterCommand(scope, guilds = []) {
|
|
18
16
|
return (ctor) => {
|
|
@@ -22,6 +20,20 @@ function RegisterCommand(scope, guilds = []) {
|
|
|
22
20
|
scope,
|
|
23
21
|
guilds
|
|
24
22
|
};
|
|
23
|
+
const existingMeta = Reflect.getOwnMetadata(CommandMetadataKey, ctor);
|
|
24
|
+
if (existingMeta) {
|
|
25
|
+
throw new SeedcordError(SeedcordErrorCode.DecoratorCommandAlreadyRegistered, [
|
|
26
|
+
ctor.name,
|
|
27
|
+
existingMeta.scope,
|
|
28
|
+
scope
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
31
|
+
if (scope === "global" && guilds.length > 0) {
|
|
32
|
+
throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGlobalWithGuilds);
|
|
33
|
+
}
|
|
34
|
+
if (scope === "guild" && (!Array.isArray(guilds) || guilds.length === 0)) {
|
|
35
|
+
throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGuildWithoutGuilds);
|
|
36
|
+
}
|
|
25
37
|
Reflect.defineMetadata(CommandMetadataKey, meta, ctor);
|
|
26
38
|
};
|
|
27
39
|
}
|
|
@@ -268,24 +280,20 @@ var CommandRegistry = class {
|
|
|
268
280
|
await guild.commands.set(commands);
|
|
269
281
|
const tag = commands.length === 1 ? "command" : "commands";
|
|
270
282
|
this.logger.info(`${chalk3.bold.green("Configured")} ${chalk3.magenta.bold(commands.length)} ${tag} for guild ${chalk3.bold.yellow(guild.name)}`);
|
|
271
|
-
this.logger.info(
|
|
283
|
+
this.logger.info(`\u2192 ${commands.map((command) => chalk3.bold.cyan(command.name)).join(", ")}`);
|
|
272
284
|
}
|
|
273
285
|
}
|
|
274
286
|
};
|
|
275
287
|
|
|
276
288
|
// src/bot/decorators/Events.ts
|
|
277
289
|
var EventMetadataKey = Symbol("event:metadata");
|
|
278
|
-
function RegisterEvent(
|
|
290
|
+
function RegisterEvent(...defs) {
|
|
279
291
|
return function(constructor) {
|
|
280
292
|
const saved = Reflect.getMetadata(EventMetadataKey, constructor);
|
|
281
293
|
const existing = saved ?? [];
|
|
282
|
-
const
|
|
283
|
-
events
|
|
284
|
-
];
|
|
285
|
-
const frequency = options?.frequency ?? "on";
|
|
286
|
-
const entries = toStore.map((event) => ({
|
|
294
|
+
const entries = defs.map(([event, options]) => ({
|
|
287
295
|
event,
|
|
288
|
-
frequency
|
|
296
|
+
frequency: options?.frequency ?? "on"
|
|
289
297
|
}));
|
|
290
298
|
Reflect.defineMetadata(EventMetadataKey, [
|
|
291
299
|
...existing,
|
|
@@ -294,8 +302,6 @@ function RegisterEvent(events, options) {
|
|
|
294
302
|
};
|
|
295
303
|
}
|
|
296
304
|
__name(RegisterEvent, "RegisterEvent");
|
|
297
|
-
|
|
298
|
-
// src/bot/decorators/Middlewares.ts
|
|
299
305
|
var MiddlewareType = /* @__PURE__ */ (function(MiddlewareType2) {
|
|
300
306
|
MiddlewareType2["Interaction"] = "middleware:interaction";
|
|
301
307
|
MiddlewareType2["Event"] = "middleware:event";
|
|
@@ -306,10 +312,10 @@ function Middleware(type, priority = 0, options = {}) {
|
|
|
306
312
|
return (ctor) => {
|
|
307
313
|
const normalizedPriority = Number(priority);
|
|
308
314
|
if (!Number.isFinite(normalizedPriority)) {
|
|
309
|
-
throw new
|
|
315
|
+
throw new SeedcordTypeError(SeedcordErrorCode.DecoratorInvalidMiddlewarePriority);
|
|
310
316
|
}
|
|
311
|
-
if (type === "middleware:interaction" && options.events
|
|
312
|
-
throw new
|
|
317
|
+
if (type === "middleware:interaction" && Array.isArray(options.events) && options.events.length > 0) {
|
|
318
|
+
throw new SeedcordError(SeedcordErrorCode.DecoratorInteractionEventFilter);
|
|
313
319
|
}
|
|
314
320
|
const metadata = {
|
|
315
321
|
priority: normalizedPriority,
|
|
@@ -322,8 +328,6 @@ function Middleware(type, priority = 0, options = {}) {
|
|
|
322
328
|
};
|
|
323
329
|
}
|
|
324
330
|
__name(Middleware, "Middleware");
|
|
325
|
-
|
|
326
|
-
// src/interfaces/Handler.ts
|
|
327
331
|
var BaseHandler = class {
|
|
328
332
|
static {
|
|
329
333
|
__name(this, "BaseHandler");
|
|
@@ -334,10 +338,18 @@ var BaseHandler = class {
|
|
|
334
338
|
errored = false;
|
|
335
339
|
event;
|
|
336
340
|
args = [];
|
|
341
|
+
logger;
|
|
337
342
|
constructor(event, core, args) {
|
|
338
343
|
this.core = core;
|
|
339
344
|
this.event = event;
|
|
340
345
|
this.args = args ?? [];
|
|
346
|
+
this.logger = new Logger(this.constructor.name);
|
|
347
|
+
this.populate();
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Populates the handler with necessary data before execution. Override this method in your handler classes to customize population logic. This method is called at the end of the constructor before all async operations.
|
|
351
|
+
*/
|
|
352
|
+
populate() {
|
|
341
353
|
}
|
|
342
354
|
hasChecks() {
|
|
343
355
|
return this.checkable;
|
|
@@ -548,12 +560,16 @@ var EventController = class {
|
|
|
548
560
|
}
|
|
549
561
|
attachToClient() {
|
|
550
562
|
for (const [eventName, handlerEntries] of this.eventMap) {
|
|
551
|
-
this.logger.debug(`Attaching ${chalk3.bold.green(eventName)} to ${chalk3.
|
|
563
|
+
this.logger.debug(`Attaching ${chalk3.bold.green(eventName)} to the client with ${chalk3.gray(handlerEntries.length)} handler(s)`);
|
|
552
564
|
for (const entry of handlerEntries) {
|
|
553
565
|
const register = entry.frequency === "once" ? this.core.bot.client.once.bind(this.core.bot.client) : this.core.bot.client.on.bind(this.core.bot.client);
|
|
554
566
|
register(eventName, (...args) => {
|
|
567
|
+
this.core.bot.emit("any:event", eventName, ...args);
|
|
555
568
|
void (async () => {
|
|
556
|
-
await this.processEvent(eventName, args, entry.ctor)
|
|
569
|
+
await this.processEvent(eventName, args, entry.ctor).catch((err) => {
|
|
570
|
+
this.logger.error(`[${chalk3.bold.red("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
|
|
571
|
+
this.core.bot.emit("error:unhandled:event", err);
|
|
572
|
+
});
|
|
557
573
|
})();
|
|
558
574
|
});
|
|
559
575
|
}
|
|
@@ -690,7 +706,7 @@ function buildSlashRoute(arg1, arg2, arg3) {
|
|
|
690
706
|
group = arg1.options.getSubcommandGroup(false) ?? void 0;
|
|
691
707
|
sub = arg1.options.getSubcommand(false) ?? void 0;
|
|
692
708
|
} else {
|
|
693
|
-
throw new
|
|
709
|
+
throw new SeedcordTypeError(SeedcordErrorCode.UtilInvalidSlashRouteArgument);
|
|
694
710
|
}
|
|
695
711
|
if (sub && group) return `${command}/${group}/${sub}`;
|
|
696
712
|
if (sub) return `${command}/${sub}`;
|
|
@@ -793,7 +809,7 @@ function Catchable(options) {
|
|
|
793
809
|
const originalMethod = descriptor.value;
|
|
794
810
|
descriptor.value = async function(...args) {
|
|
795
811
|
const interaction = this.getEvent();
|
|
796
|
-
if (!originalMethod) throw new
|
|
812
|
+
if (!originalMethod) throw new SeedcordError(SeedcordErrorCode.DecoratorMethodNotFound);
|
|
797
813
|
try {
|
|
798
814
|
await originalMethod.apply(this, args);
|
|
799
815
|
} catch (error) {
|
|
@@ -1010,8 +1026,10 @@ var InteractionController = class {
|
|
|
1010
1026
|
}
|
|
1011
1027
|
attachToClient() {
|
|
1012
1028
|
this.core.bot.client.on(Events.InteractionCreate, (interaction) => {
|
|
1029
|
+
this.core.bot.emit("any:interaction", interaction);
|
|
1013
1030
|
this.handleInteraction(interaction).catch((err) => {
|
|
1014
1031
|
this.logger.error(`[${chalk3.bold.red("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
|
|
1032
|
+
this.core.bot.emit("error:unhandled:interaction", err);
|
|
1015
1033
|
});
|
|
1016
1034
|
});
|
|
1017
1035
|
}
|
|
@@ -1032,7 +1050,11 @@ var InteractionController = class {
|
|
|
1032
1050
|
}
|
|
1033
1051
|
async processInteraction(interaction, extractKey, getHandler, args) {
|
|
1034
1052
|
const key = extractKey(interaction);
|
|
1035
|
-
if (
|
|
1053
|
+
if ([
|
|
1054
|
+
...this.keysToIgnore
|
|
1055
|
+
].some((pattern) => typeof pattern === "string" ? pattern === key : pattern.test(key))) {
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1036
1058
|
for (const { ctor } of this.middlewares) {
|
|
1037
1059
|
const middleware = new ctor(interaction, this.core, args);
|
|
1038
1060
|
if (middleware.hasChecks()) await middleware.runChecks();
|
|
@@ -1129,16 +1151,16 @@ var InteractionController = class {
|
|
|
1129
1151
|
await this.processInteraction(interaction, () => autocompleteKey, (key) => this.autocompleteMap.get(key));
|
|
1130
1152
|
}
|
|
1131
1153
|
};
|
|
1132
|
-
var Plugin = class {
|
|
1154
|
+
var Plugin = class extends StrictEventEmitter {
|
|
1133
1155
|
static {
|
|
1134
1156
|
__name(this, "Plugin");
|
|
1135
1157
|
}
|
|
1136
1158
|
pluggable;
|
|
1137
1159
|
constructor(pluggable) {
|
|
1138
|
-
this.pluggable = pluggable;
|
|
1160
|
+
super(), this.pluggable = pluggable;
|
|
1139
1161
|
}
|
|
1140
1162
|
};
|
|
1141
|
-
var Pluggable = class _Pluggable {
|
|
1163
|
+
var Pluggable = class _Pluggable extends StrictEventEmitter {
|
|
1142
1164
|
static {
|
|
1143
1165
|
__name(this, "Pluggable");
|
|
1144
1166
|
}
|
|
@@ -1147,6 +1169,7 @@ var Pluggable = class _Pluggable {
|
|
|
1147
1169
|
startup;
|
|
1148
1170
|
static PLUGIN_INIT_TIMEOUT_MS = 15e3;
|
|
1149
1171
|
constructor(shutdown, startup) {
|
|
1172
|
+
super();
|
|
1150
1173
|
this.shutdown = shutdown;
|
|
1151
1174
|
this.startup = startup;
|
|
1152
1175
|
}
|
|
@@ -1171,15 +1194,21 @@ var Pluggable = class _Pluggable {
|
|
|
1171
1194
|
* @param startupPhase - When during startup to initialize this plugin ({@link StartupPhase})
|
|
1172
1195
|
* @param args - Additional arguments to pass to the plugin constructor
|
|
1173
1196
|
* @returns This instance with the plugin attached as a typed property
|
|
1174
|
-
* @throws
|
|
1197
|
+
* @throws A {@link SeedcordError} When called after initialization or if key already exists
|
|
1175
1198
|
* @example
|
|
1176
1199
|
* ```typescript
|
|
1177
1200
|
* seedcord.attach('db', Mongo, StartupPhase.Configuration, { uri: 'mongodb://...', name: 'seedcord', dir: ... })
|
|
1178
1201
|
* ```
|
|
1179
1202
|
*/
|
|
1180
1203
|
attach(key, Plugin2, startupPhase, ...args) {
|
|
1181
|
-
if (this.isInitialized)
|
|
1182
|
-
|
|
1204
|
+
if (this.isInitialized) {
|
|
1205
|
+
throw new SeedcordError(SeedcordErrorCode.CorePluginAfterInit);
|
|
1206
|
+
}
|
|
1207
|
+
if (this[key]) {
|
|
1208
|
+
throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [
|
|
1209
|
+
key
|
|
1210
|
+
]);
|
|
1211
|
+
}
|
|
1183
1212
|
const instance = new Plugin2(this, ...args);
|
|
1184
1213
|
const entry = {
|
|
1185
1214
|
[key]: instance
|
|
@@ -1192,6 +1221,8 @@ var Pluggable = class _Pluggable {
|
|
|
1192
1221
|
return Object.assign(this, entry);
|
|
1193
1222
|
}
|
|
1194
1223
|
};
|
|
1224
|
+
var emojiStorage = {};
|
|
1225
|
+
var Emojis = emojiStorage;
|
|
1195
1226
|
var EmojiInjector = class {
|
|
1196
1227
|
static {
|
|
1197
1228
|
__name(this, "EmojiInjector");
|
|
@@ -1202,6 +1233,7 @@ var EmojiInjector = class {
|
|
|
1202
1233
|
this.core = core;
|
|
1203
1234
|
}
|
|
1204
1235
|
async init() {
|
|
1236
|
+
this.clearEmojis();
|
|
1205
1237
|
if (!this.core.config.bot.emojis || Object.keys(this.core.config.bot.emojis).length === 0) {
|
|
1206
1238
|
this.logger.info(`${chalk3.bold.green("Loaded")}: ${chalk3.magenta.bold("0")} emojis`);
|
|
1207
1239
|
return;
|
|
@@ -1210,15 +1242,24 @@ var EmojiInjector = class {
|
|
|
1210
1242
|
await this.core.bot.client.application?.emojis.fetch();
|
|
1211
1243
|
let foundCount = 0;
|
|
1212
1244
|
Object.entries(configEmojis).forEach(([key, emojiName]) => {
|
|
1245
|
+
if (typeof emojiName !== "string") {
|
|
1246
|
+
this.logger.warn(`${chalk3.bold.yellow("Invalid")}: ${chalk3.magenta.bold(String(key))} (expected string, received ${typeof emojiName})`);
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1213
1249
|
const emoji = this.core.bot.client.application?.emojis.cache.find((e) => e.name === emojiName);
|
|
1214
1250
|
if (emoji) {
|
|
1215
|
-
|
|
1251
|
+
emojiStorage[key] = `<${emoji.identifier}>`;
|
|
1216
1252
|
foundCount++;
|
|
1217
|
-
|
|
1253
|
+
return;
|
|
1218
1254
|
}
|
|
1255
|
+
emojiStorage[key] = emojiName;
|
|
1256
|
+
this.logger.warn(`${chalk3.bold.yellow("Missing")}: ${chalk3.magenta.bold(emojiName)} (using configured value)`);
|
|
1219
1257
|
});
|
|
1220
1258
|
this.logger.info(`${chalk3.bold.green("Loaded")}: ${chalk3.magenta.bold(foundCount)} emojis`);
|
|
1221
1259
|
}
|
|
1260
|
+
clearEmojis() {
|
|
1261
|
+
for (const key of Object.keys(emojiStorage)) Reflect.deleteProperty(emojiStorage, key);
|
|
1262
|
+
}
|
|
1222
1263
|
};
|
|
1223
1264
|
|
|
1224
1265
|
// src/bot/Bot.ts
|
|
@@ -1245,6 +1286,7 @@ var Bot = class extends Plugin {
|
|
|
1245
1286
|
events;
|
|
1246
1287
|
commands;
|
|
1247
1288
|
emojiInjector;
|
|
1289
|
+
emojis = Emojis;
|
|
1248
1290
|
constructor(core) {
|
|
1249
1291
|
super(core), this.core = core;
|
|
1250
1292
|
this._client = new Client(core.config.bot.clientOptions);
|
|
@@ -1296,11 +1338,16 @@ var Bot = class extends Plugin {
|
|
|
1296
1338
|
get client() {
|
|
1297
1339
|
return this._client;
|
|
1298
1340
|
}
|
|
1341
|
+
emit(event, ...args) {
|
|
1342
|
+
return super.emit(event, ...args);
|
|
1343
|
+
}
|
|
1299
1344
|
};
|
|
1300
1345
|
_ts_decorate4([
|
|
1301
1346
|
Envapt("DISCORD_BOT_TOKEN", {
|
|
1302
1347
|
converter(raw, _fallback) {
|
|
1303
|
-
if (typeof raw !== "string")
|
|
1348
|
+
if (typeof raw !== "string") {
|
|
1349
|
+
throw new SeedcordError(SeedcordErrorCode.ConfigMissingDiscordToken);
|
|
1350
|
+
}
|
|
1304
1351
|
return raw;
|
|
1305
1352
|
}
|
|
1306
1353
|
}),
|
|
@@ -1363,6 +1410,25 @@ function _ts_metadata5(k, v) {
|
|
|
1363
1410
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1364
1411
|
}
|
|
1365
1412
|
__name(_ts_metadata5, "_ts_metadata");
|
|
1413
|
+
function webhookUrlValidator(raw, _fallback) {
|
|
1414
|
+
if (raw === null) {
|
|
1415
|
+
throw new SeedcordError(SeedcordErrorCode.ConfigUnknownExceptionWebhookMissing);
|
|
1416
|
+
}
|
|
1417
|
+
if (typeof raw !== "string") {
|
|
1418
|
+
throw new SeedcordError(SeedcordErrorCode.ConfigUnknownExceptionWebhookInvalid);
|
|
1419
|
+
}
|
|
1420
|
+
const value = raw.trim();
|
|
1421
|
+
if (value === "") {
|
|
1422
|
+
throw new SeedcordError(SeedcordErrorCode.ConfigUnknownExceptionWebhookMissing);
|
|
1423
|
+
}
|
|
1424
|
+
const pattern = String.raw`^https?:\/\/(?:canary\.|ptb\.)?discord(?:app)?\.com\/api\/webhooks\/\d+\/[\w$-]+$`;
|
|
1425
|
+
const discordWebhookRegex = new RegExp(pattern);
|
|
1426
|
+
if (!URL.canParse(value) || !discordWebhookRegex.test(value)) {
|
|
1427
|
+
throw new SeedcordError(SeedcordErrorCode.ConfigUnknownExceptionWebhookInvalid);
|
|
1428
|
+
}
|
|
1429
|
+
return value;
|
|
1430
|
+
}
|
|
1431
|
+
__name(webhookUrlValidator, "webhookUrlValidator");
|
|
1366
1432
|
var UnknownException = class _UnknownException extends WebhookLog {
|
|
1367
1433
|
static {
|
|
1368
1434
|
__name(this, "UnknownException");
|
|
@@ -1402,11 +1468,7 @@ var UnknownException = class _UnknownException extends WebhookLog {
|
|
|
1402
1468
|
};
|
|
1403
1469
|
_ts_decorate5([
|
|
1404
1470
|
Envapt("UNKNOWN_EXCEPTION_WEBHOOK_URL", {
|
|
1405
|
-
converter(raw,
|
|
1406
|
-
if (!raw) throw new Error("Missing UNKNOWN_EXCEPTION_WEBHOOK_URL");
|
|
1407
|
-
if (!URL.canParse(String(raw))) throw new Error("Invalid UNKNOWN_EXCEPTION_WEBHOOK_URL");
|
|
1408
|
-
return raw;
|
|
1409
|
-
}
|
|
1471
|
+
converter: /* @__PURE__ */ __name((raw, fallback) => webhookUrlValidator(raw), "converter")
|
|
1410
1472
|
}),
|
|
1411
1473
|
_ts_metadata5("design:type", String)
|
|
1412
1474
|
], UnknownException, "unknownExceptionWebhookUrl", void 0);
|
|
@@ -1595,7 +1657,7 @@ var Seedcord = class _Seedcord extends Pluggable {
|
|
|
1595
1657
|
* Creates a new Seedcord instance
|
|
1596
1658
|
*
|
|
1597
1659
|
* @param config - Bot configuration including paths and Discord client options
|
|
1598
|
-
* @throws An {@link
|
|
1660
|
+
* @throws An {@link SeedcordError} When attempting to create multiple instances (singleton)
|
|
1599
1661
|
*/
|
|
1600
1662
|
constructor(config) {
|
|
1601
1663
|
const shutdown = new CoordinatedShutdown();
|
|
@@ -1604,7 +1666,7 @@ var Seedcord = class _Seedcord extends Pluggable {
|
|
|
1604
1666
|
this.shutdown = shutdown;
|
|
1605
1667
|
this.startup = startup;
|
|
1606
1668
|
if (_Seedcord.isInstantiated) {
|
|
1607
|
-
throw new
|
|
1669
|
+
throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);
|
|
1608
1670
|
}
|
|
1609
1671
|
_Seedcord.isInstantiated = true;
|
|
1610
1672
|
this.effects = new EffectsRegistry(this);
|
|
@@ -1656,7 +1718,7 @@ function EventCatchable(log) {
|
|
|
1656
1718
|
return function(_target, _prop, descriptor) {
|
|
1657
1719
|
const original = descriptor.value;
|
|
1658
1720
|
descriptor.value = async function(...args) {
|
|
1659
|
-
if (!original) throw new
|
|
1721
|
+
if (!original) throw new SeedcordError(SeedcordErrorCode.DecoratorMethodNotFound);
|
|
1660
1722
|
try {
|
|
1661
1723
|
await original.apply(this, args);
|
|
1662
1724
|
} catch (err) {
|
|
@@ -1680,6 +1742,206 @@ function EventCatchable(log) {
|
|
|
1680
1742
|
};
|
|
1681
1743
|
}
|
|
1682
1744
|
__name(EventCatchable, "EventCatchable");
|
|
1745
|
+
var resolveFactory = /* @__PURE__ */ __name(async (input, ctx) => typeof input === "function" ? await input(ctx) : input, "resolveFactory");
|
|
1746
|
+
var isV2 = /* @__PURE__ */ __name((opts) => "container" in opts, "isV2");
|
|
1747
|
+
var usesResolver = /* @__PURE__ */ __name((opts) => "resolveDecision" in opts, "usesResolver");
|
|
1748
|
+
var usesCustomIds = /* @__PURE__ */ __name((opts) => "confirmCustomIds" in opts, "usesCustomIds");
|
|
1749
|
+
var isMessageComponentIx = /* @__PURE__ */ __name((ix) => "deferUpdate" in ix && "customId" in ix, "isMessageComponentIx");
|
|
1750
|
+
var buildPrompt = /* @__PURE__ */ __name(async (opts, ctx) => {
|
|
1751
|
+
if (isV2(opts)) {
|
|
1752
|
+
const container = await resolveFactory(opts.container, ctx);
|
|
1753
|
+
return {
|
|
1754
|
+
flags: "IsComponentsV2",
|
|
1755
|
+
components: [
|
|
1756
|
+
container.component
|
|
1757
|
+
]
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
const prompt = await resolveFactory(opts.prompt, ctx);
|
|
1761
|
+
const rows = await resolveFactory(opts.rows, ctx);
|
|
1762
|
+
const components = [
|
|
1763
|
+
...rows
|
|
1764
|
+
];
|
|
1765
|
+
const payload = {
|
|
1766
|
+
components
|
|
1767
|
+
};
|
|
1768
|
+
if (typeof prompt === "string") payload.content = prompt;
|
|
1769
|
+
else payload.embeds = [
|
|
1770
|
+
prompt.component
|
|
1771
|
+
];
|
|
1772
|
+
return payload;
|
|
1773
|
+
}, "buildPrompt");
|
|
1774
|
+
var clearedPayload = /* @__PURE__ */ __name((opts) => isV2(opts) ? {
|
|
1775
|
+
flags: "IsComponentsV2",
|
|
1776
|
+
components: []
|
|
1777
|
+
} : {
|
|
1778
|
+
components: []
|
|
1779
|
+
}, "clearedPayload");
|
|
1780
|
+
var decide = /* @__PURE__ */ __name(async (opts, i) => {
|
|
1781
|
+
if (usesResolver(opts)) return opts.resolveDecision(i);
|
|
1782
|
+
if (usesCustomIds(opts)) {
|
|
1783
|
+
const { confirmCustomIds, cancelCustomIds = [] } = opts;
|
|
1784
|
+
if (confirmCustomIds.includes(i.customId)) return true;
|
|
1785
|
+
if (cancelCustomIds.includes(i.customId)) return false;
|
|
1786
|
+
}
|
|
1787
|
+
return false;
|
|
1788
|
+
}, "decide");
|
|
1789
|
+
var shouldDefer = /* @__PURE__ */ __name((ix, opts, isSlash, isContext) => {
|
|
1790
|
+
if (ix.deferred) return false;
|
|
1791
|
+
if (opts.defer === false) return false;
|
|
1792
|
+
return isSlash || isContext;
|
|
1793
|
+
}, "shouldDefer");
|
|
1794
|
+
var maybeDefer = /* @__PURE__ */ __name(async (ix, opts, isSlash, isContext) => {
|
|
1795
|
+
if (!shouldDefer(ix, opts, isSlash, isContext)) return;
|
|
1796
|
+
if (isSlash || isContext) {
|
|
1797
|
+
const { ephemeral = true } = opts;
|
|
1798
|
+
const flags = ephemeral ? {
|
|
1799
|
+
flags: "Ephemeral"
|
|
1800
|
+
} : void 0;
|
|
1801
|
+
if (flags) await ix.deferReply(flags);
|
|
1802
|
+
else await ix.deferReply();
|
|
1803
|
+
} else if (isMessageComponentIx(ix)) {
|
|
1804
|
+
await ix.deferUpdate();
|
|
1805
|
+
} else {
|
|
1806
|
+
await ix.deferReply().catch(() => void 0);
|
|
1807
|
+
}
|
|
1808
|
+
}, "maybeDefer");
|
|
1809
|
+
var sendPrompt = /* @__PURE__ */ __name(async (ix, payload, ephemeral, isSlash, isContext) => {
|
|
1810
|
+
if (isSlash || isContext) {
|
|
1811
|
+
if (ix.deferred) return ix.editReply(payload);
|
|
1812
|
+
const reply = {
|
|
1813
|
+
...payload,
|
|
1814
|
+
...ephemeral ? {
|
|
1815
|
+
flags: "Ephemeral"
|
|
1816
|
+
} : {}
|
|
1817
|
+
};
|
|
1818
|
+
await ix.reply(reply);
|
|
1819
|
+
return ix.fetchReply();
|
|
1820
|
+
}
|
|
1821
|
+
const follow = {
|
|
1822
|
+
...payload,
|
|
1823
|
+
...ephemeral ? {
|
|
1824
|
+
flags: "Ephemeral"
|
|
1825
|
+
} : {}
|
|
1826
|
+
};
|
|
1827
|
+
return ix.followUp(follow);
|
|
1828
|
+
}, "sendPrompt");
|
|
1829
|
+
var awaitComponent = /* @__PURE__ */ __name(async (msg, original, opts) => {
|
|
1830
|
+
const componentType = opts.componentType ?? ComponentType.Button;
|
|
1831
|
+
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
1832
|
+
try {
|
|
1833
|
+
const button = await msg.awaitMessageComponent({
|
|
1834
|
+
componentType,
|
|
1835
|
+
time: timeoutMs,
|
|
1836
|
+
filter: /* @__PURE__ */ __name((c) => {
|
|
1837
|
+
if (c.user.id !== original.user.id) return false;
|
|
1838
|
+
if (usesCustomIds(opts)) {
|
|
1839
|
+
const { confirmCustomIds, cancelCustomIds = [] } = opts;
|
|
1840
|
+
return confirmCustomIds.includes(c.customId) || cancelCustomIds.includes(c.customId);
|
|
1841
|
+
}
|
|
1842
|
+
return true;
|
|
1843
|
+
}, "filter")
|
|
1844
|
+
});
|
|
1845
|
+
return {
|
|
1846
|
+
button,
|
|
1847
|
+
timedOut: false
|
|
1848
|
+
};
|
|
1849
|
+
} catch {
|
|
1850
|
+
return {
|
|
1851
|
+
button: null,
|
|
1852
|
+
timedOut: true
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
}, "awaitComponent");
|
|
1856
|
+
var clearUi = /* @__PURE__ */ __name(async (ix, msg, opts, isSlash) => {
|
|
1857
|
+
if (!isSlash) {
|
|
1858
|
+
try {
|
|
1859
|
+
await msg.edit(clearedPayload(opts));
|
|
1860
|
+
} catch {
|
|
1861
|
+
await ix.deleteReply(msg).catch(() => void 0);
|
|
1862
|
+
}
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
await ix.editReply(clearedPayload(opts)).catch(() => void 0);
|
|
1866
|
+
}, "clearUi");
|
|
1867
|
+
var normalizeClassicOutcome = /* @__PURE__ */ __name((payload) => ({
|
|
1868
|
+
...payload,
|
|
1869
|
+
components: payload.components ?? []
|
|
1870
|
+
}), "normalizeClassicOutcome");
|
|
1871
|
+
var outcomeReplacement = /* @__PURE__ */ __name(async (opts, ctx, confirmed, timedOut) => {
|
|
1872
|
+
const outcomes = opts.outcomeUi;
|
|
1873
|
+
if (isV2(opts)) {
|
|
1874
|
+
const v2Outcomes = outcomes;
|
|
1875
|
+
if (timedOut) return await resolveFactory(v2Outcomes.onTimeout, ctx);
|
|
1876
|
+
if (!confirmed) return await resolveFactory(v2Outcomes.onCancel, ctx);
|
|
1877
|
+
if (v2Outcomes.onConfirm) return await resolveFactory(v2Outcomes.onConfirm, ctx);
|
|
1878
|
+
return null;
|
|
1879
|
+
}
|
|
1880
|
+
const classicOutcomes = outcomes;
|
|
1881
|
+
if (timedOut) return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onTimeout, ctx));
|
|
1882
|
+
if (!confirmed) return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onCancel, ctx));
|
|
1883
|
+
if (classicOutcomes.onConfirm) {
|
|
1884
|
+
return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onConfirm, ctx));
|
|
1885
|
+
}
|
|
1886
|
+
return null;
|
|
1887
|
+
}, "outcomeReplacement");
|
|
1888
|
+
function Confirmable(question, options) {
|
|
1889
|
+
return function(_target, _propertyKey, descriptor) {
|
|
1890
|
+
const original = descriptor.value;
|
|
1891
|
+
descriptor.value = async function(...args) {
|
|
1892
|
+
if (!original) throw new SeedcordError(SeedcordErrorCode.DecoratorMethodNotFound);
|
|
1893
|
+
const ix = this.getEvent();
|
|
1894
|
+
const isSlash = ix.isChatInputCommand();
|
|
1895
|
+
const isContext = ix.isContextMenuCommand();
|
|
1896
|
+
const { ephemeral = true } = options;
|
|
1897
|
+
await maybeDefer(ix, options, isSlash, isContext);
|
|
1898
|
+
const q = typeof question === "function" ? await question.apply(this) : question;
|
|
1899
|
+
const ctx = {
|
|
1900
|
+
handler: this,
|
|
1901
|
+
interaction: ix,
|
|
1902
|
+
question: q
|
|
1903
|
+
};
|
|
1904
|
+
const prompt = await buildPrompt(options, ctx);
|
|
1905
|
+
const promptMsg = await sendPrompt(ix, prompt, ephemeral, isSlash, isContext);
|
|
1906
|
+
const { button, timedOut } = await awaitComponent(promptMsg, ix, options);
|
|
1907
|
+
let confirmed = false;
|
|
1908
|
+
if (button) {
|
|
1909
|
+
await button.deferUpdate().catch(() => void 0);
|
|
1910
|
+
confirmed = await decide(options, button);
|
|
1911
|
+
}
|
|
1912
|
+
const replacement = await outcomeReplacement(options, ctx, confirmed, timedOut);
|
|
1913
|
+
if (replacement) {
|
|
1914
|
+
if (isSlash || isContext) {
|
|
1915
|
+
await ix.editReply(replacement).catch(() => void 0);
|
|
1916
|
+
} else {
|
|
1917
|
+
await promptMsg.edit(replacement).catch(async () => {
|
|
1918
|
+
await ix.deleteReply(promptMsg).catch(() => void 0);
|
|
1919
|
+
await ix.followUp(replacement).catch(() => void 0);
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
} else {
|
|
1923
|
+
await clearUi(ix, promptMsg, options, isSlash);
|
|
1924
|
+
}
|
|
1925
|
+
if (options.onResolved) {
|
|
1926
|
+
await options.onResolved({
|
|
1927
|
+
confirmed,
|
|
1928
|
+
timedOut,
|
|
1929
|
+
handler: this,
|
|
1930
|
+
interaction: ix,
|
|
1931
|
+
question: q,
|
|
1932
|
+
...button ? {
|
|
1933
|
+
button
|
|
1934
|
+
} : {}
|
|
1935
|
+
});
|
|
1936
|
+
}
|
|
1937
|
+
if (confirmed) {
|
|
1938
|
+
await original.apply(this, args);
|
|
1939
|
+
}
|
|
1940
|
+
};
|
|
1941
|
+
return descriptor;
|
|
1942
|
+
};
|
|
1943
|
+
}
|
|
1944
|
+
__name(Confirmable, "Confirmable");
|
|
1683
1945
|
|
|
1684
1946
|
// src/bot/errors/Channels.ts
|
|
1685
1947
|
var ChannelNotFoundError = class extends CustomError {
|
|
@@ -2045,7 +2307,9 @@ function checkPermissions(client, roleOrChannel, scope = "all", inverse = false)
|
|
|
2045
2307
|
if (roleOrChannel instanceof Role) {
|
|
2046
2308
|
permissions = roleOrChannel.permissions;
|
|
2047
2309
|
} else {
|
|
2048
|
-
if (!client.user)
|
|
2310
|
+
if (!client.user) {
|
|
2311
|
+
throw new SeedcordError(SeedcordErrorCode.CoreClientUserUnavailable);
|
|
2312
|
+
}
|
|
2049
2313
|
permissions = roleOrChannel.permissionsFor(client.user, true);
|
|
2050
2314
|
}
|
|
2051
2315
|
if (!permissions) {
|
|
@@ -2064,12 +2328,16 @@ function checkPermissions(client, roleOrChannel, scope = "all", inverse = false)
|
|
|
2064
2328
|
}
|
|
2065
2329
|
}
|
|
2066
2330
|
__name(checkPermissions, "checkPermissions");
|
|
2067
|
-
|
|
2068
|
-
// src/bot/utilities/roles/getBotRole.ts
|
|
2069
2331
|
function getBotRole(client, guild) {
|
|
2070
|
-
if (!client.user)
|
|
2332
|
+
if (!client.user) {
|
|
2333
|
+
throw new SeedcordError(SeedcordErrorCode.CoreClientUserUnavailable);
|
|
2334
|
+
}
|
|
2071
2335
|
const botRole = guild.roles.botRoleFor(client.user);
|
|
2072
|
-
if (!botRole)
|
|
2336
|
+
if (!botRole) {
|
|
2337
|
+
throw new SeedcordError(SeedcordErrorCode.CoreBotRoleMissing, [
|
|
2338
|
+
guild.id
|
|
2339
|
+
]);
|
|
2340
|
+
}
|
|
2073
2341
|
return botRole;
|
|
2074
2342
|
}
|
|
2075
2343
|
__name(getBotRole, "getBotRole");
|
|
@@ -2181,6 +2449,6 @@ async function updateMemberRoles(rolesToAdd, rolesToRemove, member) {
|
|
|
2181
2449
|
}
|
|
2182
2450
|
__name(updateMemberRoles, "updateMemberRoles");
|
|
2183
2451
|
|
|
2184
|
-
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 };
|
|
2452
|
+
export { AutocompleteHandler, AutocompleteRoute, BaseComponent, BaseErrorEmbed, BaseHandler, Bot, BuilderComponent, BuilderTypes, ButtonRoute, CannotAssignBotRole, CannotSendEmbedsError, Catchable, ChannelNotFoundError, ChannelNotTextChannel, Checkable, CommandMetadataKey, CommandRegistry, Confirmable, ContextMenuRoute, CouldNotFindChannel, CustomError, DatabaseError, EffectMetadataKey, EffectsEmitter, EffectsHandler, EffectsRegistry, EmojiInjector, Emojis, 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 };
|
|
2185
2453
|
//# sourceMappingURL=index.mjs.map
|
|
2186
2454
|
//# sourceMappingURL=index.mjs.map
|