seedcord 0.7.1 → 0.8.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 +314 -43
- 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 -46
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -34,8 +34,6 @@ var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2);
|
|
|
34
34
|
|
|
35
35
|
var __defProp = Object.defineProperty;
|
|
36
36
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
37
|
-
|
|
38
|
-
// src/bot/decorators/Command.ts
|
|
39
37
|
var CommandMetadataKey = Symbol("command:metadata");
|
|
40
38
|
function RegisterCommand(scope, guilds = []) {
|
|
41
39
|
return (ctor) => {
|
|
@@ -45,6 +43,20 @@ function RegisterCommand(scope, guilds = []) {
|
|
|
45
43
|
scope,
|
|
46
44
|
guilds
|
|
47
45
|
};
|
|
46
|
+
const existingMeta = Reflect.getOwnMetadata(CommandMetadataKey, ctor);
|
|
47
|
+
if (existingMeta) {
|
|
48
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.DecoratorCommandAlreadyRegistered, [
|
|
49
|
+
ctor.name,
|
|
50
|
+
existingMeta.scope,
|
|
51
|
+
scope
|
|
52
|
+
]);
|
|
53
|
+
}
|
|
54
|
+
if (scope === "global" && guilds.length > 0) {
|
|
55
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.DecoratorCommandGlobalWithGuilds);
|
|
56
|
+
}
|
|
57
|
+
if (scope === "guild" && (!Array.isArray(guilds) || guilds.length === 0)) {
|
|
58
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.DecoratorCommandGuildWithoutGuilds);
|
|
59
|
+
}
|
|
48
60
|
Reflect.defineMetadata(CommandMetadataKey, meta, ctor);
|
|
49
61
|
};
|
|
50
62
|
}
|
|
@@ -291,24 +303,20 @@ var CommandRegistry = class {
|
|
|
291
303
|
await guild.commands.set(commands);
|
|
292
304
|
const tag = commands.length === 1 ? "command" : "commands";
|
|
293
305
|
this.logger.info(`${chalk3__default.default.bold.green("Configured")} ${chalk3__default.default.magenta.bold(commands.length)} ${tag} for guild ${chalk3__default.default.bold.yellow(guild.name)}`);
|
|
294
|
-
this.logger.info(
|
|
306
|
+
this.logger.info(`\u2192 ${commands.map((command) => chalk3__default.default.bold.cyan(command.name)).join(", ")}`);
|
|
295
307
|
}
|
|
296
308
|
}
|
|
297
309
|
};
|
|
298
310
|
|
|
299
311
|
// src/bot/decorators/Events.ts
|
|
300
312
|
var EventMetadataKey = Symbol("event:metadata");
|
|
301
|
-
function RegisterEvent(
|
|
313
|
+
function RegisterEvent(...defs) {
|
|
302
314
|
return function(constructor) {
|
|
303
315
|
const saved = Reflect.getMetadata(EventMetadataKey, constructor);
|
|
304
316
|
const existing = saved ?? [];
|
|
305
|
-
const
|
|
306
|
-
events
|
|
307
|
-
];
|
|
308
|
-
const frequency = options?.frequency ?? "on";
|
|
309
|
-
const entries = toStore.map((event) => ({
|
|
317
|
+
const entries = defs.map(([event, options]) => ({
|
|
310
318
|
event,
|
|
311
|
-
frequency
|
|
319
|
+
frequency: options?.frequency ?? "on"
|
|
312
320
|
}));
|
|
313
321
|
Reflect.defineMetadata(EventMetadataKey, [
|
|
314
322
|
...existing,
|
|
@@ -317,8 +325,6 @@ function RegisterEvent(events, options) {
|
|
|
317
325
|
};
|
|
318
326
|
}
|
|
319
327
|
__name(RegisterEvent, "RegisterEvent");
|
|
320
|
-
|
|
321
|
-
// src/bot/decorators/Middlewares.ts
|
|
322
328
|
var MiddlewareType = /* @__PURE__ */ (function(MiddlewareType2) {
|
|
323
329
|
MiddlewareType2["Interaction"] = "middleware:interaction";
|
|
324
330
|
MiddlewareType2["Event"] = "middleware:event";
|
|
@@ -329,10 +335,10 @@ function Middleware(type, priority = 0, options = {}) {
|
|
|
329
335
|
return (ctor) => {
|
|
330
336
|
const normalizedPriority = Number(priority);
|
|
331
337
|
if (!Number.isFinite(normalizedPriority)) {
|
|
332
|
-
throw new
|
|
338
|
+
throw new services.SeedcordTypeError(services.SeedcordErrorCode.DecoratorInvalidMiddlewarePriority);
|
|
333
339
|
}
|
|
334
|
-
if (type === "middleware:interaction" && options.events
|
|
335
|
-
throw new
|
|
340
|
+
if (type === "middleware:interaction" && Array.isArray(options.events) && options.events.length > 0) {
|
|
341
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.DecoratorInteractionEventFilter);
|
|
336
342
|
}
|
|
337
343
|
const metadata = {
|
|
338
344
|
priority: normalizedPriority,
|
|
@@ -345,8 +351,6 @@ function Middleware(type, priority = 0, options = {}) {
|
|
|
345
351
|
};
|
|
346
352
|
}
|
|
347
353
|
__name(Middleware, "Middleware");
|
|
348
|
-
|
|
349
|
-
// src/interfaces/Handler.ts
|
|
350
354
|
var BaseHandler = class {
|
|
351
355
|
static {
|
|
352
356
|
__name(this, "BaseHandler");
|
|
@@ -357,10 +361,18 @@ var BaseHandler = class {
|
|
|
357
361
|
errored = false;
|
|
358
362
|
event;
|
|
359
363
|
args = [];
|
|
364
|
+
logger;
|
|
360
365
|
constructor(event, core, args) {
|
|
361
366
|
this.core = core;
|
|
362
367
|
this.event = event;
|
|
363
368
|
this.args = args ?? [];
|
|
369
|
+
this.logger = new services.Logger(this.constructor.name);
|
|
370
|
+
this.populate();
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* 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.
|
|
374
|
+
*/
|
|
375
|
+
populate() {
|
|
364
376
|
}
|
|
365
377
|
hasChecks() {
|
|
366
378
|
return this.checkable;
|
|
@@ -575,8 +587,12 @@ var EventController = class {
|
|
|
575
587
|
for (const entry of handlerEntries) {
|
|
576
588
|
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);
|
|
577
589
|
register(eventName, (...args) => {
|
|
590
|
+
this.core.bot.emit("any:event", eventName, ...args);
|
|
578
591
|
void (async () => {
|
|
579
|
-
await this.processEvent(eventName, args, entry.ctor)
|
|
592
|
+
await this.processEvent(eventName, args, entry.ctor).catch((err) => {
|
|
593
|
+
this.logger.error(`[${chalk3__default.default.bold.red("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
|
|
594
|
+
this.core.bot.emit("error:unhandled:event", err);
|
|
595
|
+
});
|
|
580
596
|
})();
|
|
581
597
|
});
|
|
582
598
|
}
|
|
@@ -713,7 +729,7 @@ function buildSlashRoute(arg1, arg2, arg3) {
|
|
|
713
729
|
group = arg1.options.getSubcommandGroup(false) ?? void 0;
|
|
714
730
|
sub = arg1.options.getSubcommand(false) ?? void 0;
|
|
715
731
|
} else {
|
|
716
|
-
throw new
|
|
732
|
+
throw new services.SeedcordTypeError(services.SeedcordErrorCode.UtilInvalidSlashRouteArgument);
|
|
717
733
|
}
|
|
718
734
|
if (sub && group) return `${command}/${group}/${sub}`;
|
|
719
735
|
if (sub) return `${command}/${sub}`;
|
|
@@ -816,7 +832,7 @@ function Catchable(options) {
|
|
|
816
832
|
const originalMethod = descriptor.value;
|
|
817
833
|
descriptor.value = async function(...args) {
|
|
818
834
|
const interaction = this.getEvent();
|
|
819
|
-
if (!originalMethod) throw new
|
|
835
|
+
if (!originalMethod) throw new services.SeedcordError(services.SeedcordErrorCode.DecoratorMethodNotFound);
|
|
820
836
|
try {
|
|
821
837
|
await originalMethod.apply(this, args);
|
|
822
838
|
} catch (error) {
|
|
@@ -1033,8 +1049,10 @@ var InteractionController = class {
|
|
|
1033
1049
|
}
|
|
1034
1050
|
attachToClient() {
|
|
1035
1051
|
this.core.bot.client.on(discord_js.Events.InteractionCreate, (interaction) => {
|
|
1052
|
+
this.core.bot.emit("any:interaction", interaction);
|
|
1036
1053
|
this.handleInteraction(interaction).catch((err) => {
|
|
1037
1054
|
this.logger.error(`[${chalk3__default.default.bold.red("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
|
|
1055
|
+
this.core.bot.emit("error:unhandled:interaction", err);
|
|
1038
1056
|
});
|
|
1039
1057
|
});
|
|
1040
1058
|
}
|
|
@@ -1055,7 +1073,11 @@ var InteractionController = class {
|
|
|
1055
1073
|
}
|
|
1056
1074
|
async processInteraction(interaction, extractKey, getHandler, args) {
|
|
1057
1075
|
const key = extractKey(interaction);
|
|
1058
|
-
if (
|
|
1076
|
+
if ([
|
|
1077
|
+
...this.keysToIgnore
|
|
1078
|
+
].some((pattern) => typeof pattern === "string" ? pattern === key : pattern.test(key))) {
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1059
1081
|
for (const { ctor } of this.middlewares) {
|
|
1060
1082
|
const middleware = new ctor(interaction, this.core, args);
|
|
1061
1083
|
if (middleware.hasChecks()) await middleware.runChecks();
|
|
@@ -1152,16 +1174,16 @@ var InteractionController = class {
|
|
|
1152
1174
|
await this.processInteraction(interaction, () => autocompleteKey, (key) => this.autocompleteMap.get(key));
|
|
1153
1175
|
}
|
|
1154
1176
|
};
|
|
1155
|
-
var Plugin = class {
|
|
1177
|
+
var Plugin = class extends services.StrictEventEmitter {
|
|
1156
1178
|
static {
|
|
1157
1179
|
__name(this, "Plugin");
|
|
1158
1180
|
}
|
|
1159
1181
|
pluggable;
|
|
1160
1182
|
constructor(pluggable) {
|
|
1161
|
-
this.pluggable = pluggable;
|
|
1183
|
+
super(), this.pluggable = pluggable;
|
|
1162
1184
|
}
|
|
1163
1185
|
};
|
|
1164
|
-
var Pluggable = class _Pluggable {
|
|
1186
|
+
var Pluggable = class _Pluggable extends services.StrictEventEmitter {
|
|
1165
1187
|
static {
|
|
1166
1188
|
__name(this, "Pluggable");
|
|
1167
1189
|
}
|
|
@@ -1170,6 +1192,7 @@ var Pluggable = class _Pluggable {
|
|
|
1170
1192
|
startup;
|
|
1171
1193
|
static PLUGIN_INIT_TIMEOUT_MS = 15e3;
|
|
1172
1194
|
constructor(shutdown, startup) {
|
|
1195
|
+
super();
|
|
1173
1196
|
this.shutdown = shutdown;
|
|
1174
1197
|
this.startup = startup;
|
|
1175
1198
|
}
|
|
@@ -1194,15 +1217,21 @@ var Pluggable = class _Pluggable {
|
|
|
1194
1217
|
* @param startupPhase - When during startup to initialize this plugin ({@link StartupPhase})
|
|
1195
1218
|
* @param args - Additional arguments to pass to the plugin constructor
|
|
1196
1219
|
* @returns This instance with the plugin attached as a typed property
|
|
1197
|
-
* @throws
|
|
1220
|
+
* @throws A {@link SeedcordError} When called after initialization or if key already exists
|
|
1198
1221
|
* @example
|
|
1199
1222
|
* ```typescript
|
|
1200
1223
|
* seedcord.attach('db', Mongo, StartupPhase.Configuration, { uri: 'mongodb://...', name: 'seedcord', dir: ... })
|
|
1201
1224
|
* ```
|
|
1202
1225
|
*/
|
|
1203
1226
|
attach(key, Plugin2, startupPhase, ...args) {
|
|
1204
|
-
if (this.isInitialized)
|
|
1205
|
-
|
|
1227
|
+
if (this.isInitialized) {
|
|
1228
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.CorePluginAfterInit);
|
|
1229
|
+
}
|
|
1230
|
+
if (this[key]) {
|
|
1231
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.CorePluginKeyExists, [
|
|
1232
|
+
key
|
|
1233
|
+
]);
|
|
1234
|
+
}
|
|
1206
1235
|
const instance = new Plugin2(this, ...args);
|
|
1207
1236
|
const entry = {
|
|
1208
1237
|
[key]: instance
|
|
@@ -1215,6 +1244,8 @@ var Pluggable = class _Pluggable {
|
|
|
1215
1244
|
return Object.assign(this, entry);
|
|
1216
1245
|
}
|
|
1217
1246
|
};
|
|
1247
|
+
var emojiStorage = {};
|
|
1248
|
+
var Emojis = emojiStorage;
|
|
1218
1249
|
var EmojiInjector = class {
|
|
1219
1250
|
static {
|
|
1220
1251
|
__name(this, "EmojiInjector");
|
|
@@ -1225,6 +1256,7 @@ var EmojiInjector = class {
|
|
|
1225
1256
|
this.core = core;
|
|
1226
1257
|
}
|
|
1227
1258
|
async init() {
|
|
1259
|
+
this.clearEmojis();
|
|
1228
1260
|
if (!this.core.config.bot.emojis || Object.keys(this.core.config.bot.emojis).length === 0) {
|
|
1229
1261
|
this.logger.info(`${chalk3__default.default.bold.green("Loaded")}: ${chalk3__default.default.magenta.bold("0")} emojis`);
|
|
1230
1262
|
return;
|
|
@@ -1233,14 +1265,24 @@ var EmojiInjector = class {
|
|
|
1233
1265
|
await this.core.bot.client.application?.emojis.fetch();
|
|
1234
1266
|
let foundCount = 0;
|
|
1235
1267
|
Object.entries(configEmojis).forEach(([key, emojiName]) => {
|
|
1268
|
+
if (typeof emojiName !== "string") {
|
|
1269
|
+
this.logger.warn(`${chalk3__default.default.bold.yellow("Invalid")}: ${chalk3__default.default.magenta.bold(String(key))} (expected string, received ${typeof emojiName})`);
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1236
1272
|
const emoji = this.core.bot.client.application?.emojis.cache.find((e) => e.name === emojiName);
|
|
1237
1273
|
if (emoji) {
|
|
1238
|
-
|
|
1274
|
+
emojiStorage[key] = `<${emoji.identifier}>`;
|
|
1239
1275
|
foundCount++;
|
|
1240
1276
|
this.logger.debug(`${chalk3__default.default.bold.green("Found")}: ${chalk3__default.default.magenta.bold(emojiName)} (${emoji.id})`);
|
|
1277
|
+
return;
|
|
1241
1278
|
}
|
|
1279
|
+
emojiStorage[key] = emojiName;
|
|
1280
|
+
this.logger.warn(`${chalk3__default.default.bold.yellow("Missing")}: ${chalk3__default.default.magenta.bold(emojiName)} (using configured value)`);
|
|
1242
1281
|
});
|
|
1243
|
-
this.logger.info(`${chalk3__default.default.bold.green("Loaded")}: ${chalk3__default.default.magenta.bold(foundCount)}
|
|
1282
|
+
this.logger.info(`${chalk3__default.default.bold.green("Loaded")}: ${chalk3__default.default.magenta.bold(foundCount)} emoji(s)`);
|
|
1283
|
+
}
|
|
1284
|
+
clearEmojis() {
|
|
1285
|
+
for (const key of Object.keys(emojiStorage)) Reflect.deleteProperty(emojiStorage, key);
|
|
1244
1286
|
}
|
|
1245
1287
|
};
|
|
1246
1288
|
|
|
@@ -1268,6 +1310,7 @@ var Bot = class extends Plugin {
|
|
|
1268
1310
|
events;
|
|
1269
1311
|
commands;
|
|
1270
1312
|
emojiInjector;
|
|
1313
|
+
emojis = Emojis;
|
|
1271
1314
|
constructor(core) {
|
|
1272
1315
|
super(core), this.core = core;
|
|
1273
1316
|
this._client = new discord_js.Client(core.config.bot.clientOptions);
|
|
@@ -1319,11 +1362,16 @@ var Bot = class extends Plugin {
|
|
|
1319
1362
|
get client() {
|
|
1320
1363
|
return this._client;
|
|
1321
1364
|
}
|
|
1365
|
+
emit(event, ...args) {
|
|
1366
|
+
return super.emit(event, ...args);
|
|
1367
|
+
}
|
|
1322
1368
|
};
|
|
1323
1369
|
_ts_decorate4([
|
|
1324
1370
|
envapt.Envapt("DISCORD_BOT_TOKEN", {
|
|
1325
1371
|
converter(raw, _fallback) {
|
|
1326
|
-
if (typeof raw !== "string")
|
|
1372
|
+
if (typeof raw !== "string") {
|
|
1373
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.ConfigMissingDiscordToken);
|
|
1374
|
+
}
|
|
1327
1375
|
return raw;
|
|
1328
1376
|
}
|
|
1329
1377
|
}),
|
|
@@ -1386,6 +1434,25 @@ function _ts_metadata5(k, v) {
|
|
|
1386
1434
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1387
1435
|
}
|
|
1388
1436
|
__name(_ts_metadata5, "_ts_metadata");
|
|
1437
|
+
function webhookUrlValidator(raw, _fallback) {
|
|
1438
|
+
if (raw === null) {
|
|
1439
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.ConfigUnknownExceptionWebhookMissing);
|
|
1440
|
+
}
|
|
1441
|
+
if (typeof raw !== "string") {
|
|
1442
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.ConfigUnknownExceptionWebhookInvalid);
|
|
1443
|
+
}
|
|
1444
|
+
const value = raw.trim();
|
|
1445
|
+
if (value === "") {
|
|
1446
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.ConfigUnknownExceptionWebhookMissing);
|
|
1447
|
+
}
|
|
1448
|
+
const pattern = String.raw`^https?:\/\/(?:canary\.|ptb\.)?discord(?:app)?\.com\/api\/webhooks\/\d+\/[\w$-]+$`;
|
|
1449
|
+
const discordWebhookRegex = new RegExp(pattern);
|
|
1450
|
+
if (!URL.canParse(value) || !discordWebhookRegex.test(value)) {
|
|
1451
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.ConfigUnknownExceptionWebhookInvalid);
|
|
1452
|
+
}
|
|
1453
|
+
return value;
|
|
1454
|
+
}
|
|
1455
|
+
__name(webhookUrlValidator, "webhookUrlValidator");
|
|
1389
1456
|
exports.UnknownException = class _UnknownException extends WebhookLog {
|
|
1390
1457
|
static {
|
|
1391
1458
|
__name(this, "UnknownException");
|
|
@@ -1425,11 +1492,7 @@ exports.UnknownException = class _UnknownException extends WebhookLog {
|
|
|
1425
1492
|
};
|
|
1426
1493
|
_ts_decorate5([
|
|
1427
1494
|
envapt.Envapt("UNKNOWN_EXCEPTION_WEBHOOK_URL", {
|
|
1428
|
-
converter(raw,
|
|
1429
|
-
if (!raw) throw new Error("Missing UNKNOWN_EXCEPTION_WEBHOOK_URL");
|
|
1430
|
-
if (!URL.canParse(String(raw))) throw new Error("Invalid UNKNOWN_EXCEPTION_WEBHOOK_URL");
|
|
1431
|
-
return raw;
|
|
1432
|
-
}
|
|
1495
|
+
converter: /* @__PURE__ */ __name((raw, fallback) => webhookUrlValidator(raw), "converter")
|
|
1433
1496
|
}),
|
|
1434
1497
|
_ts_metadata5("design:type", String)
|
|
1435
1498
|
], exports.UnknownException, "unknownExceptionWebhookUrl", void 0);
|
|
@@ -1618,7 +1681,7 @@ var Seedcord = class _Seedcord extends Pluggable {
|
|
|
1618
1681
|
* Creates a new Seedcord instance
|
|
1619
1682
|
*
|
|
1620
1683
|
* @param config - Bot configuration including paths and Discord client options
|
|
1621
|
-
* @throws An {@link
|
|
1684
|
+
* @throws An {@link SeedcordError} When attempting to create multiple instances (singleton)
|
|
1622
1685
|
*/
|
|
1623
1686
|
constructor(config) {
|
|
1624
1687
|
const shutdown = new services.CoordinatedShutdown();
|
|
@@ -1627,7 +1690,7 @@ var Seedcord = class _Seedcord extends Pluggable {
|
|
|
1627
1690
|
this.shutdown = shutdown;
|
|
1628
1691
|
this.startup = startup;
|
|
1629
1692
|
if (_Seedcord.isInstantiated) {
|
|
1630
|
-
throw new
|
|
1693
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.CoreSingletonViolation);
|
|
1631
1694
|
}
|
|
1632
1695
|
_Seedcord.isInstantiated = true;
|
|
1633
1696
|
this.effects = new EffectsRegistry(this);
|
|
@@ -1679,7 +1742,7 @@ function EventCatchable(log) {
|
|
|
1679
1742
|
return function(_target, _prop, descriptor) {
|
|
1680
1743
|
const original = descriptor.value;
|
|
1681
1744
|
descriptor.value = async function(...args) {
|
|
1682
|
-
if (!original) throw new
|
|
1745
|
+
if (!original) throw new services.SeedcordError(services.SeedcordErrorCode.DecoratorMethodNotFound);
|
|
1683
1746
|
try {
|
|
1684
1747
|
await original.apply(this, args);
|
|
1685
1748
|
} catch (err) {
|
|
@@ -1703,6 +1766,206 @@ function EventCatchable(log) {
|
|
|
1703
1766
|
};
|
|
1704
1767
|
}
|
|
1705
1768
|
__name(EventCatchable, "EventCatchable");
|
|
1769
|
+
var resolveFactory = /* @__PURE__ */ __name(async (input, ctx) => typeof input === "function" ? await input(ctx) : input, "resolveFactory");
|
|
1770
|
+
var isV2 = /* @__PURE__ */ __name((opts) => "container" in opts, "isV2");
|
|
1771
|
+
var usesResolver = /* @__PURE__ */ __name((opts) => "resolveDecision" in opts, "usesResolver");
|
|
1772
|
+
var usesCustomIds = /* @__PURE__ */ __name((opts) => "confirmCustomIds" in opts, "usesCustomIds");
|
|
1773
|
+
var isMessageComponentIx = /* @__PURE__ */ __name((ix) => "deferUpdate" in ix && "customId" in ix, "isMessageComponentIx");
|
|
1774
|
+
var buildPrompt = /* @__PURE__ */ __name(async (opts, ctx) => {
|
|
1775
|
+
if (isV2(opts)) {
|
|
1776
|
+
const container = await resolveFactory(opts.container, ctx);
|
|
1777
|
+
return {
|
|
1778
|
+
flags: "IsComponentsV2",
|
|
1779
|
+
components: [
|
|
1780
|
+
container.component
|
|
1781
|
+
]
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
const prompt = await resolveFactory(opts.prompt, ctx);
|
|
1785
|
+
const rows = await resolveFactory(opts.rows, ctx);
|
|
1786
|
+
const components = [
|
|
1787
|
+
...rows
|
|
1788
|
+
];
|
|
1789
|
+
const payload = {
|
|
1790
|
+
components
|
|
1791
|
+
};
|
|
1792
|
+
if (typeof prompt === "string") payload.content = prompt;
|
|
1793
|
+
else payload.embeds = [
|
|
1794
|
+
prompt.component
|
|
1795
|
+
];
|
|
1796
|
+
return payload;
|
|
1797
|
+
}, "buildPrompt");
|
|
1798
|
+
var clearedPayload = /* @__PURE__ */ __name((opts) => isV2(opts) ? {
|
|
1799
|
+
flags: "IsComponentsV2",
|
|
1800
|
+
components: []
|
|
1801
|
+
} : {
|
|
1802
|
+
components: []
|
|
1803
|
+
}, "clearedPayload");
|
|
1804
|
+
var decide = /* @__PURE__ */ __name(async (opts, i) => {
|
|
1805
|
+
if (usesResolver(opts)) return opts.resolveDecision(i);
|
|
1806
|
+
if (usesCustomIds(opts)) {
|
|
1807
|
+
const { confirmCustomIds, cancelCustomIds = [] } = opts;
|
|
1808
|
+
if (confirmCustomIds.includes(i.customId)) return true;
|
|
1809
|
+
if (cancelCustomIds.includes(i.customId)) return false;
|
|
1810
|
+
}
|
|
1811
|
+
return false;
|
|
1812
|
+
}, "decide");
|
|
1813
|
+
var shouldDefer = /* @__PURE__ */ __name((ix, opts, isSlash, isContext) => {
|
|
1814
|
+
if (ix.deferred) return false;
|
|
1815
|
+
if (opts.defer === false) return false;
|
|
1816
|
+
return isSlash || isContext;
|
|
1817
|
+
}, "shouldDefer");
|
|
1818
|
+
var maybeDefer = /* @__PURE__ */ __name(async (ix, opts, isSlash, isContext) => {
|
|
1819
|
+
if (!shouldDefer(ix, opts, isSlash, isContext)) return;
|
|
1820
|
+
if (isSlash || isContext) {
|
|
1821
|
+
const { ephemeral = true } = opts;
|
|
1822
|
+
const flags = ephemeral ? {
|
|
1823
|
+
flags: "Ephemeral"
|
|
1824
|
+
} : void 0;
|
|
1825
|
+
if (flags) await ix.deferReply(flags);
|
|
1826
|
+
else await ix.deferReply();
|
|
1827
|
+
} else if (isMessageComponentIx(ix)) {
|
|
1828
|
+
await ix.deferUpdate();
|
|
1829
|
+
} else {
|
|
1830
|
+
await ix.deferReply().catch(() => void 0);
|
|
1831
|
+
}
|
|
1832
|
+
}, "maybeDefer");
|
|
1833
|
+
var sendPrompt = /* @__PURE__ */ __name(async (ix, payload, ephemeral, isSlash, isContext) => {
|
|
1834
|
+
if (isSlash || isContext) {
|
|
1835
|
+
if (ix.deferred) return ix.editReply(payload);
|
|
1836
|
+
const reply = {
|
|
1837
|
+
...payload,
|
|
1838
|
+
...ephemeral ? {
|
|
1839
|
+
flags: "Ephemeral"
|
|
1840
|
+
} : {}
|
|
1841
|
+
};
|
|
1842
|
+
await ix.reply(reply);
|
|
1843
|
+
return ix.fetchReply();
|
|
1844
|
+
}
|
|
1845
|
+
const follow = {
|
|
1846
|
+
...payload,
|
|
1847
|
+
...ephemeral ? {
|
|
1848
|
+
flags: "Ephemeral"
|
|
1849
|
+
} : {}
|
|
1850
|
+
};
|
|
1851
|
+
return ix.followUp(follow);
|
|
1852
|
+
}, "sendPrompt");
|
|
1853
|
+
var awaitComponent = /* @__PURE__ */ __name(async (msg, original, opts) => {
|
|
1854
|
+
const componentType = opts.componentType ?? discord_js.ComponentType.Button;
|
|
1855
|
+
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
1856
|
+
try {
|
|
1857
|
+
const button = await msg.awaitMessageComponent({
|
|
1858
|
+
componentType,
|
|
1859
|
+
time: timeoutMs,
|
|
1860
|
+
filter: /* @__PURE__ */ __name((c) => {
|
|
1861
|
+
if (c.user.id !== original.user.id) return false;
|
|
1862
|
+
if (usesCustomIds(opts)) {
|
|
1863
|
+
const { confirmCustomIds, cancelCustomIds = [] } = opts;
|
|
1864
|
+
return confirmCustomIds.includes(c.customId) || cancelCustomIds.includes(c.customId);
|
|
1865
|
+
}
|
|
1866
|
+
return true;
|
|
1867
|
+
}, "filter")
|
|
1868
|
+
});
|
|
1869
|
+
return {
|
|
1870
|
+
button,
|
|
1871
|
+
timedOut: false
|
|
1872
|
+
};
|
|
1873
|
+
} catch {
|
|
1874
|
+
return {
|
|
1875
|
+
button: null,
|
|
1876
|
+
timedOut: true
|
|
1877
|
+
};
|
|
1878
|
+
}
|
|
1879
|
+
}, "awaitComponent");
|
|
1880
|
+
var clearUi = /* @__PURE__ */ __name(async (ix, msg, opts, isSlash) => {
|
|
1881
|
+
if (!isSlash) {
|
|
1882
|
+
try {
|
|
1883
|
+
await msg.edit(clearedPayload(opts));
|
|
1884
|
+
} catch {
|
|
1885
|
+
await ix.deleteReply(msg).catch(() => void 0);
|
|
1886
|
+
}
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1889
|
+
await ix.editReply(clearedPayload(opts)).catch(() => void 0);
|
|
1890
|
+
}, "clearUi");
|
|
1891
|
+
var normalizeClassicOutcome = /* @__PURE__ */ __name((payload) => ({
|
|
1892
|
+
...payload,
|
|
1893
|
+
components: payload.components ?? []
|
|
1894
|
+
}), "normalizeClassicOutcome");
|
|
1895
|
+
var outcomeReplacement = /* @__PURE__ */ __name(async (opts, ctx, confirmed, timedOut) => {
|
|
1896
|
+
const outcomes = opts.outcomeUi;
|
|
1897
|
+
if (isV2(opts)) {
|
|
1898
|
+
const v2Outcomes = outcomes;
|
|
1899
|
+
if (timedOut) return await resolveFactory(v2Outcomes.onTimeout, ctx);
|
|
1900
|
+
if (!confirmed) return await resolveFactory(v2Outcomes.onCancel, ctx);
|
|
1901
|
+
if (v2Outcomes.onConfirm) return await resolveFactory(v2Outcomes.onConfirm, ctx);
|
|
1902
|
+
return null;
|
|
1903
|
+
}
|
|
1904
|
+
const classicOutcomes = outcomes;
|
|
1905
|
+
if (timedOut) return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onTimeout, ctx));
|
|
1906
|
+
if (!confirmed) return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onCancel, ctx));
|
|
1907
|
+
if (classicOutcomes.onConfirm) {
|
|
1908
|
+
return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onConfirm, ctx));
|
|
1909
|
+
}
|
|
1910
|
+
return null;
|
|
1911
|
+
}, "outcomeReplacement");
|
|
1912
|
+
function Confirmable(question, options) {
|
|
1913
|
+
return function(_target, _propertyKey, descriptor) {
|
|
1914
|
+
const original = descriptor.value;
|
|
1915
|
+
descriptor.value = async function(...args) {
|
|
1916
|
+
if (!original) throw new services.SeedcordError(services.SeedcordErrorCode.DecoratorMethodNotFound);
|
|
1917
|
+
const ix = this.getEvent();
|
|
1918
|
+
const isSlash = ix.isChatInputCommand();
|
|
1919
|
+
const isContext = ix.isContextMenuCommand();
|
|
1920
|
+
const { ephemeral = true } = options;
|
|
1921
|
+
await maybeDefer(ix, options, isSlash, isContext);
|
|
1922
|
+
const q = typeof question === "function" ? await question.apply(this) : question;
|
|
1923
|
+
const ctx = {
|
|
1924
|
+
handler: this,
|
|
1925
|
+
interaction: ix,
|
|
1926
|
+
question: q
|
|
1927
|
+
};
|
|
1928
|
+
const prompt = await buildPrompt(options, ctx);
|
|
1929
|
+
const promptMsg = await sendPrompt(ix, prompt, ephemeral, isSlash, isContext);
|
|
1930
|
+
const { button, timedOut } = await awaitComponent(promptMsg, ix, options);
|
|
1931
|
+
let confirmed = false;
|
|
1932
|
+
if (button) {
|
|
1933
|
+
await button.deferUpdate().catch(() => void 0);
|
|
1934
|
+
confirmed = await decide(options, button);
|
|
1935
|
+
}
|
|
1936
|
+
const replacement = await outcomeReplacement(options, ctx, confirmed, timedOut);
|
|
1937
|
+
if (replacement) {
|
|
1938
|
+
if (isSlash || isContext) {
|
|
1939
|
+
await ix.editReply(replacement).catch(() => void 0);
|
|
1940
|
+
} else {
|
|
1941
|
+
await promptMsg.edit(replacement).catch(async () => {
|
|
1942
|
+
await ix.deleteReply(promptMsg).catch(() => void 0);
|
|
1943
|
+
await ix.followUp(replacement).catch(() => void 0);
|
|
1944
|
+
});
|
|
1945
|
+
}
|
|
1946
|
+
} else {
|
|
1947
|
+
await clearUi(ix, promptMsg, options, isSlash);
|
|
1948
|
+
}
|
|
1949
|
+
if (options.onResolved) {
|
|
1950
|
+
await options.onResolved({
|
|
1951
|
+
confirmed,
|
|
1952
|
+
timedOut,
|
|
1953
|
+
handler: this,
|
|
1954
|
+
interaction: ix,
|
|
1955
|
+
question: q,
|
|
1956
|
+
...button ? {
|
|
1957
|
+
button
|
|
1958
|
+
} : {}
|
|
1959
|
+
});
|
|
1960
|
+
}
|
|
1961
|
+
if (confirmed) {
|
|
1962
|
+
await original.apply(this, args);
|
|
1963
|
+
}
|
|
1964
|
+
};
|
|
1965
|
+
return descriptor;
|
|
1966
|
+
};
|
|
1967
|
+
}
|
|
1968
|
+
__name(Confirmable, "Confirmable");
|
|
1706
1969
|
|
|
1707
1970
|
// src/bot/errors/Channels.ts
|
|
1708
1971
|
var ChannelNotFoundError = class extends CustomError {
|
|
@@ -2068,7 +2331,9 @@ function checkPermissions(client, roleOrChannel, scope = "all", inverse = false)
|
|
|
2068
2331
|
if (roleOrChannel instanceof discord_js.Role) {
|
|
2069
2332
|
permissions = roleOrChannel.permissions;
|
|
2070
2333
|
} else {
|
|
2071
|
-
if (!client.user)
|
|
2334
|
+
if (!client.user) {
|
|
2335
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.CoreClientUserUnavailable);
|
|
2336
|
+
}
|
|
2072
2337
|
permissions = roleOrChannel.permissionsFor(client.user, true);
|
|
2073
2338
|
}
|
|
2074
2339
|
if (!permissions) {
|
|
@@ -2087,12 +2352,16 @@ function checkPermissions(client, roleOrChannel, scope = "all", inverse = false)
|
|
|
2087
2352
|
}
|
|
2088
2353
|
}
|
|
2089
2354
|
__name(checkPermissions, "checkPermissions");
|
|
2090
|
-
|
|
2091
|
-
// src/bot/utilities/roles/getBotRole.ts
|
|
2092
2355
|
function getBotRole(client, guild) {
|
|
2093
|
-
if (!client.user)
|
|
2356
|
+
if (!client.user) {
|
|
2357
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.CoreClientUserUnavailable);
|
|
2358
|
+
}
|
|
2094
2359
|
const botRole = guild.roles.botRoleFor(client.user);
|
|
2095
|
-
if (!botRole)
|
|
2360
|
+
if (!botRole) {
|
|
2361
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.CoreBotRoleMissing, [
|
|
2362
|
+
guild.id
|
|
2363
|
+
]);
|
|
2364
|
+
}
|
|
2096
2365
|
return botRole;
|
|
2097
2366
|
}
|
|
2098
2367
|
__name(getBotRole, "getBotRole");
|
|
@@ -2221,6 +2490,7 @@ exports.ChannelNotTextChannel = ChannelNotTextChannel;
|
|
|
2221
2490
|
exports.Checkable = Checkable;
|
|
2222
2491
|
exports.CommandMetadataKey = CommandMetadataKey;
|
|
2223
2492
|
exports.CommandRegistry = CommandRegistry;
|
|
2493
|
+
exports.Confirmable = Confirmable;
|
|
2224
2494
|
exports.ContextMenuRoute = ContextMenuRoute;
|
|
2225
2495
|
exports.CouldNotFindChannel = CouldNotFindChannel;
|
|
2226
2496
|
exports.CustomError = CustomError;
|
|
@@ -2230,6 +2500,7 @@ exports.EffectsEmitter = EffectsEmitter;
|
|
|
2230
2500
|
exports.EffectsHandler = EffectsHandler;
|
|
2231
2501
|
exports.EffectsRegistry = EffectsRegistry;
|
|
2232
2502
|
exports.EmojiInjector = EmojiInjector;
|
|
2503
|
+
exports.Emojis = Emojis;
|
|
2233
2504
|
exports.EventCatchable = EventCatchable;
|
|
2234
2505
|
exports.EventController = EventController;
|
|
2235
2506
|
exports.EventHandler = EventHandler;
|