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