seedcord 0.9.0 → 0.10.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 +951 -977
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +829 -640
- package/dist/index.d.ts +829 -640
- package/dist/index.mjs +952 -979
- package/dist/index.mjs.map +1 -1
- package/package.json +30 -5
package/dist/index.cjs
CHANGED
|
@@ -737,7 +737,7 @@ function buildSlashRoute(arg1, arg2, arg3) {
|
|
|
737
737
|
}
|
|
738
738
|
__name(buildSlashRoute, "buildSlashRoute");
|
|
739
739
|
|
|
740
|
-
// src/bot/errors/Database.ts
|
|
740
|
+
// src/bot/defaults/errors/Database.ts
|
|
741
741
|
var DatabaseError = class extends CustomError {
|
|
742
742
|
static {
|
|
743
743
|
__name(this, "DatabaseError");
|
|
@@ -1245,6 +1245,10 @@ var Pluggable = class _Pluggable extends services.StrictEventEmitter {
|
|
|
1245
1245
|
}
|
|
1246
1246
|
};
|
|
1247
1247
|
var emojiStorage = {};
|
|
1248
|
+
function isEmojiTuple(v) {
|
|
1249
|
+
return Array.isArray(v) && v.length === 2 && typeof v[0] === "string" && typeof v[1] === "string";
|
|
1250
|
+
}
|
|
1251
|
+
__name(isEmojiTuple, "isEmojiTuple");
|
|
1248
1252
|
var Emojis = emojiStorage;
|
|
1249
1253
|
var EmojiInjector = class {
|
|
1250
1254
|
static {
|
|
@@ -1264,23 +1268,57 @@ var EmojiInjector = class {
|
|
|
1264
1268
|
const configEmojis = this.core.config.bot.emojis;
|
|
1265
1269
|
await this.core.bot.client.application?.emojis.fetch();
|
|
1266
1270
|
let foundCount = 0;
|
|
1267
|
-
Object.entries(configEmojis)
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
+
const entries = Object.entries(configEmojis);
|
|
1272
|
+
for (const [key, value] of entries) {
|
|
1273
|
+
if (isEmojiTuple(value)) {
|
|
1274
|
+
foundCount += this.handleTuple(key, value);
|
|
1275
|
+
continue;
|
|
1271
1276
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
foundCount++;
|
|
1276
|
-
this.logger.debug(`${chalk3__default.default.bold.green("Found")}: ${chalk3__default.default.magenta.bold(emojiName)} (${emoji.id})`);
|
|
1277
|
-
return;
|
|
1277
|
+
if (typeof value === "string") {
|
|
1278
|
+
foundCount += this.handleString(key, value);
|
|
1279
|
+
continue;
|
|
1278
1280
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
});
|
|
1281
|
+
this.logger.warn(`${chalk3__default.default.bold.yellow("Invalid")}: ${chalk3__default.default.magenta.bold(String(key))} (expected string or [string, string])`);
|
|
1282
|
+
}
|
|
1282
1283
|
this.logger.info(`${chalk3__default.default.bold.green("Loaded")}: ${chalk3__default.default.magenta.bold(foundCount)} emoji(s)`);
|
|
1283
1284
|
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Handle emoji config values in tuple form: [emojiName, guildId]
|
|
1287
|
+
* Returns 1 when the emoji was found and stored as an emoji object, otherwise 0.
|
|
1288
|
+
*/
|
|
1289
|
+
handleTuple(key, value) {
|
|
1290
|
+
const [emojiName, guildId] = value;
|
|
1291
|
+
const guild = this.core.bot.client.guilds.cache.get(guildId);
|
|
1292
|
+
if (!guild) {
|
|
1293
|
+
emojiStorage[key] = emojiName;
|
|
1294
|
+
this.logger.warn(`${chalk3__default.default.bold.yellow("Missing")}: ${chalk3__default.default.magenta.bold(emojiName)} in guild ${chalk3__default.default.gray(guildId)} (guild not in cache or not found, using provided string)`);
|
|
1295
|
+
return 0;
|
|
1296
|
+
}
|
|
1297
|
+
const guildEmoji = guild.emojis.cache.find((e) => e.name === emojiName);
|
|
1298
|
+
if (guildEmoji) {
|
|
1299
|
+
emojiStorage[key] = guildEmoji;
|
|
1300
|
+
this.logger.debug(`${chalk3__default.default.bold.green("Found")}: ${chalk3__default.default.magenta.bold(emojiName)} (${guildEmoji.id}) in guild ${chalk3__default.default.gray(guildId)}`);
|
|
1301
|
+
return 1;
|
|
1302
|
+
}
|
|
1303
|
+
emojiStorage[key] = emojiName;
|
|
1304
|
+
this.logger.warn(`${chalk3__default.default.bold.yellow("Missing")}: ${chalk3__default.default.magenta.bold(emojiName)} in guild ${chalk3__default.default.magenta.bold(guildId)} (using provided string)`);
|
|
1305
|
+
return 0;
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Handle emoji config values provided as a simple string (application emoji lookup).
|
|
1309
|
+
* Returns 1 when the emoji was found and stored as an emoji object, otherwise 0.
|
|
1310
|
+
*/
|
|
1311
|
+
handleString(key, emojiName) {
|
|
1312
|
+
const appEmoji = this.core.bot.client.application?.emojis.cache.find((e) => e.name === emojiName);
|
|
1313
|
+
if (appEmoji) {
|
|
1314
|
+
emojiStorage[key] = appEmoji;
|
|
1315
|
+
this.logger.debug(`${chalk3__default.default.bold.green("Found")}: ${chalk3__default.default.magenta.bold(emojiName)} (${appEmoji.id})`);
|
|
1316
|
+
return 1;
|
|
1317
|
+
}
|
|
1318
|
+
emojiStorage[key] = emojiName;
|
|
1319
|
+
this.logger.warn(`${chalk3__default.default.bold.yellow("Missing")}: ${chalk3__default.default.magenta.bold(emojiName)} (using provided string)`);
|
|
1320
|
+
return 0;
|
|
1321
|
+
}
|
|
1284
1322
|
clearEmojis() {
|
|
1285
1323
|
for (const key of Object.keys(emojiStorage)) Reflect.deleteProperty(emojiStorage, key);
|
|
1286
1324
|
}
|
|
@@ -1378,1106 +1416,1041 @@ _ts_decorate4([
|
|
|
1378
1416
|
_ts_metadata4("design:type", String)
|
|
1379
1417
|
], Bot.prototype, "botToken", void 0);
|
|
1380
1418
|
|
|
1381
|
-
// src/
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
effect,
|
|
1387
|
-
frequency: options?.frequency
|
|
1388
|
-
};
|
|
1389
|
-
Reflect.defineMetadata(EffectMetadataKey, meta, constructor);
|
|
1419
|
+
// src/bot/decorators/Checkable.ts
|
|
1420
|
+
function Checkable(ctor) {
|
|
1421
|
+
return class extends ctor {
|
|
1422
|
+
static name = ctor.name;
|
|
1423
|
+
checkable = true;
|
|
1390
1424
|
};
|
|
1391
1425
|
}
|
|
1392
|
-
__name(
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
var
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
constructor(data, core) {
|
|
1408
|
-
this.data = data;
|
|
1409
|
-
this.core = core;
|
|
1410
|
-
this.data = data;
|
|
1411
|
-
this.core = core;
|
|
1412
|
-
}
|
|
1413
|
-
};
|
|
1414
|
-
|
|
1415
|
-
// src/effects/bases/WebhookLog.ts
|
|
1416
|
-
var WebhookLog = class extends EffectsHandler {
|
|
1417
|
-
static {
|
|
1418
|
-
__name(this, "WebhookLog");
|
|
1419
|
-
}
|
|
1420
|
-
constructor(data, core) {
|
|
1421
|
-
super(data, core);
|
|
1422
|
-
}
|
|
1423
|
-
};
|
|
1424
|
-
|
|
1425
|
-
// src/effects/default/UnknownException.ts
|
|
1426
|
-
function _ts_decorate5(decorators, target, key, desc) {
|
|
1427
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1428
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1429
|
-
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;
|
|
1430
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1431
|
-
}
|
|
1432
|
-
__name(_ts_decorate5, "_ts_decorate");
|
|
1433
|
-
function _ts_metadata5(k, v) {
|
|
1434
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1435
|
-
}
|
|
1436
|
-
__name(_ts_metadata5, "_ts_metadata");
|
|
1437
|
-
function webhookUrlValidator(raw, _fallback) {
|
|
1438
|
-
if (raw === null) {
|
|
1439
|
-
throw new services.SeedcordError(services.SeedcordErrorCode.ConfigUnknownExceptionWebhookMissing);
|
|
1426
|
+
__name(Checkable, "Checkable");
|
|
1427
|
+
var resolveFactory = /* @__PURE__ */ __name(async (input, ctx) => typeof input === "function" ? await input(ctx) : input, "resolveFactory");
|
|
1428
|
+
var isV2 = /* @__PURE__ */ __name((opts) => "container" in opts, "isV2");
|
|
1429
|
+
var usesResolver = /* @__PURE__ */ __name((opts) => "resolveDecision" in opts, "usesResolver");
|
|
1430
|
+
var usesCustomIds = /* @__PURE__ */ __name((opts) => "confirmCustomIds" in opts, "usesCustomIds");
|
|
1431
|
+
var isMessageComponentIx = /* @__PURE__ */ __name((ix) => "deferUpdate" in ix && "customId" in ix, "isMessageComponentIx");
|
|
1432
|
+
var buildPrompt = /* @__PURE__ */ __name(async (opts, ctx) => {
|
|
1433
|
+
if (isV2(opts)) {
|
|
1434
|
+
const container = await resolveFactory(opts.container, ctx);
|
|
1435
|
+
return {
|
|
1436
|
+
flags: "IsComponentsV2",
|
|
1437
|
+
components: [
|
|
1438
|
+
container.component
|
|
1439
|
+
]
|
|
1440
|
+
};
|
|
1440
1441
|
}
|
|
1441
|
-
|
|
1442
|
-
|
|
1442
|
+
const prompt = await resolveFactory(opts.prompt, ctx);
|
|
1443
|
+
const rows = await resolveFactory(opts.rows, ctx);
|
|
1444
|
+
const components = [
|
|
1445
|
+
...rows
|
|
1446
|
+
];
|
|
1447
|
+
const payload = {
|
|
1448
|
+
components
|
|
1449
|
+
};
|
|
1450
|
+
if (typeof prompt === "string") payload.content = prompt;
|
|
1451
|
+
else payload.embeds = [
|
|
1452
|
+
prompt.component
|
|
1453
|
+
];
|
|
1454
|
+
return payload;
|
|
1455
|
+
}, "buildPrompt");
|
|
1456
|
+
var clearedPayload = /* @__PURE__ */ __name((opts) => isV2(opts) ? {
|
|
1457
|
+
flags: "IsComponentsV2",
|
|
1458
|
+
components: []
|
|
1459
|
+
} : {
|
|
1460
|
+
components: []
|
|
1461
|
+
}, "clearedPayload");
|
|
1462
|
+
var decide = /* @__PURE__ */ __name(async (opts, i) => {
|
|
1463
|
+
if (usesResolver(opts)) return opts.resolveDecision(i);
|
|
1464
|
+
if (usesCustomIds(opts)) {
|
|
1465
|
+
const { confirmCustomIds, cancelCustomIds = [] } = opts;
|
|
1466
|
+
if (confirmCustomIds.includes(i.customId)) return true;
|
|
1467
|
+
if (cancelCustomIds.includes(i.customId)) return false;
|
|
1443
1468
|
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1469
|
+
return false;
|
|
1470
|
+
}, "decide");
|
|
1471
|
+
var shouldDefer = /* @__PURE__ */ __name((ix, opts, isSlash, isContext) => {
|
|
1472
|
+
if (ix.deferred) return false;
|
|
1473
|
+
if (opts.defer === false) return false;
|
|
1474
|
+
return isSlash || isContext;
|
|
1475
|
+
}, "shouldDefer");
|
|
1476
|
+
var maybeDefer = /* @__PURE__ */ __name(async (ix, opts, isSlash, isContext) => {
|
|
1477
|
+
if (!shouldDefer(ix, opts, isSlash, isContext)) return;
|
|
1478
|
+
if (isSlash || isContext) {
|
|
1479
|
+
const { ephemeral = true } = opts;
|
|
1480
|
+
const flags = ephemeral ? {
|
|
1481
|
+
flags: "Ephemeral"
|
|
1482
|
+
} : void 0;
|
|
1483
|
+
if (flags) await ix.deferReply(flags);
|
|
1484
|
+
else await ix.deferReply();
|
|
1485
|
+
} else if (isMessageComponentIx(ix)) {
|
|
1486
|
+
await ix.deferUpdate();
|
|
1487
|
+
} else {
|
|
1488
|
+
await ix.deferReply().catch(() => void 0);
|
|
1447
1489
|
}
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
if (
|
|
1451
|
-
|
|
1490
|
+
}, "maybeDefer");
|
|
1491
|
+
var sendPrompt = /* @__PURE__ */ __name(async (ix, payload, ephemeral, isSlash, isContext) => {
|
|
1492
|
+
if (isSlash || isContext) {
|
|
1493
|
+
if (ix.deferred) return ix.editReply(payload);
|
|
1494
|
+
const reply = {
|
|
1495
|
+
...payload,
|
|
1496
|
+
...ephemeral ? {
|
|
1497
|
+
flags: "Ephemeral"
|
|
1498
|
+
} : {}
|
|
1499
|
+
};
|
|
1500
|
+
await ix.reply(reply);
|
|
1501
|
+
return ix.fetchReply();
|
|
1452
1502
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1503
|
+
const follow = {
|
|
1504
|
+
...payload,
|
|
1505
|
+
...ephemeral ? {
|
|
1506
|
+
flags: "Ephemeral"
|
|
1507
|
+
} : {}
|
|
1508
|
+
};
|
|
1509
|
+
return ix.followUp(follow);
|
|
1510
|
+
}, "sendPrompt");
|
|
1511
|
+
var awaitComponent = /* @__PURE__ */ __name(async (msg, original, opts) => {
|
|
1512
|
+
const componentType = opts.componentType ?? discord_js.ComponentType.Button;
|
|
1513
|
+
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
1514
|
+
try {
|
|
1515
|
+
const button = await msg.awaitMessageComponent({
|
|
1516
|
+
componentType,
|
|
1517
|
+
time: timeoutMs,
|
|
1518
|
+
filter: /* @__PURE__ */ __name((c) => {
|
|
1519
|
+
if (c.user.id !== original.user.id) return false;
|
|
1520
|
+
if (usesCustomIds(opts)) {
|
|
1521
|
+
const { confirmCustomIds, cancelCustomIds = [] } = opts;
|
|
1522
|
+
return confirmCustomIds.includes(c.customId) || cancelCustomIds.includes(c.customId);
|
|
1523
|
+
}
|
|
1524
|
+
return true;
|
|
1525
|
+
}, "filter")
|
|
1526
|
+
});
|
|
1527
|
+
return {
|
|
1528
|
+
button,
|
|
1529
|
+
timedOut: false
|
|
1530
|
+
};
|
|
1531
|
+
} catch {
|
|
1532
|
+
return {
|
|
1533
|
+
button: null,
|
|
1534
|
+
timedOut: true
|
|
1535
|
+
};
|
|
1459
1536
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
});
|
|
1464
|
-
async execute() {
|
|
1465
|
-
const metadataFile = this.prepareMetadataFile();
|
|
1537
|
+
}, "awaitComponent");
|
|
1538
|
+
var clearUi = /* @__PURE__ */ __name(async (ix, msg, opts, isSlash) => {
|
|
1539
|
+
if (!isSlash) {
|
|
1466
1540
|
try {
|
|
1467
|
-
await
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
username: "Unknown Exception",
|
|
1471
|
-
avatarURL: "https://cdn.discordapp.com/attachments/1351446034827579466/1351446912947191830/warning-2.png",
|
|
1472
|
-
components: [
|
|
1473
|
-
new UnhandledErrorContainer(this.data).component
|
|
1474
|
-
],
|
|
1475
|
-
files: metadataFile ? [
|
|
1476
|
-
metadataFile
|
|
1477
|
-
] : []
|
|
1478
|
-
});
|
|
1479
|
-
} catch (error) {
|
|
1480
|
-
_UnknownException.logger.error("Failed to send unknown exception webhook", error);
|
|
1541
|
+
await msg.edit(clearedPayload(opts));
|
|
1542
|
+
} catch {
|
|
1543
|
+
await ix.deleteReply(msg).catch(() => void 0);
|
|
1481
1544
|
}
|
|
1545
|
+
return;
|
|
1482
1546
|
}
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1547
|
+
await ix.editReply(clearedPayload(opts)).catch(() => void 0);
|
|
1548
|
+
}, "clearUi");
|
|
1549
|
+
var normalizeClassicOutcome = /* @__PURE__ */ __name((payload) => ({
|
|
1550
|
+
...payload,
|
|
1551
|
+
components: payload.components ?? []
|
|
1552
|
+
}), "normalizeClassicOutcome");
|
|
1553
|
+
var outcomeReplacement = /* @__PURE__ */ __name(async (opts, ctx, confirmed, timedOut) => {
|
|
1554
|
+
const outcomes = opts.outcomeUi;
|
|
1555
|
+
if (isV2(opts)) {
|
|
1556
|
+
const v2Outcomes = outcomes;
|
|
1557
|
+
if (timedOut) return await resolveFactory(v2Outcomes.onTimeout, ctx);
|
|
1558
|
+
if (!confirmed) return await resolveFactory(v2Outcomes.onCancel, ctx);
|
|
1559
|
+
if (v2Outcomes.onConfirm) return await resolveFactory(v2Outcomes.onConfirm, ctx);
|
|
1560
|
+
return null;
|
|
1491
1561
|
}
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
_ts_metadata5("design:type", String)
|
|
1498
|
-
], exports.UnknownException, "unknownExceptionWebhookUrl", void 0);
|
|
1499
|
-
exports.UnknownException = _ts_decorate5([
|
|
1500
|
-
RegisterEffect("unknownException")
|
|
1501
|
-
], exports.UnknownException);
|
|
1502
|
-
var DefaultSeparator = class DefaultSeparator2 extends BuilderComponent {
|
|
1503
|
-
static {
|
|
1504
|
-
__name(this, "DefaultSeparator");
|
|
1505
|
-
}
|
|
1506
|
-
constructor() {
|
|
1507
|
-
super("separator");
|
|
1508
|
-
this.instance.setSpacing(discord_js.SeparatorSpacingSize.Small).setDivider(true);
|
|
1562
|
+
const classicOutcomes = outcomes;
|
|
1563
|
+
if (timedOut) return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onTimeout, ctx));
|
|
1564
|
+
if (!confirmed) return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onCancel, ctx));
|
|
1565
|
+
if (classicOutcomes.onConfirm) {
|
|
1566
|
+
return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onConfirm, ctx));
|
|
1509
1567
|
}
|
|
1510
|
-
|
|
1511
|
-
|
|
1568
|
+
return null;
|
|
1569
|
+
}, "outcomeReplacement");
|
|
1570
|
+
function Confirmable(question, options) {
|
|
1571
|
+
return function(_target, _propertyKey, descriptor) {
|
|
1572
|
+
const original = descriptor.value;
|
|
1573
|
+
descriptor.value = async function(...args) {
|
|
1574
|
+
if (!original) throw new services.SeedcordError(services.SeedcordErrorCode.DecoratorMethodNotFound);
|
|
1575
|
+
const ix = this.getEvent();
|
|
1576
|
+
const isSlash = ix.isChatInputCommand();
|
|
1577
|
+
const isContext = ix.isContextMenuCommand();
|
|
1578
|
+
const { ephemeral = true } = options;
|
|
1579
|
+
await maybeDefer(ix, options, isSlash, isContext);
|
|
1580
|
+
const q = typeof question === "function" ? await question.apply(this) : question;
|
|
1581
|
+
const ctx = {
|
|
1582
|
+
handler: this,
|
|
1583
|
+
interaction: ix,
|
|
1584
|
+
question: q
|
|
1585
|
+
};
|
|
1586
|
+
const prompt = await buildPrompt(options, ctx);
|
|
1587
|
+
const promptMsg = await sendPrompt(ix, prompt, ephemeral, isSlash, isContext);
|
|
1588
|
+
const { button, timedOut } = await awaitComponent(promptMsg, ix, options);
|
|
1589
|
+
let confirmed = false;
|
|
1590
|
+
if (button) {
|
|
1591
|
+
await button.deferUpdate().catch(() => void 0);
|
|
1592
|
+
confirmed = await decide(options, button);
|
|
1593
|
+
}
|
|
1594
|
+
const replacement = await outcomeReplacement(options, ctx, confirmed, timedOut);
|
|
1595
|
+
if (replacement) {
|
|
1596
|
+
if (isSlash || isContext) {
|
|
1597
|
+
await ix.editReply(replacement).catch(() => void 0);
|
|
1598
|
+
} else {
|
|
1599
|
+
await promptMsg.edit(replacement).catch(async () => {
|
|
1600
|
+
await ix.deleteReply(promptMsg).catch(() => void 0);
|
|
1601
|
+
await ix.followUp(replacement).catch(() => void 0);
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
} else {
|
|
1605
|
+
await clearUi(ix, promptMsg, options, isSlash);
|
|
1606
|
+
}
|
|
1607
|
+
if (options.onResolved) {
|
|
1608
|
+
await options.onResolved({
|
|
1609
|
+
confirmed,
|
|
1610
|
+
timedOut,
|
|
1611
|
+
handler: this,
|
|
1612
|
+
interaction: ix,
|
|
1613
|
+
question: q,
|
|
1614
|
+
...button ? {
|
|
1615
|
+
button
|
|
1616
|
+
} : {}
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
if (confirmed) {
|
|
1620
|
+
await original.apply(this, args);
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
return descriptor;
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
__name(Confirmable, "Confirmable");
|
|
1627
|
+
function EventCatchable(options) {
|
|
1628
|
+
return function(_target, _prop, descriptor) {
|
|
1629
|
+
const log = options?.log ?? false;
|
|
1630
|
+
const silent = options?.silent ?? false;
|
|
1631
|
+
const original = descriptor.value;
|
|
1632
|
+
descriptor.value = async function(...args) {
|
|
1633
|
+
if (!original) throw new services.SeedcordError(services.SeedcordErrorCode.DecoratorMethodNotFound);
|
|
1634
|
+
try {
|
|
1635
|
+
await original.apply(this, args);
|
|
1636
|
+
} catch (err) {
|
|
1637
|
+
if (!(err instanceof Error)) throw err;
|
|
1638
|
+
this.setErrored();
|
|
1639
|
+
if (log) console.error(err);
|
|
1640
|
+
const eventArgs = Array.isArray(this.getEvent()) ? this.getEvent() : [
|
|
1641
|
+
this.getEvent()
|
|
1642
|
+
];
|
|
1643
|
+
const msg = eventArgs.find((x) => x instanceof discord_js.Message);
|
|
1644
|
+
const { response } = extractErrorResponse(err, this.core, msg?.guild ?? null, msg?.author ?? null, eventArgs);
|
|
1645
|
+
if (typeof silent === "boolean" && silent) return;
|
|
1646
|
+
if (typeof silent !== "boolean" && silent.some((errorType) => err instanceof errorType)) {
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1649
|
+
if (!msg) return;
|
|
1650
|
+
await msg.reply({
|
|
1651
|
+
embeds: [
|
|
1652
|
+
response
|
|
1653
|
+
],
|
|
1654
|
+
components: []
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
};
|
|
1659
|
+
}
|
|
1660
|
+
__name(EventCatchable, "EventCatchable");
|
|
1661
|
+
|
|
1662
|
+
// src/bot/defaults/errors/Channels.ts
|
|
1663
|
+
var ChannelNotFoundError = class extends CustomError {
|
|
1512
1664
|
static {
|
|
1513
|
-
__name(this, "
|
|
1514
|
-
}
|
|
1515
|
-
constructor(data) {
|
|
1516
|
-
super("container");
|
|
1517
|
-
const { uuid, error, guild, user, metadata } = data;
|
|
1518
|
-
this.instance.addTextDisplayComponents((text) => text.setContent(`### An unknown exception was thrown
|
|
1519
|
-
**Guild ID:** \`${guild?.id ?? "Not used in a guild"}\`
|
|
1520
|
-
**Guild Name:** ${guild?.name ?? "Not used in a guild"}
|
|
1521
|
-
**User ID:** \`${user?.id ?? "Missing user info"}\`
|
|
1522
|
-
**Username:** ${user?.username ?? "Missing user info"}
|
|
1523
|
-
`)).addSeparatorComponents(new DefaultSeparator().component).addTextDisplayComponents((text) => text.setContent(`### UUID \`${uuid}\`
|
|
1524
|
-
\`\`\`${error.stack}\`\`\``));
|
|
1525
|
-
this.addTimestampsIfAvailable(error);
|
|
1526
|
-
this.addMetadataIfAvailable(metadata);
|
|
1527
|
-
}
|
|
1528
|
-
addTimestampsIfAvailable(error) {
|
|
1529
|
-
if (!(error instanceof discord_js.DiscordAPIError)) return;
|
|
1530
|
-
const now = Date.now();
|
|
1531
|
-
const snowflake = error.url.match(/\/interactions\/(\d+)\//)?.[1];
|
|
1532
|
-
if (!snowflake) return void 0;
|
|
1533
|
-
const interactionTs = Number(discord_js.SnowflakeUtil.deconstruct(snowflake).timestamp);
|
|
1534
|
-
const diff = now - interactionTs;
|
|
1535
|
-
const seconds = Math.floor(diff / 1e3);
|
|
1536
|
-
const millis = diff % 1e3;
|
|
1537
|
-
this.instance.addSeparatorComponents(new DefaultSeparator().component).addTextDisplayComponents((text) => text.setContent(`### Timestamps
|
|
1538
|
-
- **\`Interaction sent\` :** ${new Date(interactionTs).toISOString()} (${interactionTs})
|
|
1539
|
-
- **\`Error logged \` :** ${new Date(now).toISOString()} (${now})
|
|
1540
|
-
- **\`Offset \` :** ${seconds}s ${millis}ms`));
|
|
1665
|
+
__name(this, "ChannelNotFoundError");
|
|
1541
1666
|
}
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1667
|
+
channelId;
|
|
1668
|
+
/**
|
|
1669
|
+
* Creates a new ChannelNotFoundError.
|
|
1670
|
+
*
|
|
1671
|
+
* @param message - The error message
|
|
1672
|
+
* @param channelId - The ID of the channel that could not be found
|
|
1673
|
+
*/
|
|
1674
|
+
constructor(message, channelId) {
|
|
1675
|
+
super(message), this.channelId = channelId;
|
|
1676
|
+
this.response.setDescription(`Channel with ID \`${this.channelId}\` not found.`);
|
|
1545
1677
|
}
|
|
1546
1678
|
};
|
|
1547
|
-
var
|
|
1679
|
+
var CannotSendEmbedsError = class extends CustomError {
|
|
1548
1680
|
static {
|
|
1549
|
-
__name(this, "
|
|
1681
|
+
__name(this, "CannotSendEmbedsError");
|
|
1550
1682
|
}
|
|
1551
|
-
|
|
1683
|
+
channelId;
|
|
1552
1684
|
/**
|
|
1553
|
-
*
|
|
1685
|
+
* Creates a new CannotSendEmbedsError.
|
|
1554
1686
|
*
|
|
1555
|
-
* @
|
|
1556
|
-
* @param
|
|
1557
|
-
* @param listener - Function to call when the event is emitted
|
|
1558
|
-
* @returns This EffectsEmitter instance for chaining
|
|
1687
|
+
* @param message - The error message
|
|
1688
|
+
* @param channelId - The ID of the channel where embeds cannot be sent
|
|
1559
1689
|
*/
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1690
|
+
constructor(message, channelId) {
|
|
1691
|
+
super(message), this.channelId = channelId;
|
|
1692
|
+
this.response.setDescription(`Cannot send embeds in <#${this.channelId}>.
|
|
1693
|
+
|
|
1694
|
+
Please ensure I have the following permissions:
|
|
1695
|
+
\u2022 View Channel
|
|
1696
|
+
\u2022 Send Messages
|
|
1697
|
+
\u2022 Embed Links
|
|
1698
|
+
\u2022 Attach Files
|
|
1699
|
+
\u2022 Read Message History
|
|
1700
|
+
\u2022 Use External Emojis
|
|
1701
|
+
`);
|
|
1702
|
+
}
|
|
1703
|
+
};
|
|
1704
|
+
var CouldNotFindChannel = class extends CustomError {
|
|
1705
|
+
static {
|
|
1706
|
+
__name(this, "CouldNotFindChannel");
|
|
1563
1707
|
}
|
|
1708
|
+
channelId;
|
|
1564
1709
|
/**
|
|
1565
|
-
*
|
|
1710
|
+
* Creates a new CouldNotFindChannel error.
|
|
1566
1711
|
*
|
|
1567
|
-
* @
|
|
1568
|
-
* @param
|
|
1569
|
-
* @param listener - Function to call when the event is emitted
|
|
1570
|
-
* @returns This EffectsEmitter instance for chaining
|
|
1712
|
+
* @param message - The error message
|
|
1713
|
+
* @param channelId - The ID of the channel that could not be found
|
|
1571
1714
|
*/
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1715
|
+
constructor(message, channelId) {
|
|
1716
|
+
super(message), this.channelId = channelId;
|
|
1717
|
+
this.response.setDescription(`Could not find channel with ID \`${this.channelId}\`. It could also be that the channel is not a text channel.`);
|
|
1718
|
+
}
|
|
1719
|
+
};
|
|
1720
|
+
var ChannelNotTextChannel = class extends CustomError {
|
|
1721
|
+
static {
|
|
1722
|
+
__name(this, "ChannelNotTextChannel");
|
|
1575
1723
|
}
|
|
1724
|
+
channelId;
|
|
1576
1725
|
/**
|
|
1577
|
-
*
|
|
1726
|
+
* Creates a new ChannelNotTextChannel error.
|
|
1578
1727
|
*
|
|
1579
|
-
* @
|
|
1580
|
-
* @param
|
|
1581
|
-
* @param data - The data to pass to registered listeners
|
|
1582
|
-
* @returns True if the event had listeners, false otherwise
|
|
1728
|
+
* @param message - The error message
|
|
1729
|
+
* @param channelId - The ID of the channel that is not a text channel
|
|
1583
1730
|
*/
|
|
1584
|
-
|
|
1585
|
-
|
|
1731
|
+
constructor(message, channelId) {
|
|
1732
|
+
super(message), this.channelId = channelId;
|
|
1733
|
+
this.response.setDescription(`Channel with ID \`${this.channelId}\` is not a text channel.`);
|
|
1586
1734
|
}
|
|
1587
1735
|
};
|
|
1588
1736
|
|
|
1589
|
-
// src/
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
}
|
|
1594
|
-
core;
|
|
1595
|
-
logger = new services.Logger("Effects");
|
|
1596
|
-
isInitialized = false;
|
|
1597
|
-
effectsMap = new discord_js.Collection();
|
|
1598
|
-
emitter = new EffectsEmitter();
|
|
1599
|
-
constructor(core) {
|
|
1600
|
-
super(core), this.core = core;
|
|
1737
|
+
// src/bot/utilities/channels/fetchText.ts
|
|
1738
|
+
async function fetchText(client, channelId) {
|
|
1739
|
+
if (channelId instanceof discord_js.TextChannel) {
|
|
1740
|
+
return channelId;
|
|
1601
1741
|
}
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
frequency: "on"
|
|
1610
|
-
});
|
|
1611
|
-
await this.loadEffects(effectsDir);
|
|
1612
|
-
this.attachEffects();
|
|
1613
|
-
const totalEffects = Array.from(this.effectsMap.values()).reduce((acc, handlers) => acc + handlers.length, 0);
|
|
1614
|
-
this.logger.info(`${chalk3__default.default.bold.green("Loaded")}: ${chalk3__default.default.bold.magenta(totalEffects)} side effects`);
|
|
1742
|
+
let channel = client.channels.cache.get(channelId);
|
|
1743
|
+
if (!channel) {
|
|
1744
|
+
try {
|
|
1745
|
+
channel = await client.channels.fetch(channelId);
|
|
1746
|
+
} catch {
|
|
1747
|
+
throw new CouldNotFindChannel("Channel not found or not a text channel", channelId);
|
|
1748
|
+
}
|
|
1615
1749
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
for (const exportName of Object.keys(imported)) {
|
|
1619
|
-
const val = imported[exportName];
|
|
1620
|
-
if (this.isEffectHandler(val)) {
|
|
1621
|
-
const meta = Reflect.getMetadata(EffectMetadataKey, val);
|
|
1622
|
-
this.registerEffect(val, meta);
|
|
1623
|
-
this.logger.info(`${chalk3__default.default.italic("Registered")} ${chalk3__default.default.bold.yellow(val.name)} from ${chalk3__default.default.gray(relativePath)}`);
|
|
1624
|
-
}
|
|
1625
|
-
}
|
|
1626
|
-
}, this.logger);
|
|
1750
|
+
if (channel?.isTextBased()) {
|
|
1751
|
+
return channel;
|
|
1627
1752
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1753
|
+
throw new CouldNotFindChannel("Channel not found or not a text channel", channelId);
|
|
1754
|
+
}
|
|
1755
|
+
__name(fetchText, "fetchText");
|
|
1756
|
+
|
|
1757
|
+
// src/bot/utilities/channels/sendInText.ts
|
|
1758
|
+
async function sendInText(client, channelId, message) {
|
|
1759
|
+
const channel = await fetchText(client, channelId);
|
|
1760
|
+
return await channel.send(message);
|
|
1761
|
+
}
|
|
1762
|
+
__name(sendInText, "sendInText");
|
|
1763
|
+
function throwCustomError(error, message, CustomError2) {
|
|
1764
|
+
const uuid = crypto.randomUUID();
|
|
1765
|
+
services.Logger.Error("Throwing Custom Error", error.name);
|
|
1766
|
+
if (typeof CustomError2 === typeof DatabaseError) {
|
|
1767
|
+
const errorMessage = error instanceof Error ? error.message : message;
|
|
1768
|
+
throw new CustomError2(errorMessage, uuid);
|
|
1769
|
+
} else {
|
|
1770
|
+
if (error instanceof Error) {
|
|
1771
|
+
throw new CustomError2(`${message}: ${error.message ? error.message : error.toString()}`);
|
|
1772
|
+
} else {
|
|
1773
|
+
throw new CustomError2(message);
|
|
1633
1774
|
}
|
|
1634
|
-
handlers.push({
|
|
1635
|
-
ctor: handler,
|
|
1636
|
-
frequency: options.frequency ?? "on"
|
|
1637
|
-
});
|
|
1638
|
-
}
|
|
1639
|
-
isEffectHandler(obj) {
|
|
1640
|
-
if (typeof obj !== "function") return false;
|
|
1641
|
-
return obj.prototype instanceof EffectsHandler && Reflect.hasMetadata(EffectMetadataKey, obj);
|
|
1642
1775
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1776
|
+
}
|
|
1777
|
+
__name(throwCustomError, "throwCustomError");
|
|
1778
|
+
|
|
1779
|
+
// src/bot/utilities/messages/attemptSendDM.ts
|
|
1780
|
+
async function attemptSendDM(user, content) {
|
|
1781
|
+
const payload = {
|
|
1782
|
+
...content.content !== void 0 && {
|
|
1783
|
+
content: content.content
|
|
1784
|
+
},
|
|
1785
|
+
...content.embeds !== void 0 && {
|
|
1786
|
+
embeds: [
|
|
1787
|
+
...content.embeds
|
|
1788
|
+
]
|
|
1789
|
+
},
|
|
1790
|
+
...content.components !== void 0 && {
|
|
1791
|
+
components: [
|
|
1792
|
+
...content.components
|
|
1793
|
+
]
|
|
1656
1794
|
}
|
|
1795
|
+
};
|
|
1796
|
+
try {
|
|
1797
|
+
return await user.send(payload);
|
|
1798
|
+
} catch {
|
|
1799
|
+
return null;
|
|
1657
1800
|
}
|
|
1658
|
-
|
|
1659
|
-
|
|
1801
|
+
}
|
|
1802
|
+
__name(attemptSendDM, "attemptSendDM");
|
|
1803
|
+
var RoleHigherThanMe = class extends CustomError {
|
|
1804
|
+
static {
|
|
1805
|
+
__name(this, "RoleHigherThanMe");
|
|
1660
1806
|
}
|
|
1661
|
-
|
|
1807
|
+
role;
|
|
1808
|
+
botRole;
|
|
1809
|
+
/**
|
|
1810
|
+
* Creates a new RoleHigherThanMe error.
|
|
1811
|
+
*
|
|
1812
|
+
* @param message - The error message
|
|
1813
|
+
*/
|
|
1814
|
+
constructor(message, role, botRole) {
|
|
1815
|
+
super(message), this.role = role, this.botRole = botRole;
|
|
1816
|
+
this.response.setDescription(`I cannot assign a role that is higher than me.
|
|
1662
1817
|
|
|
1663
|
-
|
|
1664
|
-
|
|
1818
|
+
The role <@&${this.role.id}> is higher than my role <@&${this.botRole.id}> in the hierarchy.`);
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
var CannotAssignBotRole = class extends CustomError {
|
|
1665
1822
|
static {
|
|
1666
|
-
__name(this, "
|
|
1823
|
+
__name(this, "CannotAssignBotRole");
|
|
1667
1824
|
}
|
|
1668
|
-
config;
|
|
1669
|
-
static isInstantiated = false;
|
|
1670
|
-
/** @see {@link CoordinatedShutdown} */
|
|
1671
|
-
shutdown;
|
|
1672
|
-
/** @see {@link CoordinatedStartup} */
|
|
1673
|
-
startup;
|
|
1674
|
-
/** @see {@link EffectsRegistry} */
|
|
1675
|
-
effects;
|
|
1676
|
-
/** @see {@link Bot} */
|
|
1677
|
-
bot;
|
|
1678
|
-
/** @see {@link HealthCheck} */
|
|
1679
|
-
healthCheck;
|
|
1680
1825
|
/**
|
|
1681
|
-
* Creates a new
|
|
1826
|
+
* Creates a new CannotAssignBotRole error.
|
|
1682
1827
|
*
|
|
1683
|
-
* @param
|
|
1684
|
-
* @throws An {@link SeedcordError} When attempting to create multiple instances (singleton)
|
|
1828
|
+
* @param message - The error message
|
|
1685
1829
|
*/
|
|
1686
|
-
constructor(
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
}
|
|
1695
|
-
_Seedcord.isInstantiated = true;
|
|
1696
|
-
this.effects = new EffectsRegistry(this);
|
|
1697
|
-
this.bot = new Bot(this);
|
|
1698
|
-
this.healthCheck = new services.HealthCheck(this.shutdown);
|
|
1699
|
-
this.registerStartupTasks();
|
|
1830
|
+
constructor(message = "I cannot assign a managed role.") {
|
|
1831
|
+
super(message);
|
|
1832
|
+
this.response.setDescription("I cannot assign a managed role.");
|
|
1833
|
+
}
|
|
1834
|
+
};
|
|
1835
|
+
var RoleDoesNotExist = class extends CustomError {
|
|
1836
|
+
static {
|
|
1837
|
+
__name(this, "RoleDoesNotExist");
|
|
1700
1838
|
}
|
|
1839
|
+
roleId;
|
|
1701
1840
|
/**
|
|
1702
|
-
*
|
|
1703
|
-
*
|
|
1841
|
+
* Creates a new RoleDoesNotExist error.
|
|
1842
|
+
*
|
|
1843
|
+
* @param message - The error message
|
|
1844
|
+
* @param roleId - The ID of the role that doesn't exist
|
|
1704
1845
|
*/
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
await this.bot.init();
|
|
1714
|
-
this.bot.logger.info(chalk3__default.default.bold("Initialized"));
|
|
1715
|
-
});
|
|
1716
|
-
this.startup.addTask(services.StartupPhase.Ready, "Health Check", async () => {
|
|
1717
|
-
this.healthCheck.logger.info(chalk3__default.default.bold("Initializing"));
|
|
1718
|
-
await this.healthCheck.init();
|
|
1719
|
-
this.healthCheck.logger.info(chalk3__default.default.bold("Initialized"));
|
|
1720
|
-
});
|
|
1846
|
+
constructor(message, roleId) {
|
|
1847
|
+
super(message), this.roleId = roleId;
|
|
1848
|
+
this.response.setDescription(`The role with ID \`${this.roleId}\` does not exist.`);
|
|
1849
|
+
}
|
|
1850
|
+
};
|
|
1851
|
+
var MissingPermissions = class extends CustomError {
|
|
1852
|
+
static {
|
|
1853
|
+
__name(this, "MissingPermissions");
|
|
1721
1854
|
}
|
|
1855
|
+
where;
|
|
1856
|
+
missingPerms;
|
|
1722
1857
|
/**
|
|
1723
|
-
*
|
|
1858
|
+
* Creates a new MissingPermissions error.
|
|
1724
1859
|
*
|
|
1725
|
-
* @
|
|
1860
|
+
* @param message - The error message
|
|
1861
|
+
* @param missingPerms - Array of missing permission names
|
|
1862
|
+
* @param where - Location or subject where permissions are missing
|
|
1726
1863
|
*/
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1864
|
+
constructor(message, where, missingPerms) {
|
|
1865
|
+
super(message), this.where = where, this.missingPerms = missingPerms;
|
|
1866
|
+
const bullets = this.missingPerms.map((perm) => `\u2022 ${perm}`).join("\n");
|
|
1867
|
+
const mention = this.where instanceof discord_js.Role ? `<@&${this.where.id}>` : this.where instanceof discord_js.TextChannel ? `<#${this.where.id}>` : this.where instanceof discord_js.GuildMember ? `<@${this.where.id}>` : `\`${this.where.name}\``;
|
|
1868
|
+
const label = this.where instanceof discord_js.Role ? "role" : this.where instanceof discord_js.TextChannel ? "channel" : this.where instanceof discord_js.GuildMember ? "member" : "guild";
|
|
1869
|
+
this.response.setDescription(`The ${label} ${mention} is missing the following permission entries:
|
|
1870
|
+
|
|
1871
|
+
${bullets}`);
|
|
1730
1872
|
}
|
|
1731
1873
|
};
|
|
1874
|
+
var HasDangerousPermissions = class extends CustomError {
|
|
1875
|
+
static {
|
|
1876
|
+
__name(this, "HasDangerousPermissions");
|
|
1877
|
+
}
|
|
1878
|
+
target;
|
|
1879
|
+
dangerousPerms;
|
|
1880
|
+
/**
|
|
1881
|
+
* Creates a new HasDangerousPermissions error.
|
|
1882
|
+
*
|
|
1883
|
+
* @param message - The error message
|
|
1884
|
+
* @param target - The subject that has the unwanted permissions
|
|
1885
|
+
* @param dangerousPerms - Array of dangerous permission names
|
|
1886
|
+
*/
|
|
1887
|
+
constructor(message, target, dangerousPerms) {
|
|
1888
|
+
super(message), this.target = target, this.dangerousPerms = dangerousPerms;
|
|
1889
|
+
const bullets = this.dangerousPerms.map((perm) => `\u2022 ${perm}`).join("\n");
|
|
1890
|
+
const mention = this.target instanceof discord_js.Role ? `<@&${this.target.id}>` : this.target instanceof discord_js.TextChannel ? `<#${this.target.id}>` : this.target instanceof discord_js.GuildMember ? `<@${this.target.id}>` : `\`${this.target.name}\``;
|
|
1891
|
+
const label = this.target instanceof discord_js.Role ? "role" : this.target instanceof discord_js.TextChannel ? "channel" : this.target instanceof discord_js.GuildMember ? "member" : "guild";
|
|
1892
|
+
this.response.setDescription(`The ${label} ${mention} has the following permission entries that must not be enabled:
|
|
1732
1893
|
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1894
|
+
${bullets}`);
|
|
1895
|
+
}
|
|
1896
|
+
};
|
|
1897
|
+
var PermissionNames = new Map(Object.entries(discord_js.PermissionFlagsBits).map(([key, bit]) => [
|
|
1898
|
+
bit,
|
|
1899
|
+
utils.prettify(key)
|
|
1900
|
+
]));
|
|
1901
|
+
function checkPermissions(a, b, c, d, e) {
|
|
1902
|
+
const opts = a instanceof discord_js.Role || a instanceof discord_js.GuildMember ? {
|
|
1903
|
+
for: a,
|
|
1904
|
+
in: b,
|
|
1905
|
+
scope: c,
|
|
1906
|
+
inverse: d ?? false,
|
|
1907
|
+
...e ?? {}
|
|
1908
|
+
} : a;
|
|
1909
|
+
const { for: pFor, in: pIn, scope, inverse = false, missing: missingCtor, dangerous: dangerousCtor } = opts;
|
|
1910
|
+
const Missing = missingCtor ?? MissingPermissions;
|
|
1911
|
+
const Dangerous = dangerousCtor ?? HasDangerousPermissions;
|
|
1912
|
+
const perms = pIn instanceof discord_js.Guild ? pFor.permissions : pIn.permissionsFor(pFor, true);
|
|
1913
|
+
const names = /* @__PURE__ */ __name((bits) => bits.map((bit) => PermissionNames.get(bit) ?? String(bit)), "names");
|
|
1914
|
+
const present = scope.filter((bit) => perms.has(bit, true));
|
|
1915
|
+
const presentNames = names(present);
|
|
1916
|
+
if (inverse) {
|
|
1917
|
+
if (present.length > 0) {
|
|
1918
|
+
const base = `${pFor instanceof discord_js.Role ? "Role" : "Member"} has dangerous permissions in this ${pIn instanceof discord_js.Guild ? "guild" : "channel"}`;
|
|
1919
|
+
throw new Dangerous(base, pFor, presentNames);
|
|
1920
|
+
}
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const missingBits = scope.filter((bit) => !perms.has(bit, true));
|
|
1924
|
+
if (missingBits.length > 0) {
|
|
1925
|
+
throw new Missing("Missing Any/All/No Permissions", pIn, names(missingBits));
|
|
1926
|
+
}
|
|
1739
1927
|
}
|
|
1740
|
-
__name(
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
if (!msg) return;
|
|
1764
|
-
await msg.reply({
|
|
1765
|
-
embeds: [
|
|
1766
|
-
response
|
|
1767
|
-
],
|
|
1768
|
-
components: []
|
|
1769
|
-
});
|
|
1770
|
-
}
|
|
1771
|
-
};
|
|
1772
|
-
};
|
|
1928
|
+
__name(checkPermissions, "checkPermissions");
|
|
1929
|
+
var ensurePermissions = checkPermissions;
|
|
1930
|
+
|
|
1931
|
+
// src/bot/utilities/permissions/checkBotPermissions.ts
|
|
1932
|
+
function checkBotPermissions(target, scope, inverse = false, errors) {
|
|
1933
|
+
if (target instanceof discord_js.Guild) {
|
|
1934
|
+
const me2 = target.members.me;
|
|
1935
|
+
if (!me2) {
|
|
1936
|
+
const names = scope.map((bit) => PermissionNames.get(bit) ?? String(bit));
|
|
1937
|
+
const Missing = errors?.missing ?? MissingPermissions;
|
|
1938
|
+
throw new Missing("Missing Permissions", target, names);
|
|
1939
|
+
}
|
|
1940
|
+
checkPermissions(me2, target, scope, inverse, errors);
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
const me = target.guild.members.me;
|
|
1944
|
+
if (!me) {
|
|
1945
|
+
const names = scope.map((bit) => PermissionNames.get(bit) ?? String(bit));
|
|
1946
|
+
const Missing = errors?.missing ?? MissingPermissions;
|
|
1947
|
+
services.Logger.Warn("checkBotPermissions", `Bot member is unavailable in guild ${target.guild.id} while checking permissions in channel ${target.id}`);
|
|
1948
|
+
throw new Missing("Missing Permissions", target, names);
|
|
1949
|
+
}
|
|
1950
|
+
checkPermissions(me, target, scope, inverse, errors);
|
|
1773
1951
|
}
|
|
1774
|
-
__name(
|
|
1775
|
-
var
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
const container = await resolveFactory(opts.container, ctx);
|
|
1783
|
-
return {
|
|
1784
|
-
flags: "IsComponentsV2",
|
|
1785
|
-
components: [
|
|
1786
|
-
container.component
|
|
1787
|
-
]
|
|
1788
|
-
};
|
|
1952
|
+
__name(checkBotPermissions, "checkBotPermissions");
|
|
1953
|
+
var ensureBotPermissions = checkBotPermissions;
|
|
1954
|
+
function getBotRole(guild) {
|
|
1955
|
+
const botRole = guild.roles.botRoleFor(guild.client.user);
|
|
1956
|
+
if (!botRole) {
|
|
1957
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.CoreBotRoleMissing, [
|
|
1958
|
+
guild.id
|
|
1959
|
+
]);
|
|
1789
1960
|
}
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
components: []
|
|
1807
|
-
} : {
|
|
1808
|
-
components: []
|
|
1809
|
-
}, "clearedPayload");
|
|
1810
|
-
var decide = /* @__PURE__ */ __name(async (opts, i) => {
|
|
1811
|
-
if (usesResolver(opts)) return opts.resolveDecision(i);
|
|
1812
|
-
if (usesCustomIds(opts)) {
|
|
1813
|
-
const { confirmCustomIds, cancelCustomIds = [] } = opts;
|
|
1814
|
-
if (confirmCustomIds.includes(i.customId)) return true;
|
|
1815
|
-
if (cancelCustomIds.includes(i.customId)) return false;
|
|
1961
|
+
return botRole;
|
|
1962
|
+
}
|
|
1963
|
+
__name(getBotRole, "getBotRole");
|
|
1964
|
+
|
|
1965
|
+
// src/bot/utilities/permissions/hasPermsToAssign.ts
|
|
1966
|
+
function hasPermsToAssign(roleOrOptions) {
|
|
1967
|
+
const { targetRole, errors } = roleOrOptions instanceof discord_js.Role ? {
|
|
1968
|
+
targetRole: roleOrOptions,
|
|
1969
|
+
errors: void 0
|
|
1970
|
+
} : roleOrOptions;
|
|
1971
|
+
const HigherErr = errors?.higher ?? RoleHigherThanMe;
|
|
1972
|
+
const ManagedErr = errors?.managed ?? CannotAssignBotRole;
|
|
1973
|
+
const Missing = errors?.missing ?? MissingPermissions;
|
|
1974
|
+
const botRole = getBotRole(targetRole.guild);
|
|
1975
|
+
if (targetRole.comparePositionTo(botRole) >= 0) {
|
|
1976
|
+
throw new HigherErr("Role is higher than me", targetRole, botRole);
|
|
1816
1977
|
}
|
|
1817
|
-
|
|
1818
|
-
}
|
|
1819
|
-
var shouldDefer = /* @__PURE__ */ __name((ix, opts, isSlash, isContext) => {
|
|
1820
|
-
if (ix.deferred) return false;
|
|
1821
|
-
if (opts.defer === false) return false;
|
|
1822
|
-
return isSlash || isContext;
|
|
1823
|
-
}, "shouldDefer");
|
|
1824
|
-
var maybeDefer = /* @__PURE__ */ __name(async (ix, opts, isSlash, isContext) => {
|
|
1825
|
-
if (!shouldDefer(ix, opts, isSlash, isContext)) return;
|
|
1826
|
-
if (isSlash || isContext) {
|
|
1827
|
-
const { ephemeral = true } = opts;
|
|
1828
|
-
const flags = ephemeral ? {
|
|
1829
|
-
flags: "Ephemeral"
|
|
1830
|
-
} : void 0;
|
|
1831
|
-
if (flags) await ix.deferReply(flags);
|
|
1832
|
-
else await ix.deferReply();
|
|
1833
|
-
} else if (isMessageComponentIx(ix)) {
|
|
1834
|
-
await ix.deferUpdate();
|
|
1835
|
-
} else {
|
|
1836
|
-
await ix.deferReply().catch(() => void 0);
|
|
1978
|
+
if (targetRole.managed) {
|
|
1979
|
+
throw new ManagedErr(`Cannot assign managed role ${targetRole.name}`);
|
|
1837
1980
|
}
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
return ix.fetchReply();
|
|
1981
|
+
checkBotPermissions(targetRole.guild, [
|
|
1982
|
+
discord_js.PermissionFlagsBits.ManageRoles
|
|
1983
|
+
], false, {
|
|
1984
|
+
missing: Missing
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1987
|
+
__name(hasPermsToAssign, "hasPermsToAssign");
|
|
1988
|
+
async function fetchRole(clientOrGuild, roleId) {
|
|
1989
|
+
let role;
|
|
1990
|
+
if (!roleId) {
|
|
1991
|
+
throw new RoleDoesNotExist("Role ID is null or undefined", roleId);
|
|
1850
1992
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1993
|
+
if (clientOrGuild instanceof discord_js.Guild) {
|
|
1994
|
+
const guild = clientOrGuild;
|
|
1995
|
+
role = guild.roles.cache.get(roleId);
|
|
1996
|
+
if (!role) {
|
|
1997
|
+
try {
|
|
1998
|
+
role = await guild.roles.fetch(roleId);
|
|
1999
|
+
} catch {
|
|
2000
|
+
throw new RoleDoesNotExist("Role not found in specified guild", roleId);
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
} else {
|
|
2004
|
+
const client = clientOrGuild;
|
|
2005
|
+
role = client.guilds.cache.map((guild) => guild.roles.cache.get(roleId)).find((role2) => role2);
|
|
2006
|
+
if (!role) {
|
|
2007
|
+
const guilds = client.guilds.cache;
|
|
2008
|
+
for (const guild of guilds.values()) {
|
|
2009
|
+
try {
|
|
2010
|
+
role = await guild.roles.fetch(roleId);
|
|
2011
|
+
if (role) break;
|
|
2012
|
+
} catch {
|
|
2013
|
+
continue;
|
|
1871
2014
|
}
|
|
1872
|
-
|
|
1873
|
-
}, "filter")
|
|
1874
|
-
});
|
|
1875
|
-
return {
|
|
1876
|
-
button,
|
|
1877
|
-
timedOut: false
|
|
1878
|
-
};
|
|
1879
|
-
} catch {
|
|
1880
|
-
return {
|
|
1881
|
-
button: null,
|
|
1882
|
-
timedOut: true
|
|
1883
|
-
};
|
|
1884
|
-
}
|
|
1885
|
-
}, "awaitComponent");
|
|
1886
|
-
var clearUi = /* @__PURE__ */ __name(async (ix, msg, opts, isSlash) => {
|
|
1887
|
-
if (!isSlash) {
|
|
1888
|
-
try {
|
|
1889
|
-
await msg.edit(clearedPayload(opts));
|
|
1890
|
-
} catch {
|
|
1891
|
-
await ix.deleteReply(msg).catch(() => void 0);
|
|
2015
|
+
}
|
|
1892
2016
|
}
|
|
1893
|
-
return;
|
|
1894
|
-
}
|
|
1895
|
-
await ix.editReply(clearedPayload(opts)).catch(() => void 0);
|
|
1896
|
-
}, "clearUi");
|
|
1897
|
-
var normalizeClassicOutcome = /* @__PURE__ */ __name((payload) => ({
|
|
1898
|
-
...payload,
|
|
1899
|
-
components: payload.components ?? []
|
|
1900
|
-
}), "normalizeClassicOutcome");
|
|
1901
|
-
var outcomeReplacement = /* @__PURE__ */ __name(async (opts, ctx, confirmed, timedOut) => {
|
|
1902
|
-
const outcomes = opts.outcomeUi;
|
|
1903
|
-
if (isV2(opts)) {
|
|
1904
|
-
const v2Outcomes = outcomes;
|
|
1905
|
-
if (timedOut) return await resolveFactory(v2Outcomes.onTimeout, ctx);
|
|
1906
|
-
if (!confirmed) return await resolveFactory(v2Outcomes.onCancel, ctx);
|
|
1907
|
-
if (v2Outcomes.onConfirm) return await resolveFactory(v2Outcomes.onConfirm, ctx);
|
|
1908
|
-
return null;
|
|
1909
2017
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
if (!confirmed) return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onCancel, ctx));
|
|
1913
|
-
if (classicOutcomes.onConfirm) {
|
|
1914
|
-
return normalizeClassicOutcome(await resolveFactory(classicOutcomes.onConfirm, ctx));
|
|
2018
|
+
if (!role) {
|
|
2019
|
+
throw new RoleDoesNotExist("Role not found", roleId);
|
|
1915
2020
|
}
|
|
1916
|
-
return
|
|
1917
|
-
}, "outcomeReplacement");
|
|
1918
|
-
function Confirmable(question, options) {
|
|
1919
|
-
return function(_target, _propertyKey, descriptor) {
|
|
1920
|
-
const original = descriptor.value;
|
|
1921
|
-
descriptor.value = async function(...args) {
|
|
1922
|
-
if (!original) throw new services.SeedcordError(services.SeedcordErrorCode.DecoratorMethodNotFound);
|
|
1923
|
-
const ix = this.getEvent();
|
|
1924
|
-
const isSlash = ix.isChatInputCommand();
|
|
1925
|
-
const isContext = ix.isContextMenuCommand();
|
|
1926
|
-
const { ephemeral = true } = options;
|
|
1927
|
-
await maybeDefer(ix, options, isSlash, isContext);
|
|
1928
|
-
const q = typeof question === "function" ? await question.apply(this) : question;
|
|
1929
|
-
const ctx = {
|
|
1930
|
-
handler: this,
|
|
1931
|
-
interaction: ix,
|
|
1932
|
-
question: q
|
|
1933
|
-
};
|
|
1934
|
-
const prompt = await buildPrompt(options, ctx);
|
|
1935
|
-
const promptMsg = await sendPrompt(ix, prompt, ephemeral, isSlash, isContext);
|
|
1936
|
-
const { button, timedOut } = await awaitComponent(promptMsg, ix, options);
|
|
1937
|
-
let confirmed = false;
|
|
1938
|
-
if (button) {
|
|
1939
|
-
await button.deferUpdate().catch(() => void 0);
|
|
1940
|
-
confirmed = await decide(options, button);
|
|
1941
|
-
}
|
|
1942
|
-
const replacement = await outcomeReplacement(options, ctx, confirmed, timedOut);
|
|
1943
|
-
if (replacement) {
|
|
1944
|
-
if (isSlash || isContext) {
|
|
1945
|
-
await ix.editReply(replacement).catch(() => void 0);
|
|
1946
|
-
} else {
|
|
1947
|
-
await promptMsg.edit(replacement).catch(async () => {
|
|
1948
|
-
await ix.deleteReply(promptMsg).catch(() => void 0);
|
|
1949
|
-
await ix.followUp(replacement).catch(() => void 0);
|
|
1950
|
-
});
|
|
1951
|
-
}
|
|
1952
|
-
} else {
|
|
1953
|
-
await clearUi(ix, promptMsg, options, isSlash);
|
|
1954
|
-
}
|
|
1955
|
-
if (options.onResolved) {
|
|
1956
|
-
await options.onResolved({
|
|
1957
|
-
confirmed,
|
|
1958
|
-
timedOut,
|
|
1959
|
-
handler: this,
|
|
1960
|
-
interaction: ix,
|
|
1961
|
-
question: q,
|
|
1962
|
-
...button ? {
|
|
1963
|
-
button
|
|
1964
|
-
} : {}
|
|
1965
|
-
});
|
|
1966
|
-
}
|
|
1967
|
-
if (confirmed) {
|
|
1968
|
-
await original.apply(this, args);
|
|
1969
|
-
}
|
|
1970
|
-
};
|
|
1971
|
-
return descriptor;
|
|
1972
|
-
};
|
|
2021
|
+
return role;
|
|
1973
2022
|
}
|
|
1974
|
-
__name(
|
|
2023
|
+
__name(fetchRole, "fetchRole");
|
|
1975
2024
|
|
|
1976
|
-
// src/bot/errors/
|
|
1977
|
-
var
|
|
2025
|
+
// src/bot/defaults/errors/User.ts
|
|
2026
|
+
var UserNotInGuild = class extends CustomError {
|
|
1978
2027
|
static {
|
|
1979
|
-
__name(this, "
|
|
2028
|
+
__name(this, "UserNotInGuild");
|
|
1980
2029
|
}
|
|
1981
|
-
channelId;
|
|
1982
2030
|
/**
|
|
1983
|
-
* Creates a new
|
|
2031
|
+
* Creates a new UserNotInGuild error.
|
|
1984
2032
|
*
|
|
1985
2033
|
* @param message - The error message
|
|
1986
|
-
* @param channelId - The ID of the channel that could not be found
|
|
1987
2034
|
*/
|
|
1988
|
-
constructor(message
|
|
1989
|
-
super(message)
|
|
1990
|
-
this.response.setDescription(
|
|
2035
|
+
constructor(message = "User is not in the guild.") {
|
|
2036
|
+
super(message);
|
|
2037
|
+
this.response.setDescription("User is not in the guild.");
|
|
1991
2038
|
}
|
|
1992
2039
|
};
|
|
1993
|
-
var
|
|
2040
|
+
var UserNotFound = class extends CustomError {
|
|
1994
2041
|
static {
|
|
1995
|
-
__name(this, "
|
|
2042
|
+
__name(this, "UserNotFound");
|
|
1996
2043
|
}
|
|
1997
|
-
|
|
2044
|
+
userArg;
|
|
1998
2045
|
/**
|
|
1999
|
-
* Creates a new
|
|
2046
|
+
* Creates a new UserNotFound error.
|
|
2000
2047
|
*
|
|
2001
|
-
* @param
|
|
2002
|
-
* @param channelId - The ID of the channel where embeds cannot be sent
|
|
2048
|
+
* @param userArg - The user argument that could not be resolved
|
|
2003
2049
|
*/
|
|
2004
|
-
constructor(
|
|
2005
|
-
super(
|
|
2006
|
-
this.response.setDescription(`
|
|
2007
|
-
|
|
2008
|
-
Please
|
|
2009
|
-
\u2022 View Channel
|
|
2010
|
-
\u2022 Send Messages
|
|
2011
|
-
\u2022 Embed Links
|
|
2012
|
-
\u2022 Attach Files
|
|
2013
|
-
\u2022 Read Message History
|
|
2014
|
-
\u2022 Use External Emojis
|
|
2015
|
-
`);
|
|
2050
|
+
constructor(userArg) {
|
|
2051
|
+
super(`User not found: ${userArg}`), this.userArg = userArg;
|
|
2052
|
+
this.response.setTitle("User Not Found").setDescription(`User probably doesn't exist or was deleted.
|
|
2053
|
+
**User Argument:** \`${this.userArg}\`
|
|
2054
|
+
Please check the user ID and try again. Only pass valid user IDs as the argument.`);
|
|
2016
2055
|
}
|
|
2017
2056
|
};
|
|
2018
|
-
|
|
2057
|
+
|
|
2058
|
+
// src/bot/utilities/users/fetchGuildMember.ts
|
|
2059
|
+
async function fetchGuildMember(guild, userId) {
|
|
2060
|
+
let user = guild.members.cache.get(userId);
|
|
2061
|
+
user ??= await guild.members.fetch(userId).catch(() => {
|
|
2062
|
+
throw new UserNotInGuild(`User with ID ${userId} not found in guild`);
|
|
2063
|
+
});
|
|
2064
|
+
return user;
|
|
2065
|
+
}
|
|
2066
|
+
__name(fetchGuildMember, "fetchGuildMember");
|
|
2067
|
+
|
|
2068
|
+
// src/bot/utilities/users/fetchManyGuildMembers.ts
|
|
2069
|
+
async function fetchManyGuildMembers(guild, userIds) {
|
|
2070
|
+
const results = await Promise.allSettled(userIds.map((userId) => fetchGuildMember(guild, userId)));
|
|
2071
|
+
return results.filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
2072
|
+
}
|
|
2073
|
+
__name(fetchManyGuildMembers, "fetchManyGuildMembers");
|
|
2074
|
+
async function fetchUser(client, userId) {
|
|
2075
|
+
let user = client.users.cache.get(userId);
|
|
2076
|
+
user ??= await client.users.fetch(userId).catch((err) => {
|
|
2077
|
+
if (err instanceof discord_js.DiscordAPIError && err.code === discord_js.RESTJSONErrorCodes.UnknownUser) {
|
|
2078
|
+
throw new UserNotFound(userId);
|
|
2079
|
+
}
|
|
2080
|
+
throw err;
|
|
2081
|
+
});
|
|
2082
|
+
return user;
|
|
2083
|
+
}
|
|
2084
|
+
__name(fetchUser, "fetchUser");
|
|
2085
|
+
|
|
2086
|
+
// src/bot/utilities/users/fetchManyUsers.ts
|
|
2087
|
+
async function fetchManyUsers(client, userIds) {
|
|
2088
|
+
const results = await Promise.allSettled(userIds.map((userId) => fetchUser(client, userId)));
|
|
2089
|
+
return results.filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
2090
|
+
}
|
|
2091
|
+
__name(fetchManyUsers, "fetchManyUsers");
|
|
2092
|
+
|
|
2093
|
+
// src/bot/utilities/users/updateMemberRoles.ts
|
|
2094
|
+
async function updateMemberRoles(rolesToAdd, rolesToRemove, member) {
|
|
2095
|
+
const current = new Set(member.roles.cache.map((r) => r.id));
|
|
2096
|
+
const toAdd = new Set(rolesToAdd);
|
|
2097
|
+
const toRemove = new Set(rolesToRemove);
|
|
2098
|
+
const updated = current.union(toAdd).difference(toRemove);
|
|
2099
|
+
await member.roles.set([
|
|
2100
|
+
...updated
|
|
2101
|
+
]);
|
|
2102
|
+
}
|
|
2103
|
+
__name(updateMemberRoles, "updateMemberRoles");
|
|
2104
|
+
var EffectsEmitter = class {
|
|
2019
2105
|
static {
|
|
2020
|
-
__name(this, "
|
|
2106
|
+
__name(this, "EffectsEmitter");
|
|
2021
2107
|
}
|
|
2022
|
-
|
|
2108
|
+
emitter = new events.EventEmitter();
|
|
2023
2109
|
/**
|
|
2024
|
-
*
|
|
2110
|
+
* Registers a listener for the specified side effect.
|
|
2025
2111
|
*
|
|
2026
|
-
* @
|
|
2027
|
-
* @param
|
|
2112
|
+
* @typeParam KeyOfEffects - The side effect name type
|
|
2113
|
+
* @param event - The side effect name to listen for
|
|
2114
|
+
* @param listener - Function to call when the event is emitted
|
|
2115
|
+
* @returns This EffectsEmitter instance for chaining
|
|
2028
2116
|
*/
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
}
|
|
2033
|
-
};
|
|
2034
|
-
var ChannelNotTextChannel = class extends CustomError {
|
|
2035
|
-
static {
|
|
2036
|
-
__name(this, "ChannelNotTextChannel");
|
|
2117
|
+
on(event, listener) {
|
|
2118
|
+
this.emitter.on(event, listener);
|
|
2119
|
+
return this;
|
|
2037
2120
|
}
|
|
2038
|
-
channelId;
|
|
2039
2121
|
/**
|
|
2040
|
-
*
|
|
2122
|
+
* Registers a one-time listener for the specified side effect.
|
|
2041
2123
|
*
|
|
2042
|
-
* @
|
|
2043
|
-
* @param
|
|
2124
|
+
* @typeParam KeyOfEffects - The side effect name type
|
|
2125
|
+
* @param event - The side effect name to listen for once
|
|
2126
|
+
* @param listener - Function to call when the event is emitted
|
|
2127
|
+
* @returns This EffectsEmitter instance for chaining
|
|
2044
2128
|
*/
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
}
|
|
2049
|
-
};
|
|
2050
|
-
var MissingPermissions = class extends CustomError {
|
|
2051
|
-
static {
|
|
2052
|
-
__name(this, "MissingPermissions");
|
|
2129
|
+
once(event, listener) {
|
|
2130
|
+
this.emitter.once(event, listener);
|
|
2131
|
+
return this;
|
|
2053
2132
|
}
|
|
2054
|
-
missingPerms;
|
|
2055
|
-
roleOrChannel;
|
|
2056
2133
|
/**
|
|
2057
|
-
*
|
|
2134
|
+
* Emits a side effect with the provided data.
|
|
2058
2135
|
*
|
|
2059
|
-
* @
|
|
2060
|
-
* @param
|
|
2061
|
-
* @param
|
|
2136
|
+
* @typeParam KeyOfEffects - The side effect name type
|
|
2137
|
+
* @param event - The side effect name to emit
|
|
2138
|
+
* @param data - The data to pass to registered listeners
|
|
2139
|
+
* @returns True if the event had listeners, false otherwise
|
|
2062
2140
|
*/
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
const missing = this.missingPerms.map((perm) => `\u2022 ${perm}`).join("\n");
|
|
2066
|
-
const errorSubtext = this.roleOrChannel instanceof discord_js.Role ? `My role, <@&${this.roleOrChannel.id}>, is missing the following permissions:` : `I am missing the following permissions in <#${this.roleOrChannel.id}>:`;
|
|
2067
|
-
this.response.setDescription(`${errorSubtext}
|
|
2068
|
-
|
|
2069
|
-
Please ensure I have the following missing permission(s):
|
|
2070
|
-
${missing}`);
|
|
2141
|
+
emit(event, data) {
|
|
2142
|
+
return this.emitter.emit(event, data);
|
|
2071
2143
|
}
|
|
2072
2144
|
};
|
|
2073
|
-
var RoleHigherThanMe = class extends CustomError {
|
|
2074
|
-
static {
|
|
2075
|
-
__name(this, "RoleHigherThanMe");
|
|
2076
|
-
}
|
|
2077
|
-
role;
|
|
2078
|
-
botRole;
|
|
2079
|
-
/**
|
|
2080
|
-
* Creates a new RoleHigherThanMe error.
|
|
2081
|
-
*
|
|
2082
|
-
* @param message - The error message
|
|
2083
|
-
*/
|
|
2084
|
-
constructor(message, role, botRole) {
|
|
2085
|
-
super(message), this.role = role, this.botRole = botRole;
|
|
2086
|
-
this.response.setDescription(`I cannot assign a role that is higher than me.
|
|
2087
2145
|
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
};
|
|
2091
|
-
var CannotAssignBotRole = class extends CustomError {
|
|
2146
|
+
// src/effects/EffectsHandler.ts
|
|
2147
|
+
var EffectsHandler = class {
|
|
2092
2148
|
static {
|
|
2093
|
-
__name(this, "
|
|
2149
|
+
__name(this, "EffectsHandler");
|
|
2094
2150
|
}
|
|
2151
|
+
data;
|
|
2152
|
+
core;
|
|
2095
2153
|
/**
|
|
2096
|
-
* Creates a new
|
|
2154
|
+
* Creates a new effects handler instance.
|
|
2097
2155
|
*
|
|
2098
|
-
* @param
|
|
2156
|
+
* @param data - The effect event data
|
|
2157
|
+
* @param core - The core framework instance
|
|
2099
2158
|
*/
|
|
2100
|
-
constructor(
|
|
2101
|
-
|
|
2102
|
-
this.
|
|
2159
|
+
constructor(data, core) {
|
|
2160
|
+
this.data = data;
|
|
2161
|
+
this.core = core;
|
|
2162
|
+
this.data = data;
|
|
2163
|
+
this.core = core;
|
|
2103
2164
|
}
|
|
2104
2165
|
};
|
|
2105
|
-
|
|
2166
|
+
|
|
2167
|
+
// src/effects/decorators/RegisterEffect.ts
|
|
2168
|
+
var EffectMetadataKey = Symbol("effect:metadata");
|
|
2169
|
+
function RegisterEffect(effect, options) {
|
|
2170
|
+
return function(constructor) {
|
|
2171
|
+
const meta = {
|
|
2172
|
+
effect,
|
|
2173
|
+
frequency: options?.frequency
|
|
2174
|
+
};
|
|
2175
|
+
Reflect.defineMetadata(EffectMetadataKey, meta, constructor);
|
|
2176
|
+
};
|
|
2177
|
+
}
|
|
2178
|
+
__name(RegisterEffect, "RegisterEffect");
|
|
2179
|
+
|
|
2180
|
+
// src/effects/bases/WebhookLog.ts
|
|
2181
|
+
var WebhookLog = class extends EffectsHandler {
|
|
2106
2182
|
static {
|
|
2107
|
-
__name(this, "
|
|
2183
|
+
__name(this, "WebhookLog");
|
|
2108
2184
|
}
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
* Creates a new RoleDoesNotExist error.
|
|
2112
|
-
*
|
|
2113
|
-
* @param message - The error message
|
|
2114
|
-
* @param roleId - The ID of the role that doesn't exist
|
|
2115
|
-
*/
|
|
2116
|
-
constructor(message, roleId) {
|
|
2117
|
-
super(message), this.roleId = roleId;
|
|
2118
|
-
this.response.setDescription(`The role with ID \`${this.roleId}\` does not exist.`);
|
|
2185
|
+
constructor(data, core) {
|
|
2186
|
+
super(data, core);
|
|
2119
2187
|
}
|
|
2120
2188
|
};
|
|
2121
|
-
var HasDangerousPermissions = class extends CustomError {
|
|
2122
|
-
static {
|
|
2123
|
-
__name(this, "HasDangerousPermissions");
|
|
2124
|
-
}
|
|
2125
|
-
role;
|
|
2126
|
-
dangerousPerms;
|
|
2127
|
-
/**
|
|
2128
|
-
* Creates a new HasDangerousPermissions error.
|
|
2129
|
-
*
|
|
2130
|
-
* @param message - The error message
|
|
2131
|
-
* @param role - The role with dangerous permissions
|
|
2132
|
-
* @param dangerousPerms - Array of dangerous permission names
|
|
2133
|
-
*/
|
|
2134
|
-
constructor(message, role, dangerousPerms) {
|
|
2135
|
-
super(message), this.role = role, this.dangerousPerms = dangerousPerms;
|
|
2136
|
-
const dangerous = this.dangerousPerms.map((perm) => `\u2022 ${perm}`).join("\n");
|
|
2137
|
-
this.response.setDescription(`The role <@&${this.role.id}> has the following dangerous permissions:
|
|
2138
2189
|
|
|
2139
|
-
|
|
2140
|
-
|
|
2190
|
+
// src/effects/default/UnknownException.ts
|
|
2191
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
2192
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2193
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2194
|
+
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;
|
|
2195
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2196
|
+
}
|
|
2197
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
2198
|
+
function _ts_metadata5(k, v) {
|
|
2199
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2200
|
+
}
|
|
2201
|
+
__name(_ts_metadata5, "_ts_metadata");
|
|
2202
|
+
function webhookUrlValidator(raw, _fallback) {
|
|
2203
|
+
if (raw === null) {
|
|
2204
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.ConfigUnknownExceptionWebhookMissing);
|
|
2141
2205
|
}
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
// src/bot/errors/User.ts
|
|
2145
|
-
var UserNotInGuild = class extends CustomError {
|
|
2146
|
-
static {
|
|
2147
|
-
__name(this, "UserNotInGuild");
|
|
2206
|
+
if (typeof raw !== "string") {
|
|
2207
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.ConfigUnknownExceptionWebhookInvalid);
|
|
2148
2208
|
}
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
* @param message - The error message
|
|
2153
|
-
*/
|
|
2154
|
-
constructor(message = "User is not in the guild.") {
|
|
2155
|
-
super(message);
|
|
2156
|
-
this.response.setDescription("User is not in the guild.");
|
|
2209
|
+
const value = raw.trim();
|
|
2210
|
+
if (value === "") {
|
|
2211
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.ConfigUnknownExceptionWebhookMissing);
|
|
2157
2212
|
}
|
|
2158
|
-
|
|
2159
|
-
|
|
2213
|
+
const pattern = String.raw`^https?:\/\/(?:canary\.|ptb\.)?discord(?:app)?\.com\/api\/webhooks\/\d+\/[\w$-]+$`;
|
|
2214
|
+
const discordWebhookRegex = new RegExp(pattern);
|
|
2215
|
+
if (!URL.canParse(value) || !discordWebhookRegex.test(value)) {
|
|
2216
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.ConfigUnknownExceptionWebhookInvalid);
|
|
2217
|
+
}
|
|
2218
|
+
return value;
|
|
2219
|
+
}
|
|
2220
|
+
__name(webhookUrlValidator, "webhookUrlValidator");
|
|
2221
|
+
exports.UnknownException = class _UnknownException extends WebhookLog {
|
|
2160
2222
|
static {
|
|
2161
|
-
__name(this, "
|
|
2223
|
+
__name(this, "UnknownException");
|
|
2162
2224
|
}
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
constructor(userArg) {
|
|
2170
|
-
super(`User not found: ${userArg}`), this.userArg = userArg;
|
|
2171
|
-
this.response.setTitle("User Not Found").setDescription(`User probably doesn't exist or was deleted.
|
|
2172
|
-
**User Argument:** \`${this.userArg}\`
|
|
2173
|
-
Please check the user ID and try again. Only pass valid user IDs as the argument.`);
|
|
2174
|
-
}
|
|
2175
|
-
};
|
|
2176
|
-
async function fetchText(client, channelId) {
|
|
2177
|
-
if (channelId instanceof discord_js.TextChannel) {
|
|
2178
|
-
return channelId;
|
|
2179
|
-
}
|
|
2180
|
-
let channel = client.channels.cache.get(channelId);
|
|
2181
|
-
if (!channel) {
|
|
2225
|
+
static logger = new services.Logger("Effect: UnknownException");
|
|
2226
|
+
webhook = new discord_js.WebhookClient({
|
|
2227
|
+
url: _UnknownException.unknownExceptionWebhookUrl
|
|
2228
|
+
});
|
|
2229
|
+
async execute() {
|
|
2230
|
+
const metadataFile = this.prepareMetadataFile();
|
|
2182
2231
|
try {
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
const channel = await fetchText(client, channelId);
|
|
2198
|
-
return await channel.send(message);
|
|
2199
|
-
}
|
|
2200
|
-
__name(sendInText, "sendInText");
|
|
2201
|
-
function throwCustomError(error, message, CustomError2) {
|
|
2202
|
-
const uuid = crypto.randomUUID();
|
|
2203
|
-
services.Logger.Error("Throwing Custom Error", error.name);
|
|
2204
|
-
if (typeof CustomError2 === typeof DatabaseError) {
|
|
2205
|
-
const errorMessage = error instanceof Error ? error.message : message;
|
|
2206
|
-
throw new CustomError2(errorMessage, uuid);
|
|
2207
|
-
} else {
|
|
2208
|
-
if (error instanceof Error) {
|
|
2209
|
-
throw new CustomError2(`${message}: ${error.message ? error.message : error.toString()}`);
|
|
2210
|
-
} else {
|
|
2211
|
-
throw new CustomError2(message);
|
|
2232
|
+
await this.webhook.send({
|
|
2233
|
+
flags: "IsComponentsV2",
|
|
2234
|
+
withComponents: true,
|
|
2235
|
+
username: "Unknown Exception",
|
|
2236
|
+
avatarURL: "https://cdn.discordapp.com/attachments/1351446034827579466/1351446912947191830/warning-2.png",
|
|
2237
|
+
components: [
|
|
2238
|
+
new UnhandledErrorContainer(this.data).component
|
|
2239
|
+
],
|
|
2240
|
+
files: metadataFile ? [
|
|
2241
|
+
metadataFile
|
|
2242
|
+
] : []
|
|
2243
|
+
});
|
|
2244
|
+
} catch (error) {
|
|
2245
|
+
_UnknownException.logger.error("Failed to send unknown exception webhook", error);
|
|
2212
2246
|
}
|
|
2213
2247
|
}
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
},
|
|
2223
|
-
...content.embeds !== void 0 && {
|
|
2224
|
-
embeds: [
|
|
2225
|
-
...content.embeds
|
|
2226
|
-
]
|
|
2227
|
-
},
|
|
2228
|
-
...content.components !== void 0 && {
|
|
2229
|
-
components: [
|
|
2230
|
-
...content.components
|
|
2231
|
-
]
|
|
2232
|
-
}
|
|
2233
|
-
};
|
|
2234
|
-
try {
|
|
2235
|
-
return await user.send(payload);
|
|
2236
|
-
} catch {
|
|
2237
|
-
return null;
|
|
2248
|
+
prepareMetadataFile() {
|
|
2249
|
+
const { metadata } = this.data;
|
|
2250
|
+
if (!metadata) return null;
|
|
2251
|
+
const content = utils.filterCirculars(metadata);
|
|
2252
|
+
return new discord_js.AttachmentBuilder(Buffer.from(JSON.stringify(content, void 0, 2), "utf-8"), {
|
|
2253
|
+
name: "metadata.json",
|
|
2254
|
+
description: "Metadata associated with the error"
|
|
2255
|
+
});
|
|
2238
2256
|
}
|
|
2239
|
-
}
|
|
2240
|
-
__name(attemptSendDM, "attemptSendDM");
|
|
2241
|
-
var PermissionNames = new Map(Object.entries(discord_js.PermissionFlagsBits).map(([key, bit]) => [
|
|
2242
|
-
bit,
|
|
2243
|
-
utils.prettify(key)
|
|
2244
|
-
]));
|
|
2245
|
-
var PERM_GROUPS = {
|
|
2246
|
-
manage: /* @__PURE__ */ new Map([
|
|
2247
|
-
[
|
|
2248
|
-
discord_js.PermissionFlagsBits.ManageChannels,
|
|
2249
|
-
"Manage Channels"
|
|
2250
|
-
],
|
|
2251
|
-
[
|
|
2252
|
-
discord_js.PermissionFlagsBits.ManageRoles,
|
|
2253
|
-
"Manage Roles"
|
|
2254
|
-
],
|
|
2255
|
-
[
|
|
2256
|
-
discord_js.PermissionFlagsBits.ManageWebhooks,
|
|
2257
|
-
"Manage Webhooks"
|
|
2258
|
-
],
|
|
2259
|
-
[
|
|
2260
|
-
discord_js.PermissionFlagsBits.ManageMessages,
|
|
2261
|
-
"Manage Messages"
|
|
2262
|
-
],
|
|
2263
|
-
[
|
|
2264
|
-
discord_js.PermissionFlagsBits.ManageNicknames,
|
|
2265
|
-
"Manage Nicknames"
|
|
2266
|
-
]
|
|
2267
|
-
]),
|
|
2268
|
-
embed: /* @__PURE__ */ new Map([
|
|
2269
|
-
[
|
|
2270
|
-
discord_js.PermissionFlagsBits.ViewChannel,
|
|
2271
|
-
"View Channel"
|
|
2272
|
-
],
|
|
2273
|
-
[
|
|
2274
|
-
discord_js.PermissionFlagsBits.SendMessages,
|
|
2275
|
-
"Send Messages"
|
|
2276
|
-
],
|
|
2277
|
-
[
|
|
2278
|
-
discord_js.PermissionFlagsBits.EmbedLinks,
|
|
2279
|
-
"Embed Links"
|
|
2280
|
-
],
|
|
2281
|
-
[
|
|
2282
|
-
discord_js.PermissionFlagsBits.AttachFiles,
|
|
2283
|
-
"Attach Files"
|
|
2284
|
-
],
|
|
2285
|
-
[
|
|
2286
|
-
discord_js.PermissionFlagsBits.UseExternalEmojis,
|
|
2287
|
-
"Use External Emojis"
|
|
2288
|
-
],
|
|
2289
|
-
[
|
|
2290
|
-
discord_js.PermissionFlagsBits.ReadMessageHistory,
|
|
2291
|
-
"Read Message History"
|
|
2292
|
-
]
|
|
2293
|
-
]),
|
|
2294
|
-
others: /* @__PURE__ */ new Map([
|
|
2295
|
-
[
|
|
2296
|
-
discord_js.PermissionFlagsBits.AddReactions,
|
|
2297
|
-
"Add Reactions"
|
|
2298
|
-
],
|
|
2299
|
-
[
|
|
2300
|
-
discord_js.PermissionFlagsBits.UseApplicationCommands,
|
|
2301
|
-
"Use Application Commands"
|
|
2302
|
-
]
|
|
2303
|
-
])
|
|
2304
2257
|
};
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
break;
|
|
2318
|
-
case "embed":
|
|
2319
|
-
required = PERM_GROUPS.embed;
|
|
2320
|
-
break;
|
|
2321
|
-
case "others":
|
|
2322
|
-
required = new Map([
|
|
2323
|
-
...PERM_GROUPS.others,
|
|
2324
|
-
...PERM_GROUPS.embed
|
|
2325
|
-
]);
|
|
2326
|
-
break;
|
|
2327
|
-
default:
|
|
2328
|
-
required = new Map([
|
|
2329
|
-
...PERM_GROUPS.manage,
|
|
2330
|
-
...PERM_GROUPS.others,
|
|
2331
|
-
...PERM_GROUPS.embed
|
|
2332
|
-
]);
|
|
2333
|
-
break;
|
|
2334
|
-
}
|
|
2258
|
+
_ts_decorate5([
|
|
2259
|
+
envapt.Envapt("UNKNOWN_EXCEPTION_WEBHOOK_URL", {
|
|
2260
|
+
converter: /* @__PURE__ */ __name((raw, fallback) => webhookUrlValidator(raw), "converter")
|
|
2261
|
+
}),
|
|
2262
|
+
_ts_metadata5("design:type", String)
|
|
2263
|
+
], exports.UnknownException, "unknownExceptionWebhookUrl", void 0);
|
|
2264
|
+
exports.UnknownException = _ts_decorate5([
|
|
2265
|
+
RegisterEffect("unknownException")
|
|
2266
|
+
], exports.UnknownException);
|
|
2267
|
+
var DefaultSeparator = class DefaultSeparator2 extends BuilderComponent {
|
|
2268
|
+
static {
|
|
2269
|
+
__name(this, "DefaultSeparator");
|
|
2335
2270
|
}
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
} else {
|
|
2340
|
-
if (!client.user) {
|
|
2341
|
-
throw new services.SeedcordError(services.SeedcordErrorCode.CoreClientUserUnavailable);
|
|
2342
|
-
}
|
|
2343
|
-
permissions = roleOrChannel.permissionsFor(client.user, true);
|
|
2271
|
+
constructor() {
|
|
2272
|
+
super("separator");
|
|
2273
|
+
this.instance.setSpacing(discord_js.SeparatorSpacingSize.Small).setDivider(true);
|
|
2344
2274
|
}
|
|
2345
|
-
|
|
2346
|
-
|
|
2275
|
+
};
|
|
2276
|
+
var UnhandledErrorContainer = class UnhandledErrorContainer2 extends BuilderComponent {
|
|
2277
|
+
static {
|
|
2278
|
+
__name(this, "UnhandledErrorContainer");
|
|
2347
2279
|
}
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2280
|
+
constructor(data) {
|
|
2281
|
+
super("container");
|
|
2282
|
+
const { uuid, error, guild, user, metadata } = data;
|
|
2283
|
+
this.instance.addTextDisplayComponents((text) => text.setContent(`### An unknown exception was thrown
|
|
2284
|
+
**Guild ID:** \`${guild?.id ?? "Not used in a guild"}\`
|
|
2285
|
+
**Guild Name:** ${guild?.name ?? "Not used in a guild"}
|
|
2286
|
+
**User ID:** \`${user?.id ?? "Missing user info"}\`
|
|
2287
|
+
**Username:** ${user?.username ?? "Missing user info"}
|
|
2288
|
+
`)).addSeparatorComponents(new DefaultSeparator().component).addTextDisplayComponents((text) => text.setContent(`### UUID \`${uuid}\`
|
|
2289
|
+
\`\`\`${error.stack}\`\`\``));
|
|
2290
|
+
this.addTimestampsIfAvailable(error);
|
|
2291
|
+
this.addMetadataIfAvailable(metadata);
|
|
2358
2292
|
}
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2293
|
+
addTimestampsIfAvailable(error) {
|
|
2294
|
+
if (!(error instanceof discord_js.DiscordAPIError)) return;
|
|
2295
|
+
const now = Date.now();
|
|
2296
|
+
const snowflake = error.url.match(/\/interactions\/(\d+)\//)?.[1];
|
|
2297
|
+
if (!snowflake) return void 0;
|
|
2298
|
+
const interactionTs = Number(discord_js.SnowflakeUtil.deconstruct(snowflake).timestamp);
|
|
2299
|
+
const diff = now - interactionTs;
|
|
2300
|
+
const seconds = Math.floor(diff / 1e3);
|
|
2301
|
+
const millis = diff % 1e3;
|
|
2302
|
+
this.instance.addSeparatorComponents(new DefaultSeparator().component).addTextDisplayComponents((text) => text.setContent(`### Timestamps
|
|
2303
|
+
- **\`Interaction sent\` :** ${new Date(interactionTs).toISOString()} (${interactionTs})
|
|
2304
|
+
- **\`Error logged \` :** ${new Date(now).toISOString()} (${now})
|
|
2305
|
+
- **\`Offset \` :** ${seconds}s ${millis}ms`));
|
|
2364
2306
|
}
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
guild.id
|
|
2369
|
-
]);
|
|
2307
|
+
addMetadataIfAvailable(metadata) {
|
|
2308
|
+
if (!metadata) return;
|
|
2309
|
+
this.instance.addSeparatorComponents(new DefaultSeparator().component).addTextDisplayComponents((text) => text.setContent("### Metadata")).addFileComponents((file) => file.setURL("attachment://metadata.json"));
|
|
2370
2310
|
}
|
|
2371
|
-
|
|
2372
|
-
}
|
|
2373
|
-
__name(getBotRole, "getBotRole");
|
|
2311
|
+
};
|
|
2374
2312
|
|
|
2375
|
-
// src/
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
checkPermissions(client, botRole, scope, inverse);
|
|
2380
|
-
} else {
|
|
2381
|
-
checkPermissions(client, guildOrChannel, scope);
|
|
2313
|
+
// src/effects/EffectsRegistry.ts
|
|
2314
|
+
var EffectsRegistry = class extends Plugin {
|
|
2315
|
+
static {
|
|
2316
|
+
__name(this, "EffectsRegistry");
|
|
2382
2317
|
}
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2318
|
+
core;
|
|
2319
|
+
logger = new services.Logger("Effects");
|
|
2320
|
+
isInitialized = false;
|
|
2321
|
+
effectsMap = new discord_js.Collection();
|
|
2322
|
+
emitter = new EffectsEmitter();
|
|
2323
|
+
constructor(core) {
|
|
2324
|
+
super(core), this.core = core;
|
|
2389
2325
|
}
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
const
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2326
|
+
async init() {
|
|
2327
|
+
if (this.isInitialized) return;
|
|
2328
|
+
this.isInitialized = true;
|
|
2329
|
+
const effectsDir = this.core.config.effects.path;
|
|
2330
|
+
this.logger.info(chalk3__default.default.bold(effectsDir));
|
|
2331
|
+
this.registerEffect(exports.UnknownException, {
|
|
2332
|
+
effect: "unknownException",
|
|
2333
|
+
frequency: "on"
|
|
2334
|
+
});
|
|
2335
|
+
await this.loadEffects(effectsDir);
|
|
2336
|
+
this.attachEffects();
|
|
2337
|
+
const totalEffects = Array.from(this.effectsMap.values()).reduce((acc, handlers) => acc + handlers.length, 0);
|
|
2338
|
+
this.logger.info(`${chalk3__default.default.bold.green("Loaded")}: ${chalk3__default.default.bold.magenta(totalEffects)} side effects`);
|
|
2339
|
+
}
|
|
2340
|
+
async loadEffects(dir) {
|
|
2341
|
+
await utils.traverseDirectory(dir, (_fullPath, relativePath, imported) => {
|
|
2342
|
+
for (const exportName of Object.keys(imported)) {
|
|
2343
|
+
const val = imported[exportName];
|
|
2344
|
+
if (this.isEffectHandler(val)) {
|
|
2345
|
+
const meta = Reflect.getMetadata(EffectMetadataKey, val);
|
|
2346
|
+
this.registerEffect(val, meta);
|
|
2347
|
+
this.logger.info(`${chalk3__default.default.italic("Registered")} ${chalk3__default.default.bold.yellow(val.name)} from ${chalk3__default.default.gray(relativePath)}`);
|
|
2411
2348
|
}
|
|
2412
2349
|
}
|
|
2350
|
+
}, this.logger);
|
|
2351
|
+
}
|
|
2352
|
+
registerEffect(handler, options) {
|
|
2353
|
+
let handlers = this.effectsMap.get(options.effect);
|
|
2354
|
+
if (!handlers) {
|
|
2355
|
+
handlers = [];
|
|
2356
|
+
this.effectsMap.set(options.effect, handlers);
|
|
2413
2357
|
}
|
|
2358
|
+
handlers.push({
|
|
2359
|
+
ctor: handler,
|
|
2360
|
+
frequency: options.frequency ?? "on"
|
|
2361
|
+
});
|
|
2414
2362
|
}
|
|
2415
|
-
|
|
2416
|
-
|
|
2363
|
+
isEffectHandler(obj) {
|
|
2364
|
+
if (typeof obj !== "function") return false;
|
|
2365
|
+
return obj.prototype instanceof EffectsHandler && Reflect.hasMetadata(EffectMetadataKey, obj);
|
|
2417
2366
|
}
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2367
|
+
attachEffects() {
|
|
2368
|
+
for (const [effectName, handlerEntries] of this.effectsMap) {
|
|
2369
|
+
for (const entry of handlerEntries) {
|
|
2370
|
+
const register = entry.frequency === "once" ? this.emitter.once.bind(this.emitter) : this.emitter.on.bind(this.emitter);
|
|
2371
|
+
register(effectName, (data) => {
|
|
2372
|
+
try {
|
|
2373
|
+
const instance = new entry.ctor(data, this.core);
|
|
2374
|
+
void instance.execute();
|
|
2375
|
+
} catch (err) {
|
|
2376
|
+
this.logger.error(`Error in side effect ${String(effectName)} handler ${entry.ctor.name}:`, err);
|
|
2377
|
+
}
|
|
2378
|
+
});
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2425
2381
|
}
|
|
2426
|
-
|
|
2427
|
-
|
|
2382
|
+
emit(event, data) {
|
|
2383
|
+
return this.emitter.emit(event, data);
|
|
2428
2384
|
}
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
}
|
|
2441
|
-
|
|
2442
|
-
}
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2385
|
+
};
|
|
2386
|
+
var Seedcord = class _Seedcord extends Pluggable {
|
|
2387
|
+
static {
|
|
2388
|
+
__name(this, "Seedcord");
|
|
2389
|
+
}
|
|
2390
|
+
config;
|
|
2391
|
+
static isInstantiated = false;
|
|
2392
|
+
/** @see {@link CoordinatedShutdown} */
|
|
2393
|
+
shutdown;
|
|
2394
|
+
/** @see {@link CoordinatedStartup} */
|
|
2395
|
+
startup;
|
|
2396
|
+
/** @see {@link EffectsRegistry} */
|
|
2397
|
+
effects;
|
|
2398
|
+
/** @see {@link Bot} */
|
|
2399
|
+
bot;
|
|
2400
|
+
/** @see {@link HealthCheck} */
|
|
2401
|
+
healthCheck;
|
|
2402
|
+
/**
|
|
2403
|
+
* Creates a new Seedcord instance
|
|
2404
|
+
*
|
|
2405
|
+
* @param config - Bot configuration including paths and Discord client options
|
|
2406
|
+
* @throws An {@link SeedcordError} When attempting to create multiple instances (singleton)
|
|
2407
|
+
*/
|
|
2408
|
+
constructor(config) {
|
|
2409
|
+
const shutdown = new services.CoordinatedShutdown();
|
|
2410
|
+
const startup = new services.CoordinatedStartup();
|
|
2411
|
+
super(shutdown, startup), this.config = config;
|
|
2412
|
+
this.shutdown = shutdown;
|
|
2413
|
+
this.startup = startup;
|
|
2414
|
+
if (_Seedcord.isInstantiated) {
|
|
2415
|
+
throw new services.SeedcordError(services.SeedcordErrorCode.CoreSingletonViolation);
|
|
2456
2416
|
}
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2417
|
+
_Seedcord.isInstantiated = true;
|
|
2418
|
+
this.effects = new EffectsRegistry(this);
|
|
2419
|
+
this.bot = new Bot(this);
|
|
2420
|
+
this.healthCheck = new services.HealthCheck(this.shutdown);
|
|
2421
|
+
this.registerStartupTasks();
|
|
2422
|
+
}
|
|
2423
|
+
/**
|
|
2424
|
+
* Registers default startup tasks
|
|
2425
|
+
* @internal
|
|
2426
|
+
*/
|
|
2427
|
+
registerStartupTasks() {
|
|
2428
|
+
this.startup.addTask(services.StartupPhase.Configuration, "Effect Initialization", async () => {
|
|
2429
|
+
this.effects.logger.info(chalk3__default.default.bold("Initializing"));
|
|
2430
|
+
await this.effects.init();
|
|
2431
|
+
this.effects.logger.info(chalk3__default.default.bold("Initialized"));
|
|
2432
|
+
});
|
|
2433
|
+
this.startup.addTask(services.StartupPhase.Instantiation, "Bot Initialization", async () => {
|
|
2434
|
+
this.bot.logger.info(chalk3__default.default.bold("Initializing"));
|
|
2435
|
+
await this.bot.init();
|
|
2436
|
+
this.bot.logger.info(chalk3__default.default.bold("Initialized"));
|
|
2437
|
+
});
|
|
2438
|
+
this.startup.addTask(services.StartupPhase.Ready, "Health Check", async () => {
|
|
2439
|
+
this.healthCheck.logger.info(chalk3__default.default.bold("Initializing"));
|
|
2440
|
+
await this.healthCheck.init();
|
|
2441
|
+
this.healthCheck.logger.info(chalk3__default.default.bold("Initialized"));
|
|
2442
|
+
});
|
|
2443
|
+
}
|
|
2444
|
+
/**
|
|
2445
|
+
* Starts the bot and runs all initialization tasks
|
|
2446
|
+
*
|
|
2447
|
+
* @returns This Seedcord instance when fully initialized
|
|
2448
|
+
*/
|
|
2449
|
+
async start() {
|
|
2450
|
+
await super.init();
|
|
2451
|
+
return this;
|
|
2452
|
+
}
|
|
2453
|
+
};
|
|
2481
2454
|
|
|
2482
2455
|
exports.AutocompleteHandler = AutocompleteHandler;
|
|
2483
2456
|
exports.AutocompleteRoute = AutocompleteRoute;
|
|
@@ -2524,7 +2497,6 @@ exports.MiddlewareMetadataKey = MiddlewareMetadataKey;
|
|
|
2524
2497
|
exports.MiddlewareType = MiddlewareType;
|
|
2525
2498
|
exports.MissingPermissions = MissingPermissions;
|
|
2526
2499
|
exports.ModalRoute = ModalRoute;
|
|
2527
|
-
exports.PERM_GROUPS = PERM_GROUPS;
|
|
2528
2500
|
exports.PermissionNames = PermissionNames;
|
|
2529
2501
|
exports.Pluggable = Pluggable;
|
|
2530
2502
|
exports.Plugin = Plugin;
|
|
@@ -2547,6 +2519,8 @@ exports.attemptSendDM = attemptSendDM;
|
|
|
2547
2519
|
exports.buildSlashRoute = buildSlashRoute;
|
|
2548
2520
|
exports.checkBotPermissions = checkBotPermissions;
|
|
2549
2521
|
exports.checkPermissions = checkPermissions;
|
|
2522
|
+
exports.ensureBotPermissions = ensureBotPermissions;
|
|
2523
|
+
exports.ensurePermissions = ensurePermissions;
|
|
2550
2524
|
exports.extractErrorResponse = extractErrorResponse;
|
|
2551
2525
|
exports.fetchGuildMember = fetchGuildMember;
|
|
2552
2526
|
exports.fetchManyGuildMembers = fetchManyGuildMembers;
|