@seedcord/gateway 0.3.1 → 0.4.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.d.mts +246 -48
- package/dist/index.mjs +230 -104
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
package/dist/index.mjs
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
|
-
import { installNodeDefaults } from "@seedcord/logger/node";
|
|
3
|
-
import {
|
|
2
|
+
import { WinstonConsoleSink, WinstonFileSink, installNodeDefaults } from "@seedcord/logger/node";
|
|
3
|
+
import { EventMetadataKey, GateNotice, GatedMetadataKey, HmrManager, InteractionMetadataKey, InteractionRouteKeys, InteractionRoutes, MiddlewareMetadataKey, MissingPermissions, NoticeCard, PermissionNames, PublishDefault, accessorStore, areRoutes, asError, busLoggerOf, clearStore, decodeComponentRoute, deferFlags, guardedAccessor, isEmojiTuple, outcomeFor, pickNotice, prefixOf, queuedMsFor, reportDispatch, reportedWrite, routeIdOf, runHandlerGates, sendFlags, setBotColor, slowGateMonitor } from "@seedcord/core/internal";
|
|
4
4
|
import { SeedcordErrorCode, paint } from "@seedcord/errors";
|
|
5
5
|
import { SeedcordError, SeedcordTypeError, validateDiscordToken } from "@seedcord/errors/internal";
|
|
6
|
-
import {
|
|
6
|
+
import { ArraySourceBase, BaseHandler as BaseHandler$1, BaseReplySender, BuilderComponent, Bus, CursorSourceBase, CustomId, DispatchContext, Fault, Notice, PaginatorBase, RepliableHandler as RepliableHandler$1, ResolvedEmoji, RowComponent, Silence, Subscriber as Subscriber$1, WebhookLog as WebhookLog$1, assertPermissions, defineGate } from "@seedcord/core";
|
|
7
7
|
import { Logger, LoggerChannelRegistry } from "@seedcord/logger";
|
|
8
8
|
import { ButtonStyle, Client, ComponentType, DiscordAPIError, Events, GatewayIntentBits, Guild, GuildMember, IntentsBitField, InteractionContextType, Message, MessageFlags, PermissionFlagsBits, RESTJSONErrorCodes, Role, User } from "discord.js";
|
|
9
9
|
import { ButtonBuilder, TextDisplayBuilder } from "@discordjs/builders";
|
|
10
10
|
import { buildSlashRoute } from "@seedcord/utils/internal";
|
|
11
11
|
import { Plugin as Plugin$1 } from "@seedcord/core/plugin";
|
|
12
|
-
import {
|
|
12
|
+
import { CoordinatedShutdown, CoordinatedStartup, Pluggable } from "@seedcord/core/node";
|
|
13
|
+
import { CommandRegistry, HealthCheck, ShutdownPhase, StartupPhase, SubscriberLoader, settleWithin, shutdownOf } from "@seedcord/core/node/internal";
|
|
13
14
|
import { MemoryRateLimiter } from "@seedcord/rate-limiter";
|
|
14
|
-
import { SeedcordBrand } from "@seedcord/types/internal";
|
|
15
|
+
import { HostAugmentTarget, HostVersion, SeedcordBrand } from "@seedcord/types/internal";
|
|
15
16
|
import { Envapter } from "envapt";
|
|
16
17
|
import { Envapt } from "envapt/legacy";
|
|
17
18
|
import { HmrModuleHandler } from "@seedcord/core/hmr";
|
|
@@ -160,7 +161,7 @@ function Middleware(type, priority = 0, options = {}) {
|
|
|
160
161
|
return (ctor) => {
|
|
161
162
|
const normalizedPriority = Number(priority);
|
|
162
163
|
if (!Number.isFinite(normalizedPriority)) throw new SeedcordTypeError(SeedcordErrorCode.DecoratorInvalidMiddlewarePriority);
|
|
163
|
-
if (type === "interaction" && Array.isArray(options.events) && options.events.length > 0) throw new
|
|
164
|
+
if (type === "interaction" && Array.isArray(options.events) && options.events.length > 0) throw new SeedcordTypeError(SeedcordErrorCode.DecoratorInteractionEventFilter);
|
|
164
165
|
const metadata = {
|
|
165
166
|
priority: normalizedPriority,
|
|
166
167
|
type,
|
|
@@ -200,6 +201,7 @@ const IgnoreBots = defineGate("IgnoreBots", (ctx) => {
|
|
|
200
201
|
var NotNsfw = class extends GateNotice {
|
|
201
202
|
constructor(message = "This can only be used in an age-restricted channel.") {
|
|
202
203
|
super(message);
|
|
204
|
+
this.summary = "be in an age-restricted channel";
|
|
203
205
|
}
|
|
204
206
|
};
|
|
205
207
|
var RoleHigherThanMe = class extends Notice {
|
|
@@ -486,7 +488,7 @@ async function getConfirmation(handler, prompt, options) {
|
|
|
486
488
|
const { ephemeral = true, timeoutMs = DEFAULT_TIMEOUT_MS } = options ?? {};
|
|
487
489
|
const response = typeof prompt === "string" ? defaultPrompt(prompt, options) : await prompt(CONFIRM_IDS);
|
|
488
490
|
const interaction = handler.getEvent();
|
|
489
|
-
const sender = handler
|
|
491
|
+
const { sender } = handler;
|
|
490
492
|
const message = await sender.send(response, { ephemeral });
|
|
491
493
|
const winner = await collectChoice(message, interaction.user.id, timeoutMs);
|
|
492
494
|
if (!winner) {
|
|
@@ -724,9 +726,15 @@ function slashRouteOf(interaction) {
|
|
|
724
726
|
*/
|
|
725
727
|
var SlashHandler = class extends InteractionHandler {
|
|
726
728
|
/**
|
|
727
|
-
* The typed options for this command's route.
|
|
728
|
-
*
|
|
729
|
-
*
|
|
729
|
+
* The typed options for this command's route. Only the getters for kinds this command declares appear.
|
|
730
|
+
* Each getter's name argument is restricted to that command's options of its kind.
|
|
731
|
+
*
|
|
732
|
+
* - A required option drops the null.
|
|
733
|
+
* - Choices narrow to their literal union.
|
|
734
|
+
* - A channel option declared with `addChannelTypes` narrows to those types.
|
|
735
|
+
*
|
|
736
|
+
* Use `this.event.options` directly for anything outside this view, such as `getSubcommand()`.
|
|
737
|
+
* However, for the common case, the methods in this would suffice.
|
|
730
738
|
*/
|
|
731
739
|
get options() {
|
|
732
740
|
return this.event.options;
|
|
@@ -748,8 +756,8 @@ var SlashHandler = class extends InteractionHandler {
|
|
|
748
756
|
* class ModHandler extends SlashHandler<'ban' | 'kick'> {
|
|
749
757
|
* async execute() {
|
|
750
758
|
* await this.match({
|
|
751
|
-
* ban: (options) => this.event.guild?.members.ban(options.getUser('target'
|
|
752
|
-
* kick: (options) => this.event.guild?.members.kick(options.getUser('member'
|
|
759
|
+
* ban: (options) => this.event.guild?.members.ban(options.getUser('target').id),
|
|
760
|
+
* kick: (options) => this.event.guild?.members.kick(options.getUser('member').id)
|
|
753
761
|
* });
|
|
754
762
|
* }
|
|
755
763
|
* }
|
|
@@ -758,13 +766,18 @@ var SlashHandler = class extends InteractionHandler {
|
|
|
758
766
|
async match(arms) {
|
|
759
767
|
const route = slashRouteOf(this.event);
|
|
760
768
|
const arm = Object.hasOwn(arms, route) ? arms[route] : void 0;
|
|
761
|
-
if (!arm) throw new
|
|
769
|
+
if (!arm) throw new SeedcordTypeError(SeedcordErrorCode.SlashMatchArmMissing, [route]);
|
|
762
770
|
return await arm(this.options);
|
|
763
771
|
}
|
|
764
772
|
};
|
|
765
773
|
|
|
766
774
|
//#endregion
|
|
767
775
|
//#region src/handlers/interaction/ContextMenuHandler.ts
|
|
776
|
+
function armFor(arms, name) {
|
|
777
|
+
const arm = Object.hasOwn(arms, name) ? arms[name] : void 0;
|
|
778
|
+
if (typeof arm !== "function") throw new SeedcordTypeError(SeedcordErrorCode.ContextMenuMatchArmMissing, [name]);
|
|
779
|
+
return arm;
|
|
780
|
+
}
|
|
768
781
|
/**
|
|
769
782
|
* Base class for a user context-menu command handler (right-click a user).
|
|
770
783
|
*
|
|
@@ -792,6 +805,38 @@ var UserContextMenuHandler = class extends InteractionHandler {
|
|
|
792
805
|
get targetMember() {
|
|
793
806
|
return this.event.targetMember;
|
|
794
807
|
}
|
|
808
|
+
/** Which of the registered commands fired. */
|
|
809
|
+
get commandName() {
|
|
810
|
+
return this.event.commandName;
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Run the arm for whichever command fired. Use this only when the handler is registered for several
|
|
814
|
+
* names.
|
|
815
|
+
*
|
|
816
|
+
* Provide one arm per registered name, keyed by the name Discord shows in the right-click menu. Each
|
|
817
|
+
* arm receives the clicked user and that user's guild member, both narrowed to the cache state of that
|
|
818
|
+
* one command. The arms must cover every name in the generic. A missing name or an unknown key is a
|
|
819
|
+
* compile error.
|
|
820
|
+
*
|
|
821
|
+
* @param arms - One handler per registered command name.
|
|
822
|
+
* @returns The result of the arm that ran.
|
|
823
|
+
*
|
|
824
|
+
* @example
|
|
825
|
+
* ```ts
|
|
826
|
+
* \@UserContextMenuRoute('View Profile', 'Warn')
|
|
827
|
+
* class Moderation extends UserContextMenuHandler<'View Profile' | 'Warn'> {
|
|
828
|
+
* async execute() {
|
|
829
|
+
* await this.match({
|
|
830
|
+
* 'View Profile': (user) => this.reply(`Profile for ${user.tag}.`),
|
|
831
|
+
* Warn: (user, member) => this.reply(`Warned ${member?.displayName ?? user.tag}.`)
|
|
832
|
+
* });
|
|
833
|
+
* }
|
|
834
|
+
* }
|
|
835
|
+
* ```
|
|
836
|
+
*/
|
|
837
|
+
async match(arms) {
|
|
838
|
+
return await armFor(arms, this.event.commandName)(this.target, this.targetMember);
|
|
839
|
+
}
|
|
795
840
|
};
|
|
796
841
|
/**
|
|
797
842
|
* Base class for a message context-menu command handler (right-click a message).
|
|
@@ -816,6 +861,37 @@ var MessageContextMenuHandler = class extends InteractionHandler {
|
|
|
816
861
|
get target() {
|
|
817
862
|
return this.event.targetMessage;
|
|
818
863
|
}
|
|
864
|
+
/** Which of the registered commands fired. */
|
|
865
|
+
get commandName() {
|
|
866
|
+
return this.event.commandName;
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Run the arm for whichever command fired. Use this only when the handler is registered for several
|
|
870
|
+
* names.
|
|
871
|
+
*
|
|
872
|
+
* Provide one arm per registered name, keyed by the name Discord shows in the right-click menu. Each
|
|
873
|
+
* arm receives the clicked message, narrowed to the cache state of that one command. The arms must
|
|
874
|
+
* cover every name in the generic. A missing name or an unknown key is a compile error.
|
|
875
|
+
*
|
|
876
|
+
* @param arms - One handler per registered command name.
|
|
877
|
+
* @returns The result of the arm that ran.
|
|
878
|
+
*
|
|
879
|
+
* @example
|
|
880
|
+
* ```ts
|
|
881
|
+
* \@MessageContextMenuRoute('Report Message', 'Pin Message')
|
|
882
|
+
* class MessageTools extends MessageContextMenuHandler<'Report Message' | 'Pin Message'> {
|
|
883
|
+
* async execute() {
|
|
884
|
+
* await this.match({
|
|
885
|
+
* 'Report Message': (message) => this.report(message),
|
|
886
|
+
* 'Pin Message': (message) => message.pin()
|
|
887
|
+
* });
|
|
888
|
+
* }
|
|
889
|
+
* }
|
|
890
|
+
* ```
|
|
891
|
+
*/
|
|
892
|
+
async match(arms) {
|
|
893
|
+
return await armFor(arms, this.event.commandName)(this.target);
|
|
894
|
+
}
|
|
819
895
|
};
|
|
820
896
|
|
|
821
897
|
//#endregion
|
|
@@ -890,7 +966,7 @@ var AutocompleteHandler = class extends BaseHandler {
|
|
|
890
966
|
const { name, value } = this.focused;
|
|
891
967
|
const respond = (choices) => this.respond(choices);
|
|
892
968
|
const arm = Object.hasOwn(arms, name) ? arms[name] : void 0;
|
|
893
|
-
if (!arm) throw new
|
|
969
|
+
if (!arm) throw new SeedcordTypeError(SeedcordErrorCode.AutocompleteMatchArmMissing, [name]);
|
|
894
970
|
return await arm(value, respond);
|
|
895
971
|
}
|
|
896
972
|
/** Send autocomplete suggestions, callback type 8. Prefer {@link match}, which restricts each field's choices to its declared type. */
|
|
@@ -980,7 +1056,7 @@ var ComponentHandler = class extends InteractionHandler {
|
|
|
980
1056
|
async match(arms) {
|
|
981
1057
|
const { prefix, params } = this.route;
|
|
982
1058
|
const arm = Object.hasOwn(arms, prefix) ? arms[prefix] : void 0;
|
|
983
|
-
if (!arm) throw new
|
|
1059
|
+
if (!arm) throw new SeedcordTypeError(SeedcordErrorCode.CustomIdMatchArmMissing, [prefix]);
|
|
984
1060
|
return await arm(params);
|
|
985
1061
|
}
|
|
986
1062
|
};
|
|
@@ -1018,8 +1094,8 @@ var ButtonHandler = class extends ComponentHandler {};
|
|
|
1018
1094
|
*
|
|
1019
1095
|
* Register the customId definitions this handler decodes with `@ModalRoute`, list the same ones in the
|
|
1020
1096
|
* generic, then read `this.params` for a single route or `this.match` for several. Read the submitted
|
|
1021
|
-
* inputs from `this.
|
|
1022
|
-
*
|
|
1097
|
+
* inputs from `this.fields`. Reply through the handler members. `showModal` fails compilation on this kind,
|
|
1098
|
+
* because Discord forbids opening a modal in response to a modal.
|
|
1023
1099
|
*
|
|
1024
1100
|
* @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof ConfigId]`.
|
|
1025
1101
|
* @typeParam Cache - The interaction cache state, `'cached'` by default.
|
|
@@ -1030,13 +1106,17 @@ var ButtonHandler = class extends ComponentHandler {};
|
|
|
1030
1106
|
* class ConfigModal extends ModalHandler<[typeof ConfigId]> {
|
|
1031
1107
|
* async execute() {
|
|
1032
1108
|
* const { guildId } = this.params;
|
|
1033
|
-
* const name = this.
|
|
1109
|
+
* const name = this.fields.getTextInputValue('name');
|
|
1034
1110
|
* await this.reply(`saved ${name} for ${guildId}`);
|
|
1035
1111
|
* }
|
|
1036
1112
|
* }
|
|
1037
1113
|
* ```
|
|
1038
1114
|
*/
|
|
1039
1115
|
var ModalHandler = class extends ComponentHandler {
|
|
1116
|
+
/** The fields this modal submitted, read by custom id. */
|
|
1117
|
+
get fields() {
|
|
1118
|
+
return this.event.fields;
|
|
1119
|
+
}
|
|
1040
1120
|
/** Rewrite the message this modal was opened from. Throws when a command opened the modal. */
|
|
1041
1121
|
update(response) {
|
|
1042
1122
|
this.ensureSourceMessage("update");
|
|
@@ -1058,10 +1138,12 @@ var ModalHandler = class extends ComponentHandler {
|
|
|
1058
1138
|
/**
|
|
1059
1139
|
* Base class for a select menu handler.
|
|
1060
1140
|
*
|
|
1061
|
-
* Pass the select kind first and the customId definitions second, the same order as `@SelectMenuRoute
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1141
|
+
* Pass the select kind first and the customId definitions second, the same order as `@SelectMenuRoute`.
|
|
1142
|
+
* Read the picked ids from `this.values`. The kind decides which of `this.users`, `this.members`,
|
|
1143
|
+
* `this.roles`, and `this.channels` this handler carries. The rest are `never`.
|
|
1144
|
+
*
|
|
1145
|
+
* Read `this.params` for a single route or `this.match` for several. Reply through the handler members, or
|
|
1146
|
+
* rewrite the source message with `this.update`.
|
|
1065
1147
|
*
|
|
1066
1148
|
* @typeParam Kind - The select kind from {@link SelectMenuKind}, e.g. `SelectMenuKind.User`.
|
|
1067
1149
|
* @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof AssignId]`.
|
|
@@ -1073,12 +1155,36 @@ var ModalHandler = class extends ComponentHandler {
|
|
|
1073
1155
|
* class AssignSelect extends SelectMenuHandler<SelectMenuKind.User, [typeof AssignId]> {
|
|
1074
1156
|
* async execute() {
|
|
1075
1157
|
* const { roleId } = this.params;
|
|
1076
|
-
* await this.reply(`assigning ${this.
|
|
1158
|
+
* await this.reply(`assigning ${this.users.size} member(s) to <@&${roleId}>`);
|
|
1077
1159
|
* }
|
|
1078
1160
|
* }
|
|
1079
1161
|
* ```
|
|
1080
1162
|
*/
|
|
1081
|
-
var SelectMenuHandler = class extends ComponentHandler {
|
|
1163
|
+
var SelectMenuHandler = class extends ComponentHandler {
|
|
1164
|
+
eventMember(key) {
|
|
1165
|
+
return this.event[key];
|
|
1166
|
+
}
|
|
1167
|
+
/** The ids this select picked. */
|
|
1168
|
+
get values() {
|
|
1169
|
+
return this.eventMember("values");
|
|
1170
|
+
}
|
|
1171
|
+
/** The users this select picked. */
|
|
1172
|
+
get users() {
|
|
1173
|
+
return this.eventMember("users");
|
|
1174
|
+
}
|
|
1175
|
+
/** The guild members behind the picked users. Discord resolves these only inside a guild. */
|
|
1176
|
+
get members() {
|
|
1177
|
+
return this.eventMember("members");
|
|
1178
|
+
}
|
|
1179
|
+
/** The roles this select picked. */
|
|
1180
|
+
get roles() {
|
|
1181
|
+
return this.eventMember("roles");
|
|
1182
|
+
}
|
|
1183
|
+
/** The channels this select picked. */
|
|
1184
|
+
get channels() {
|
|
1185
|
+
return this.eventMember("channels");
|
|
1186
|
+
}
|
|
1187
|
+
};
|
|
1082
1188
|
|
|
1083
1189
|
//#endregion
|
|
1084
1190
|
//#region src/handlers/event/EventHandler.ts
|
|
@@ -1137,9 +1243,9 @@ var EventHandler = class extends BaseHandler {
|
|
|
1137
1243
|
*/
|
|
1138
1244
|
async match(arms) {
|
|
1139
1245
|
const name = this.firedEvent;
|
|
1140
|
-
if (name === void 0) throw new
|
|
1141
|
-
const arm = arms[name];
|
|
1142
|
-
if (typeof arm !== "function") throw new
|
|
1246
|
+
if (name === void 0) throw new SeedcordTypeError(SeedcordErrorCode.EventMatchArmMissing, ["<no event>"]);
|
|
1247
|
+
const arm = Object.hasOwn(arms, name) ? arms[name] : void 0;
|
|
1248
|
+
if (typeof arm !== "function") throw new SeedcordTypeError(SeedcordErrorCode.EventMatchArmMissing, [name]);
|
|
1143
1249
|
return await arm(...this.getEvent());
|
|
1144
1250
|
}
|
|
1145
1251
|
};
|
|
@@ -1208,25 +1314,33 @@ var Paginator = class extends PaginatorBase {
|
|
|
1208
1314
|
Handler;
|
|
1209
1315
|
constructor(config) {
|
|
1210
1316
|
super(config);
|
|
1211
|
-
const
|
|
1317
|
+
const pageFor = (handler, n) => this.page(handler, n);
|
|
1212
1318
|
this.Handler = class Nav extends ButtonHandler {
|
|
1213
1319
|
async execute() {
|
|
1214
1320
|
await this.deferUpdate();
|
|
1215
|
-
const response = await
|
|
1321
|
+
const response = await pageFor(this, this.params.page);
|
|
1216
1322
|
await this.update(response);
|
|
1217
1323
|
}
|
|
1218
1324
|
};
|
|
1219
1325
|
}
|
|
1220
1326
|
/**
|
|
1221
|
-
* Render page
|
|
1222
|
-
*
|
|
1327
|
+
* Render a page as a {@link ReplyResponse} without sending anything.
|
|
1328
|
+
*
|
|
1329
|
+
* @param handler - The handler rendering the page, normally `this`.
|
|
1330
|
+
* @param n - The zero-based page.
|
|
1331
|
+
*/
|
|
1332
|
+
async page(handler, n) {
|
|
1333
|
+
return this.buildPage(contextOf(handler.getEvent(), handler.core), n);
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Send a page through the handler's sender. The sender picks reply, edit, or followUp from its ack state.
|
|
1223
1337
|
*
|
|
1224
1338
|
* @param handler - The handler starting the paginator, normally `this`.
|
|
1339
|
+
* @param n - The zero-based page to open on.
|
|
1225
1340
|
*/
|
|
1226
|
-
async start(handler) {
|
|
1227
|
-
const
|
|
1228
|
-
|
|
1229
|
-
return handler.getSender().send(response, { ephemeral: this.config.ephemeral ?? false });
|
|
1341
|
+
async start(handler, n = 0) {
|
|
1342
|
+
const response = await this.page(handler, n);
|
|
1343
|
+
return handler.sender.send(response, { ephemeral: this.config.ephemeral ?? false });
|
|
1230
1344
|
}
|
|
1231
1345
|
};
|
|
1232
1346
|
|
|
@@ -1239,7 +1353,7 @@ var Paginator = class extends PaginatorBase {
|
|
|
1239
1353
|
*
|
|
1240
1354
|
* @typeParam Item - The item type, inferred from the loader's return.
|
|
1241
1355
|
*/
|
|
1242
|
-
var ArraySource = class extends
|
|
1356
|
+
var ArraySource = class extends ArraySourceBase {};
|
|
1243
1357
|
/**
|
|
1244
1358
|
* A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).
|
|
1245
1359
|
* The fetcher receives the page index and the page size and reports whether a next page exists. A cursor
|
|
@@ -1248,7 +1362,7 @@ var ArraySource = class extends ArraySource$1 {};
|
|
|
1248
1362
|
*
|
|
1249
1363
|
* @typeParam Item - The item type, inferred from the fetcher's slice.
|
|
1250
1364
|
*/
|
|
1251
|
-
var CursorSource = class extends
|
|
1365
|
+
var CursorSource = class extends CursorSourceBase {};
|
|
1252
1366
|
|
|
1253
1367
|
//#endregion
|
|
1254
1368
|
//#region src/subscribers/index.ts
|
|
@@ -1682,7 +1796,7 @@ var EventDispatcher = class {
|
|
|
1682
1796
|
this.logger.debug(`Attaching ${paint.sky.bold(eventName)} to the client with ${paint.mute(handlerEntries?.length ?? 0)} handler(s)`);
|
|
1683
1797
|
this.core.bot.client.on(eventName, (...args) => {
|
|
1684
1798
|
if (this.draining) return;
|
|
1685
|
-
this.core.bus[PublishDefault]("
|
|
1799
|
+
this.core.bus[PublishDefault]("eventDispatching", {
|
|
1686
1800
|
name: eventName,
|
|
1687
1801
|
args
|
|
1688
1802
|
});
|
|
@@ -2070,7 +2184,7 @@ var InteractionDispatcher = class {
|
|
|
2070
2184
|
const dispatch = new DispatchContext(routeIdOf(HandlerCtor) ?? routeId);
|
|
2071
2185
|
routeId = dispatch.routeId ?? routeId;
|
|
2072
2186
|
const handler = this.buildHandler(HandlerCtor, interaction, dispatch, key, !matched);
|
|
2073
|
-
if (handler instanceof RepliableHandler) sender = handler.
|
|
2187
|
+
if (handler instanceof RepliableHandler) sender = handler.sender;
|
|
2074
2188
|
const refusal = interaction.isAutocomplete() ? null : await this.gateRefusal(HandlerCtor, interaction, dispatch.routeId);
|
|
2075
2189
|
if (refusal) {
|
|
2076
2190
|
await this.answer(refusal.caught, interaction, routeId, sender, report);
|
|
@@ -2213,105 +2327,116 @@ const DRAIN_TASK_TIMEOUT_MS = 6e3;
|
|
|
2213
2327
|
const UNBIND_TIMEOUT_MS = 2e3;
|
|
2214
2328
|
const LOGOUT_TIMEOUT_MS = 2e3;
|
|
2215
2329
|
const loggerSlot = Symbol("seedcord:bot:logger");
|
|
2330
|
+
const initSlot = Symbol("seedcord:bot:init");
|
|
2331
|
+
const controllersSlot = Symbol("seedcord:bot:controllers");
|
|
2216
2332
|
/**
|
|
2217
2333
|
* The Discord client and its controllers. Access it through `core.bot`.
|
|
2218
2334
|
*/
|
|
2219
2335
|
var Bot = class {
|
|
2220
|
-
logger = new Logger("Bot", { channel: "bot" });
|
|
2336
|
+
#logger = new Logger("Bot", { channel: "bot" });
|
|
2221
2337
|
/** @internal */
|
|
2222
|
-
[loggerSlot] = this
|
|
2223
|
-
isInitialized = false;
|
|
2224
|
-
intents;
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
commandRegistry;
|
|
2338
|
+
[loggerSlot] = this.#logger;
|
|
2339
|
+
#isInitialized = false;
|
|
2340
|
+
#intents;
|
|
2341
|
+
#client;
|
|
2342
|
+
#emojiInjector;
|
|
2343
|
+
#interactions;
|
|
2344
|
+
#events;
|
|
2345
|
+
#commandRegistry;
|
|
2230
2346
|
/** @internal */
|
|
2231
2347
|
async onHmr(event) {
|
|
2232
|
-
if (this
|
|
2233
|
-
if (this
|
|
2234
|
-
if (this
|
|
2348
|
+
if (this.#interactions) await this.#interactions.onHmr(event);
|
|
2349
|
+
if (this.#events) await this.#events.onHmr(event);
|
|
2350
|
+
if (this.#commandRegistry) await this.#commandRegistry.onHmr(event);
|
|
2235
2351
|
}
|
|
2236
2352
|
/** @internal */
|
|
2237
2353
|
constructor(core) {
|
|
2238
|
-
this
|
|
2239
|
-
this
|
|
2240
|
-
if (core.config.bot.interactions.path) this
|
|
2241
|
-
if (core.config.bot.events.path) this
|
|
2242
|
-
if (core.config.bot.commands.path) this
|
|
2243
|
-
this
|
|
2244
|
-
this
|
|
2354
|
+
this.#intents = core.config.bot.clientOptions.intents;
|
|
2355
|
+
this.#client = new Client(core.config.bot.clientOptions);
|
|
2356
|
+
if (core.config.bot.interactions.path) this.#interactions = new InteractionDispatcher(core);
|
|
2357
|
+
if (core.config.bot.events.path) this.#events = new EventDispatcher(core);
|
|
2358
|
+
if (core.config.bot.commands.path) this.#commandRegistry = new CommandRegistry(core);
|
|
2359
|
+
this.#emojiInjector = new EmojiInjector(core);
|
|
2360
|
+
this.#registerShutdownTasks(core);
|
|
2361
|
+
}
|
|
2362
|
+
/** @internal */
|
|
2363
|
+
get [controllersSlot]() {
|
|
2364
|
+
return {
|
|
2365
|
+
interactions: this.#interactions,
|
|
2366
|
+
events: this.#events,
|
|
2367
|
+
commandRegistry: this.#commandRegistry
|
|
2368
|
+
};
|
|
2245
2369
|
}
|
|
2246
2370
|
/** @internal */
|
|
2247
2371
|
get applicationId() {
|
|
2248
|
-
const { application } = this
|
|
2372
|
+
const { application } = this.#client;
|
|
2249
2373
|
if (!application) throw new SeedcordError(SeedcordErrorCode.CoreApplicationUnavailable);
|
|
2250
2374
|
return application.id;
|
|
2251
2375
|
}
|
|
2252
|
-
registerShutdownTasks(core) {
|
|
2376
|
+
#registerShutdownTasks(core) {
|
|
2253
2377
|
core.shutdown.addTask(ShutdownPhase.Unbind, "stop-dispatch", () => {
|
|
2254
|
-
this
|
|
2378
|
+
this.#stopAccepting();
|
|
2255
2379
|
return Promise.resolve();
|
|
2256
2380
|
}, UNBIND_TIMEOUT_MS);
|
|
2257
|
-
core.shutdown.addTask(ShutdownPhase.Drain, "drain-dispatch", () => this
|
|
2258
|
-
core.shutdown.addTask(ShutdownPhase.Logout, "stop-bot", async () => await this
|
|
2381
|
+
core.shutdown.addTask(ShutdownPhase.Drain, "drain-dispatch", () => this.#drain(), DRAIN_TASK_TIMEOUT_MS);
|
|
2382
|
+
core.shutdown.addTask(ShutdownPhase.Logout, "stop-bot", async () => await this.#stop(), LOGOUT_TIMEOUT_MS);
|
|
2259
2383
|
}
|
|
2260
|
-
stopAccepting() {
|
|
2261
|
-
this
|
|
2262
|
-
this
|
|
2384
|
+
#stopAccepting() {
|
|
2385
|
+
this.#interactions?.stopAccepting();
|
|
2386
|
+
this.#events?.stopAccepting();
|
|
2263
2387
|
}
|
|
2264
|
-
async drain() {
|
|
2265
|
-
await Promise.allSettled([this
|
|
2388
|
+
async #drain() {
|
|
2389
|
+
await Promise.allSettled([this.#interactions?.drain(DISPATCH_DRAIN_TIMEOUT_MS), this.#events?.drain(DISPATCH_DRAIN_TIMEOUT_MS)]);
|
|
2266
2390
|
}
|
|
2267
2391
|
/** @internal */
|
|
2268
|
-
async
|
|
2269
|
-
if (this
|
|
2270
|
-
this
|
|
2392
|
+
async [initSlot]() {
|
|
2393
|
+
if (this.#isInitialized) return;
|
|
2394
|
+
this.#isInitialized = true;
|
|
2271
2395
|
const token = this.botToken;
|
|
2272
|
-
if (this
|
|
2273
|
-
if (this
|
|
2274
|
-
await this
|
|
2275
|
-
await this
|
|
2276
|
-
if (this
|
|
2277
|
-
await this
|
|
2278
|
-
assertGuildsIntent(this
|
|
2279
|
-
await this
|
|
2280
|
-
this
|
|
2281
|
-
this
|
|
2396
|
+
if (this.#interactions) await this.#interactions.init();
|
|
2397
|
+
if (this.#events) await this.#events.init();
|
|
2398
|
+
await this.#login(token);
|
|
2399
|
+
await this.#emojiInjector.init();
|
|
2400
|
+
if (this.#commandRegistry) {
|
|
2401
|
+
await this.#commandRegistry.init();
|
|
2402
|
+
assertGuildsIntent(this.#intents, this.#commandRegistry.allCommands());
|
|
2403
|
+
await this.#commandRegistry.setCommands();
|
|
2404
|
+
this.#interactions?.warnUnhandledRoutes(this.#commandRegistry.routeLeaves());
|
|
2405
|
+
this.#interactions?.warnUnhandledContextMenuRoutes(this.#commandRegistry.contextMenuLeaves());
|
|
2282
2406
|
}
|
|
2283
2407
|
}
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
this
|
|
2287
|
-
await this.logout();
|
|
2408
|
+
async #stop() {
|
|
2409
|
+
this.#client.removeAllListeners();
|
|
2410
|
+
await this.#logout();
|
|
2288
2411
|
}
|
|
2289
|
-
async login(token) {
|
|
2412
|
+
async #login(token) {
|
|
2290
2413
|
const ready = Promise.withResolvers();
|
|
2291
|
-
this.
|
|
2292
|
-
this.
|
|
2414
|
+
this.#client.once(Events.ClientReady, () => ready.resolve());
|
|
2415
|
+
this.#client.login(token);
|
|
2293
2416
|
await ready.promise;
|
|
2294
|
-
this
|
|
2417
|
+
this.#logger.info(`Logged in as ${paint.sky.bold(this.#client.user?.username)}!`);
|
|
2295
2418
|
return this;
|
|
2296
2419
|
}
|
|
2297
|
-
async logout() {
|
|
2298
|
-
await this.
|
|
2299
|
-
this
|
|
2420
|
+
async #logout() {
|
|
2421
|
+
await this.#client.destroy();
|
|
2422
|
+
this.#logger.info(paint.coral.bold("Logged out of Discord!"));
|
|
2300
2423
|
}
|
|
2301
2424
|
get client() {
|
|
2302
|
-
return this
|
|
2425
|
+
return this.#client;
|
|
2303
2426
|
}
|
|
2304
2427
|
};
|
|
2305
2428
|
__decorate([Envapt("DISCORD_BOT_TOKEN", { converter: (raw) => validateDiscordToken(raw) })], Bot.prototype, "botToken", void 0);
|
|
2306
|
-
/** @internal */
|
|
2307
2429
|
function botLoggerOf(bot) {
|
|
2308
2430
|
return bot[loggerSlot];
|
|
2309
2431
|
}
|
|
2432
|
+
function initBot(bot) {
|
|
2433
|
+
return bot[initSlot]();
|
|
2434
|
+
}
|
|
2310
2435
|
|
|
2311
2436
|
//#endregion
|
|
2312
2437
|
//#region src/version.ts
|
|
2313
2438
|
/** Package version */
|
|
2314
|
-
const version = "0.
|
|
2439
|
+
const version = "0.4.0";
|
|
2315
2440
|
|
|
2316
2441
|
//#endregion
|
|
2317
2442
|
//#region src/Seedcord.ts
|
|
@@ -2324,9 +2449,9 @@ var Seedcord = class Seedcord extends Pluggable {
|
|
|
2324
2449
|
/** @internal */
|
|
2325
2450
|
[SeedcordBrand] = true;
|
|
2326
2451
|
/** @internal */
|
|
2327
|
-
|
|
2452
|
+
[HostAugmentTarget] = "@seedcord/gateway";
|
|
2328
2453
|
/** @internal */
|
|
2329
|
-
|
|
2454
|
+
[HostVersion] = version;
|
|
2330
2455
|
healthCheck;
|
|
2331
2456
|
hmrManager;
|
|
2332
2457
|
/** @see {@link Bus} */
|
|
@@ -2358,16 +2483,17 @@ var Seedcord = class Seedcord extends Pluggable {
|
|
|
2358
2483
|
this.bot = new Bot(this);
|
|
2359
2484
|
this.rest = this.bot.client.rest;
|
|
2360
2485
|
this.rateLimiter = config.store ?? new MemoryRateLimiter();
|
|
2361
|
-
this.healthCheck = HealthCheck.fromOption(this
|
|
2486
|
+
this.healthCheck = HealthCheck.fromOption(shutdownOf(this), config.healthCheck);
|
|
2362
2487
|
this.registerStartupTasks();
|
|
2363
2488
|
}
|
|
2364
2489
|
/** The bot's discord username, populated after login. */
|
|
2365
2490
|
get username() {
|
|
2366
2491
|
return this.bot.client.user?.username;
|
|
2367
2492
|
}
|
|
2368
|
-
static reset() {
|
|
2369
|
-
super.reset();
|
|
2493
|
+
static reset(host) {
|
|
2494
|
+
if (!super.reset(host)) return false;
|
|
2370
2495
|
LoggerChannelRegistry.instance.configure({});
|
|
2496
|
+
return true;
|
|
2371
2497
|
}
|
|
2372
2498
|
registerStartupTasks() {
|
|
2373
2499
|
if (Envapter.isDevelopment || Envapter.isTest) this.registerHmrAwareModules();
|
|
@@ -2378,7 +2504,7 @@ var Seedcord = class Seedcord extends Pluggable {
|
|
|
2378
2504
|
});
|
|
2379
2505
|
this.startup.addTask(StartupPhase.Login, "bot-initialization", async () => {
|
|
2380
2506
|
botLoggerOf(this.bot).utils.initialization("Bot", "start");
|
|
2381
|
-
await this.bot
|
|
2507
|
+
await initBot(this.bot);
|
|
2382
2508
|
botLoggerOf(this.bot).utils.initialization("Bot", "end");
|
|
2383
2509
|
});
|
|
2384
2510
|
const { healthCheck } = this;
|
|
@@ -2397,8 +2523,8 @@ var Seedcord = class Seedcord extends Pluggable {
|
|
|
2397
2523
|
try {
|
|
2398
2524
|
await super.init();
|
|
2399
2525
|
} catch (caught) {
|
|
2400
|
-
await this.
|
|
2401
|
-
Seedcord.reset();
|
|
2526
|
+
await shutdownOf(this).run(1, false);
|
|
2527
|
+
Seedcord.reset(this);
|
|
2402
2528
|
throw caught;
|
|
2403
2529
|
}
|
|
2404
2530
|
return this;
|
|
@@ -2414,5 +2540,5 @@ var Seedcord = class Seedcord extends Pluggable {
|
|
|
2414
2540
|
};
|
|
2415
2541
|
|
|
2416
2542
|
//#endregion
|
|
2417
|
-
export { ArraySource, AutocompleteHandler, BaseHandler, ButtonHandler, ComponentHandler, CursorSource, Emojis, EventHandler, EventMiddleware, Gated, GatewayEmoji, IgnoreBots, InteractionHandler, InteractionMiddleware, MessageContextMenuHandler, Middleware, MiddlewareType, ModalHandler, Nsfw, Paginator, Plugin, RegisterEvent, RepliableHandler, Seedcord, SelectMenuHandler, SlashHandler, Subscriber, UserContextMenuHandler, WebhookLog, checkBotPermissions, checkPermissions, getConfirmation, hasPermsToAssign, version };
|
|
2543
|
+
export { ArraySource, AutocompleteHandler, BaseHandler, ButtonHandler, ComponentHandler, CursorSource, Emojis, EventHandler, EventMiddleware, Gated, GatewayEmoji, IgnoreBots, InteractionHandler, InteractionMiddleware, MessageContextMenuHandler, Middleware, MiddlewareType, ModalHandler, Nsfw, Paginator, Plugin, RegisterEvent, RepliableHandler, ReplySender, Seedcord, SelectMenuHandler, SlashHandler, Subscriber, UserContextMenuHandler, WebhookLog, WinstonConsoleSink, WinstonFileSink, checkBotPermissions, checkPermissions, getConfirmation, hasPermsToAssign, version };
|
|
2418
2544
|
//# sourceMappingURL=index.mjs.map
|