@seedcord/gateway 0.1.0-next.3 → 0.1.0-next.4

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.mjs CHANGED
@@ -9,15 +9,15 @@ import { ActionRowBuilder, ButtonBuilder, ContextMenuCommandBuilder, SlashComman
9
9
  import { buildSlashRoute, routeLeavesOf } from "@seedcord/utils/internal";
10
10
  import { ApplicationCommandType, ButtonStyle, Client, Collection, ComponentType, DiscordAPIError, Events, Guild, GuildMember, Message, MessageFlags, PermissionFlagsBits, RESTJSONErrorCodes, Role, TextChannel, User, chatInputApplicationCommandMention } from "discord.js";
11
11
  import * as crypto from "node:crypto";
12
- import { TypedEventEmitter } from "@seedcord/event-emitter";
13
12
  import chalk from "chalk";
14
13
  import { Converters, Envapter } from "envapt";
15
14
  import { MessageFlags as MessageFlags$1, Routes, SeparatorSpacingSize } from "discord-api-types/v10";
16
15
  import { filterCirculars, formatFilePath, hasKeys, stripAnsi, timestampFromSnowflake } from "@seedcord/utils";
17
16
  import { DiscordAPIError as DiscordAPIError$1, REST } from "@discordjs/rest";
18
- import { CoordinatedShutdown, CoordinatedStartup, HealthCheck, ShutdownPhase, ShutdownPhase as ShutdownPhase$1, StartupPhase, StartupPhase as StartupPhase$1 } from "@seedcord/core/node";
17
+ import { CoordinatedShutdown, CoordinatedStartup, HealthCheck, Pluggable, ShutdownPhase, StartupPhase, settleWithin } from "@seedcord/core/node/internal";
19
18
  import { MemoryRateLimiter } from "@seedcord/rate-limiter";
20
19
  import { SeedcordBrand } from "@seedcord/types/internal";
20
+ import { TypedEventEmitter } from "@seedcord/event-emitter";
21
21
  import { Envapt } from "envapt/legacy";
22
22
  import { resolve } from "node:path";
23
23
  import { HmrModuleHandler } from "@seedcord/core/hmr";
@@ -29,12 +29,12 @@ export * from "@seedcord/core"
29
29
 
30
30
  export * from "@seedcord/logger"
31
31
 
32
- export * from "@seedcord/event-emitter"
33
-
34
32
  export * from "@seedcord/utils"
35
33
 
36
34
  export * from "@seedcord/rate-limiter"
37
35
 
36
+ export * from "@seedcord/event-emitter"
37
+
38
38
  //#region src/logger-bootstrap.ts
39
39
  installNodeDefaults();
40
40
 
@@ -1124,112 +1124,6 @@ async function getConfirmation(interaction, prompt, options) {
1124
1124
  return confirmed;
1125
1125
  }
1126
1126
 
1127
- //#endregion
1128
- //#region src/interfaces/Plugin.ts
1129
- /**
1130
- * Base class for Seedcord plugins
1131
- *
1132
- * Extend this class to create plugins that integrate with the Seedcord lifecycle.
1133
- * Plugins have access to the core instance and must implement initialization logic.
1134
- */
1135
- var Plugin = class extends TypedEventEmitter {
1136
- pluggable;
1137
- name = this.constructor.name;
1138
- constructor(pluggable) {
1139
- super();
1140
- this.pluggable = pluggable;
1141
- }
1142
- /**
1143
- * Reloads plugin state on an HMR update. The base implementation is a no-op, override it in your plugin.
1144
- * @virtual
1145
- */
1146
- onHmr(_event) {
1147
- return Promise.resolve();
1148
- }
1149
- /**
1150
- * Registers critical file patterns that should trigger a full restart when changed in Dev HMR.
1151
- * @param patterns - Glob patterns relative to the project root
1152
- */
1153
- registerCriticalFiles(patterns) {
1154
- getDevChannel()?.send("seedcord:register-critical-files", { patterns });
1155
- }
1156
- /** @internal */
1157
- removeListener(event, listener) {
1158
- return super.removeListener(event, listener);
1159
- }
1160
- /** @internal */
1161
- removeAllListeners(event) {
1162
- return super.removeAllListeners(event);
1163
- }
1164
- };
1165
- /**
1166
- * Base class for objects that can have plugins attached.
1167
- *
1168
- * Provides plugin attachment capabilities and lifecycle management. Plugins are attached during
1169
- * configuration and initialized during startup. Not constructed directly, the host is a {@link Seedcord}.
1170
- */
1171
- var Pluggable = class Pluggable extends TypedEventEmitter {
1172
- isInitialized = false;
1173
- shutdown;
1174
- startup;
1175
- plugins = [];
1176
- static PLUGIN_INIT_TIMEOUT_MS = 15e3;
1177
- constructor(shutdown, startup) {
1178
- super();
1179
- this.shutdown = shutdown;
1180
- this.startup = startup;
1181
- }
1182
- /** @internal */
1183
- async init() {
1184
- if (this.isInitialized) return this;
1185
- await this.startup.run();
1186
- this.isInitialized = true;
1187
- return this;
1188
- }
1189
- /**
1190
- * Attaches a plugin to this instance
1191
- *
1192
- * Plugins provide external functionality and are initialized during the specified startup phase.
1193
- * The plugin instance becomes available as a property in `core` wherever it's available.
1194
- *
1195
- * Make sure to augment the {@link Core} interface with the plugin type to ensure TypeScript recognizes it and provides intellisense.
1196
- *
1197
- * @typeParam Key - The property name for accessing the plugin
1198
- * @typeParam Ctor - The plugin constructor type
1199
- * @param key - Property name to access the plugin instance
1200
- * @param Plugin - Plugin constructor class
1201
- * @param startupPhase - When during startup to initialize this plugin ({@link StartupPhase})
1202
- * @param args - Additional arguments to pass to the plugin constructor
1203
- * @returns This instance with the plugin attached as a typed property
1204
- * @throws A **SeedcordError** When called after initialization or if key already exists
1205
- * @example
1206
- * ```typescript
1207
- * seedcord.attach('db', Mongo, StartupPhase.Configuration, { uri: 'mongodb://...', name: 'seedcord', dir: ... })
1208
- * ```
1209
- */
1210
- attach(key, Plugin, startupPhase, ...args) {
1211
- if (this.isInitialized) throw new SeedcordError(SeedcordErrorCode.CorePluginAfterInit);
1212
- if (key in this) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);
1213
- const instance = new Plugin(this, ...args);
1214
- this.plugins.push(instance);
1215
- const entry = { [key]: instance };
1216
- this.startup.addTask(startupPhase, `Plugin:${key}`, async () => {
1217
- instance.logger.utils.initialization(key, "start");
1218
- await instance.init();
1219
- instance.logger.utils.initialization(key, "end");
1220
- }, Pluggable.PLUGIN_INIT_TIMEOUT_MS);
1221
- return Object.assign(this, entry);
1222
- }
1223
- /** @internal */
1224
- removeListener(event, listener) {
1225
- return super.removeListener(event, listener);
1226
- }
1227
- /** @internal */
1228
- removeAllListeners(event) {
1229
- return super.removeAllListeners(event);
1230
- }
1231
- };
1232
-
1233
1127
  //#endregion
1234
1128
  //#region src/handlers/BaseHandler.ts
1235
1129
  /**
@@ -2275,7 +2169,6 @@ function slashRouteLeaves(commands) {
2275
2169
  var CommandRegistry = class {
2276
2170
  core;
2277
2171
  onDeployed;
2278
- name = "Commands";
2279
2172
  logger = new Logger("Commands");
2280
2173
  isInitialised = false;
2281
2174
  globalCommands = [];
@@ -2571,11 +2464,12 @@ var EventDispatcher = class {
2571
2464
  core;
2572
2465
  logger = new Logger("Events");
2573
2466
  isInitialized = false;
2574
- name = "Events";
2575
2467
  eventMap = /* @__PURE__ */ new Map();
2576
2468
  middlewares = [];
2577
2469
  executedOnceHandlers = /* @__PURE__ */ new Set();
2578
2470
  attachedEvents = /* @__PURE__ */ new Set();
2471
+ inFlight = /* @__PURE__ */ new Set();
2472
+ draining = false;
2579
2473
  loading = false;
2580
2474
  loadedHandlers = [];
2581
2475
  loadedMiddlewares = [];
@@ -2744,15 +2638,22 @@ var EventDispatcher = class {
2744
2638
  const handlerEntries = this.eventMap.get(eventName);
2745
2639
  this.logger.debug(`Attaching ${paint.mint.bold(eventName)} to the client with ${paint.mute(handlerEntries?.length ?? 0)} handler(s)`);
2746
2640
  this.core.bot.client.on(eventName, (...args) => {
2641
+ if (this.draining) return;
2747
2642
  this.core.bot.emitSafe("any:event", eventName, ...args);
2748
- (async () => {
2749
- await this.processEvent(eventName, args).catch((err) => {
2750
- this.logger.error(`[${paint.coral.bold("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
2751
- this.core.bot.emit("error:unhandled:event", err);
2752
- });
2753
- })();
2643
+ const run = this.processEvent(eventName, args).catch((err) => {
2644
+ this.logger.error(`[${paint.coral.bold("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
2645
+ this.core.bot.emit("error:unhandled:event", err);
2646
+ });
2647
+ this.inFlight.add(run);
2648
+ run.finally(() => this.inFlight.delete(run));
2754
2649
  });
2755
2650
  }
2651
+ stopAccepting() {
2652
+ this.draining = true;
2653
+ }
2654
+ drain(timeoutMs) {
2655
+ return settleWithin(Promise.allSettled(this.inFlight), timeoutMs);
2656
+ }
2756
2657
  async processEvent(eventName, args) {
2757
2658
  const handlerEntries = this.eventMap.get(eventName);
2758
2659
  if (!handlerEntries || handlerEntries.length === 0) return;
@@ -2878,7 +2779,6 @@ var InteractionDispatcher = class {
2878
2779
  core;
2879
2780
  logger = new Logger("Interactions");
2880
2781
  isInitialized = false;
2881
- name = "Interactions";
2882
2782
  slashMap = /* @__PURE__ */ new Map();
2883
2783
  buttonMap = /* @__PURE__ */ new Map();
2884
2784
  modalMap = /* @__PURE__ */ new Map();
@@ -2892,6 +2792,8 @@ var InteractionDispatcher = class {
2892
2792
  autocompleteMap = /* @__PURE__ */ new Map();
2893
2793
  keysToIgnore = /* @__PURE__ */ new Set();
2894
2794
  middlewares = [];
2795
+ inFlight = /* @__PURE__ */ new Set();
2796
+ draining = false;
2895
2797
  loading = false;
2896
2798
  loadedHandlers = [];
2897
2799
  loadedMiddlewares = [];
@@ -3092,13 +2994,22 @@ var InteractionDispatcher = class {
3092
2994
  }
3093
2995
  attachToClient() {
3094
2996
  this.core.bot.client.on(Events.InteractionCreate, (interaction) => {
2997
+ if (this.draining) return;
3095
2998
  this.core.bot.emitSafe("any:interaction", interaction);
3096
- this.handleInteraction(interaction).catch((err) => {
2999
+ const run = this.handleInteraction(interaction).catch((err) => {
3097
3000
  this.logger.error(`[${paint.coral.bold("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
3098
3001
  this.core.bot.emit("error:unhandled:interaction", err);
3099
3002
  });
3003
+ this.inFlight.add(run);
3004
+ run.finally(() => this.inFlight.delete(run));
3100
3005
  });
3101
3006
  }
3007
+ stopAccepting() {
3008
+ this.draining = true;
3009
+ }
3010
+ drain(timeoutMs) {
3011
+ return settleWithin(Promise.allSettled(this.inFlight), timeoutMs);
3012
+ }
3102
3013
  async handleCustomIdInteraction(interaction, getMap, interactionType) {
3103
3014
  if ([...this.keysToIgnore].some((matcher) => matcher.owns(interaction.customId))) return;
3104
3015
  const prefix = prefixOf(interaction.customId);
@@ -3226,23 +3137,25 @@ function __decorate(decorators, target, key, desc) {
3226
3137
 
3227
3138
  //#endregion
3228
3139
  //#region src/bot/Bot.ts
3140
+ const DISPATCH_DRAIN_TIMEOUT_MS = 5e3;
3141
+ const DRAIN_TASK_TIMEOUT_MS = 6e3;
3142
+ const UNBIND_TIMEOUT_MS = 2e3;
3143
+ const LOGOUT_TIMEOUT_MS = 2e3;
3229
3144
  /**
3230
- * Discord bot implementation that manages client and controllers
3231
- *
3232
- * Don't instantiate this class directly. Use `core.bot` instead.
3145
+ * The Discord client and its controllers. Access it through `core.bot`.
3233
3146
  */
3234
- var Bot = class extends Plugin {
3147
+ var Bot = class extends TypedEventEmitter {
3235
3148
  /** @internal */
3236
3149
  logger = new Logger("Bot");
3237
3150
  isInitialized = false;
3238
3151
  _client;
3239
3152
  interactions;
3240
3153
  events;
3241
- commands;
3242
3154
  emojiInjector;
3155
+ commands;
3243
3156
  emojis = Emojis;
3244
3157
  mentions = CommandMentions;
3245
- /** @internal For use in dev mode */
3158
+ /** @internal */
3246
3159
  async onHmr(event) {
3247
3160
  if (this.interactions) await this.interactions.onHmr(event);
3248
3161
  if (this.events) await this.events.onHmr(event);
@@ -3250,7 +3163,7 @@ var Bot = class extends Plugin {
3250
3163
  }
3251
3164
  /** @internal */
3252
3165
  constructor(core) {
3253
- super(core);
3166
+ super();
3254
3167
  this._client = new Client(core.config.bot.clientOptions);
3255
3168
  if (core.config.bot.interactions.path) this.interactions = new InteractionDispatcher(core);
3256
3169
  if (core.config.bot.events.path) this.events = new EventDispatcher(core);
@@ -3261,12 +3174,24 @@ var Bot = class extends Plugin {
3261
3174
  });
3262
3175
  }
3263
3176
  this.emojiInjector = new EmojiInjector(core);
3264
- core.shutdown.addTask(ShutdownPhase$1.DiscordCleanup, "stop-bot", async () => await this.stop(), 2e3);
3177
+ this.registerShutdownTasks(core);
3265
3178
  }
3266
- /**
3267
- * Initializes Discord client and all controllers
3268
- * @internal
3269
- */
3179
+ registerShutdownTasks(core) {
3180
+ core.shutdown.addTask(ShutdownPhase.Unbind, "stop-dispatch", () => {
3181
+ this.stopAccepting();
3182
+ return Promise.resolve();
3183
+ }, UNBIND_TIMEOUT_MS);
3184
+ core.shutdown.addTask(ShutdownPhase.Drain, "drain-dispatch", () => this.drain(), DRAIN_TASK_TIMEOUT_MS);
3185
+ core.shutdown.addTask(ShutdownPhase.Logout, "stop-bot", async () => await this.stop(), LOGOUT_TIMEOUT_MS);
3186
+ }
3187
+ stopAccepting() {
3188
+ this.interactions?.stopAccepting();
3189
+ this.events?.stopAccepting();
3190
+ }
3191
+ async drain() {
3192
+ await Promise.allSettled([this.interactions?.drain(DISPATCH_DRAIN_TIMEOUT_MS), this.events?.drain(DISPATCH_DRAIN_TIMEOUT_MS)]);
3193
+ }
3194
+ /** @internal */
3270
3195
  async init() {
3271
3196
  if (this.isInitialized) return;
3272
3197
  this.isInitialized = true;
@@ -3282,17 +3207,11 @@ var Bot = class extends Plugin {
3282
3207
  this.interactions?.warnUnhandledContextMenuRoutes(this.commands.contextMenuLeaves());
3283
3208
  }
3284
3209
  }
3285
- /**
3286
- * Stops the bot and cleans up connections
3287
- * @internal
3288
- */
3210
+ /** @internal */
3289
3211
  async stop() {
3290
3212
  this._client.removeAllListeners();
3291
3213
  await this.logout();
3292
3214
  }
3293
- /**
3294
- * Logs the bot into Discord using the configured token
3295
- */
3296
3215
  async login(token) {
3297
3216
  this._client.once(Events.ClientReady, () => this.emit("ready"));
3298
3217
  this._client.login(token);
@@ -3300,9 +3219,6 @@ var Bot = class extends Plugin {
3300
3219
  this.logger.info(`Logged in as ${chalk.bold.magenta(this._client.user?.username)}!`);
3301
3220
  return this;
3302
3221
  }
3303
- /**
3304
- * Logs out and destroys the Discord client connection
3305
- */
3306
3222
  async logout() {
3307
3223
  await this._client.destroy();
3308
3224
  this.logger.info(chalk.bold.red("Logged out of Discord!"));
@@ -3310,6 +3226,12 @@ var Bot = class extends Plugin {
3310
3226
  get client() {
3311
3227
  return this._client;
3312
3228
  }
3229
+ /**
3230
+ * The overloads enforce the key/args correlation at compile time only. At runtime this forwards
3231
+ * straight to the underlying TypedEventEmitter.
3232
+ *
3233
+ * @internal
3234
+ */
3313
3235
  emit(event, ...args) {
3314
3236
  return super.emit(event, ...args);
3315
3237
  }
@@ -3403,18 +3325,16 @@ var UnhandledErrorContainer = class extends BuilderComponent {
3403
3325
  * Registers and dispatches subscribers. Subscribers load from the configured directories and run
3404
3326
  * on a programmatic or framework-event publish. Accessed via `core.bus`. Do not construct it directly.
3405
3327
  */
3406
- var Bus = class extends Plugin {
3328
+ var Bus = class extends TypedEventEmitter {
3407
3329
  core;
3408
3330
  logger = new Logger("Subscribers");
3409
- /** @internal */
3410
- name = "Subscribers";
3411
3331
  isInitialized = false;
3412
3332
  subscribersMap = /* @__PURE__ */ new Map();
3413
3333
  executedOnceHandlers = /* @__PURE__ */ new Set();
3414
3334
  webhookProbes = /* @__PURE__ */ new Map();
3415
3335
  hmrHandler;
3416
3336
  constructor(core) {
3417
- super(core);
3337
+ super();
3418
3338
  this.core = core;
3419
3339
  if (this.core.config.subscribers.path) {
3420
3340
  if (!Envapter.isDevelopment && !Envapter.isTest) return;
@@ -3543,15 +3463,13 @@ var Bus = class extends Plugin {
3543
3463
  //#endregion
3544
3464
  //#region src/version.ts
3545
3465
  /** Package version */
3546
- const version = "0.1.0-next.3";
3466
+ const version = "0.1.0-next.4";
3547
3467
 
3548
3468
  //#endregion
3549
3469
  //#region src/Seedcord.ts
3550
3470
  /**
3551
- * Main Seedcord bot framework class
3552
- *
3553
- * Primary entry point for creating Discord bots with Seedcord.
3554
- * Manages component lifecycle and provides plugin support.
3471
+ * The gateway bot host. Opens a discord.js gateway session, discovers handlers, and runs
3472
+ * coordinated startup and shutdown. Attach plugins with `attach()`.
3555
3473
  */
3556
3474
  var Seedcord = class Seedcord extends Pluggable {
3557
3475
  config;
@@ -3561,7 +3479,6 @@ var Seedcord = class Seedcord extends Pluggable {
3561
3479
  augmentTarget = "@seedcord/gateway";
3562
3480
  /** @internal */
3563
3481
  version = version;
3564
- static isInstantiated = false;
3565
3482
  healthCheck;
3566
3483
  hmrManager;
3567
3484
  /** @see {@link CoordinatedShutdown} */
@@ -3575,15 +3492,11 @@ var Seedcord = class Seedcord extends Pluggable {
3575
3492
  /** @see {@link IRateLimiter} */
3576
3493
  rateLimiter;
3577
3494
  /**
3578
- * Creates a new Seedcord instance
3579
- *
3580
3495
  * @param config - Bot configuration including paths and Discord client options
3581
3496
  * @throws A **SeedcordError** When attempting to create multiple instances (singleton)
3582
3497
  */
3583
3498
  constructor(config) {
3584
- if (Seedcord.isInstantiated) throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);
3585
- Seedcord.isInstantiated = true;
3586
- const shutdown = new CoordinatedShutdown(config.shutdownEnabled);
3499
+ const shutdown = new CoordinatedShutdown();
3587
3500
  const startup = new CoordinatedStartup();
3588
3501
  super(shutdown, startup);
3589
3502
  this.config = config;
@@ -3596,46 +3509,60 @@ var Seedcord = class Seedcord extends Pluggable {
3596
3509
  this.bus = new Bus(this);
3597
3510
  this.bot = new Bot(this);
3598
3511
  this.rateLimiter = config.store ?? new MemoryRateLimiter();
3599
- this.healthCheck = new HealthCheck(this.shutdown, config.healthCheck);
3512
+ this.healthCheck = HealthCheck.fromOption(this.shutdown, config.healthCheck);
3600
3513
  this.registerStartupTasks();
3601
3514
  }
3602
3515
  /** The bot's discord username, populated after login. */
3603
3516
  get username() {
3604
3517
  return this.bot.client.user?.username;
3605
3518
  }
3519
+ pluginCapabilities() {
3520
+ return {
3521
+ client: this.bot.client,
3522
+ token: this.bot.botToken,
3523
+ rest: this.bot.client.rest
3524
+ };
3525
+ }
3606
3526
  static reset() {
3607
- Seedcord.isInstantiated = false;
3527
+ super.reset();
3608
3528
  LoggerChannelRegistry.instance.reset();
3609
3529
  }
3610
3530
  registerStartupTasks() {
3611
3531
  if (Envapter.isDevelopment || Envapter.isTest) this.registerHmrAwareModules();
3612
- this.startup.addTask(StartupPhase$1.Configuration, "Bus Initialization", async () => {
3532
+ this.startup.addTask(StartupPhase.Configuration, "Bus Initialization", async () => {
3613
3533
  this.bus.logger.utils.initialization("Subscribers", "start");
3614
3534
  await this.bus.init();
3615
3535
  this.bus.logger.utils.initialization("Subscribers", "end");
3616
3536
  });
3617
- this.startup.addTask(StartupPhase$1.Instantiation, "Bot Initialization", async () => {
3537
+ this.startup.addTask(StartupPhase.Login, "Bot Initialization", async () => {
3618
3538
  this.bot.logger.utils.initialization("Bot", "start");
3619
3539
  await this.bot.init();
3620
3540
  this.bot.logger.utils.initialization("Bot", "end");
3621
3541
  });
3622
- this.startup.addTask(StartupPhase$1.Ready, "Health Check", async () => {
3623
- this.healthCheck.logger.utils.initialization("HealthCheck", "start");
3624
- await this.healthCheck.init();
3625
- this.healthCheck.logger.utils.initialization("HealthCheck", "end");
3542
+ const { healthCheck } = this;
3543
+ if (healthCheck) this.startup.addTask(StartupPhase.Ready, "Health Check", async () => {
3544
+ healthCheck.logger.utils.initialization("HealthCheck", "start");
3545
+ await healthCheck.init();
3546
+ healthCheck.logger.utils.initialization("HealthCheck", "end");
3626
3547
  });
3627
3548
  }
3628
3549
  /**
3629
3550
  * Starts the bot and runs all initialization tasks
3630
3551
  *
3631
- * @returns This Seedcord instance when fully initialized
3552
+ * @returns This Seedcord instance when initialized
3632
3553
  */
3633
3554
  async start() {
3634
- await super.init();
3555
+ try {
3556
+ await super.init();
3557
+ } catch (caught) {
3558
+ await this.shutdown.run(1, false);
3559
+ Seedcord.reset();
3560
+ throw caught;
3561
+ }
3635
3562
  return this;
3636
3563
  }
3637
3564
  registerHmrAwareModules() {
3638
- this.startup.addTask(StartupPhase$1.Configuration, "HMR Registration", async () => {
3565
+ this.startup.addTask(StartupPhase.Configuration, "HMR Registration", async () => {
3639
3566
  this.hmrManager.register(this.bot);
3640
3567
  this.hmrManager.register(this.bus);
3641
3568
  for (const plugin of this.plugins) this.hmrManager.register(plugin);
@@ -3645,5 +3572,5 @@ var Seedcord = class Seedcord extends Pluggable {
3645
3572
  };
3646
3573
 
3647
3574
  //#endregion
3648
- export { ArraySource, AutocompleteHandler, ButtonHandler, CommandMentions, ContextMenuHandler, CursorSource, Emojis, EventHandler, EventMiddleware, Gated, IgnoreBots, InteractionHandler, InteractionMiddleware, Middleware, MiddlewareType, ModalHandler, Nsfw, Paginator, Pluggable, Plugin, RegisterEvent, RepliableHandler, Seedcord, SelectMenuHandler, ShutdownPhase, SlashHandler, StartupPhase, Subscribe, Subscriber, WebhookLog, WebhookUrl, checkBotPermissions, checkPermissions, fetchGuildMember, fetchManyGuildMembers, fetchManyUsers, fetchRole, fetchText, fetchUser, getBotRole, getConfirmation, hasPermsToAssign, updateMemberRoles, version };
3575
+ export { ArraySource, AutocompleteHandler, ButtonHandler, CommandMentions, ContextMenuHandler, CursorSource, Emojis, EventHandler, EventMiddleware, Gated, IgnoreBots, InteractionHandler, InteractionMiddleware, Middleware, MiddlewareType, ModalHandler, Nsfw, Paginator, RegisterEvent, RepliableHandler, Seedcord, SelectMenuHandler, SlashHandler, Subscribe, Subscriber, WebhookLog, WebhookUrl, checkBotPermissions, checkPermissions, fetchGuildMember, fetchManyGuildMembers, fetchManyUsers, fetchRole, fetchText, fetchUser, getBotRole, getConfirmation, hasPermsToAssign, updateMemberRoles, version };
3649
3576
  //# sourceMappingURL=index.mjs.map