seedcord 0.4.3 → 0.5.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.cts CHANGED
@@ -1,13 +1,16 @@
1
1
  import { Logger, CoordinatedShutdown, CoordinatedStartup, StartupPhase } from '@seedcord/services';
2
2
  export * from '@seedcord/services';
3
- import { ClientOptions, Guild, User, SlashCommandBuilder, ContextMenuCommandBuilder, Collection, Client, ChatInputCommandInteraction, ButtonInteraction, ModalSubmitInteraction, AutocompleteInteraction, AnySelectMenuInteraction, ContextMenuCommandInteraction, ClientEvents, Events, AutocompleteFocusedOption, EmbedBuilder, ButtonBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, UserSelectMenuBuilder, ChannelSelectMenuBuilder, MentionableSelectMenuBuilder, RoleSelectMenuBuilder, ModalBuilder, SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder, ContainerBuilder, TextDisplayBuilder, FileBuilder, MediaGalleryBuilder, SectionBuilder, SeparatorBuilder, ActionRowBuilder, TextInputBuilder, WebhookClient } from 'discord.js';
4
- import { Nullable, Tail, TypedConstructor, ConstructorFunction } from '@seedcord/types';
3
+ import { ClientOptions, Guild, User, SlashCommandBuilder, ContextMenuCommandBuilder, Collection, Client, ChatInputCommandInteraction, ButtonInteraction, ModalSubmitInteraction, AutocompleteInteraction, AnySelectMenuInteraction, ContextMenuCommandInteraction, ClientEvents, Events, AutocompleteFocusedOption, SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder, EmbedBuilder, ModalBuilder, LabelBuilder, TextInputBuilder, ButtonBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, UserSelectMenuBuilder, ChannelSelectMenuBuilder, MentionableSelectMenuBuilder, RoleSelectMenuBuilder, ContainerBuilder, TextDisplayBuilder, FileBuilder, MediaGalleryBuilder, SectionBuilder, SeparatorBuilder, ActionRowBuilder, ColorResolvable, Interaction, Role, TextChannel, TextChannelResolvable, MessageActionRowComponentBuilder, Message, GuildMember, Snowflake, WebhookClient } from 'discord.js';
4
+ import { Nullable, Tail, TypedConstructor, TypedExclude } from '@seedcord/types';
5
5
  export * from '@seedcord/types';
6
6
  import { UUID } from 'crypto';
7
+ import { Constructor, RequireAtLeastOne } from 'type-fest';
8
+ import { UUID as UUID$1 } from 'node:crypto';
7
9
  export * from '@seedcord/utils';
8
10
 
9
11
  /**
10
12
  * Djs Interactions handlers
13
+ *
11
14
  */
12
15
  interface InteractionsConfig {
13
16
  /**
@@ -15,6 +18,10 @@ interface InteractionsConfig {
15
18
  */
16
19
  path: string;
17
20
  ignoreCustomIds?: string[];
21
+ /**
22
+ * Optional path to interaction middleware directory
23
+ */
24
+ middlewares?: string;
18
25
  }
19
26
  /**
20
27
  * Djs Events handlers
@@ -24,6 +31,10 @@ interface EventsConfig {
24
31
  * Path to dir containing event handlers.
25
32
  */
26
33
  path: string;
34
+ /**
35
+ * Optional path to event middleware directory
36
+ */
37
+ middlewares?: string;
27
38
  }
28
39
  /**
29
40
  * Djs SlashCommands and ContextMenuCommands
@@ -63,6 +74,7 @@ interface BotConfig {
63
74
  *
64
75
  * @example
65
76
  * ```ts
77
+ * // This map's values...
66
78
  * const Emojis = {
67
79
  * ThumbsUp: 'thumbsup',
68
80
  * ThumbsDown: 'thumbsdown',
@@ -71,10 +83,9 @@ interface BotConfig {
71
83
  * };
72
84
  * ```
73
85
  *
74
- * will turn into
75
- *
76
86
  * @example
77
87
  * ```ts
88
+ * // ...turn into these Discord emojis
78
89
  * const Emojis = {
79
90
  * ThumbsUp: '<:thumbsup:1872389747982323423>',
80
91
  * ThumbsDown: '<:thumbsdown:1872389747982323424>',
@@ -107,6 +118,7 @@ interface DefaultEffects {
107
118
  error: Error;
108
119
  guild: Nullable<Guild>;
109
120
  user: Nullable<User>;
121
+ metadata?: unknown;
110
122
  };
111
123
  }
112
124
  /**
@@ -167,7 +179,10 @@ declare class EffectsRegistry extends Plugin {
167
179
  emit<KeyOfEffects extends EffectKeys>(event: KeyOfEffects, data: AllEffects[KeyOfEffects]): boolean;
168
180
  }
169
181
 
170
- /** Base interface defining core Seedcord functionality */
182
+ /** Base interface defining core Seedcord functionality
183
+ *
184
+ * @internal
185
+ */
171
186
  interface BaseCore {
172
187
  readonly bot: Bot;
173
188
  readonly effects: EffectsRegistry;
@@ -219,12 +234,12 @@ declare abstract class Plugin implements Initializeable {
219
234
  }
220
235
  /**
221
236
  * Constructor type for plugins that can accept additional arguments after Core
222
- * @param TPlugin - The plugin type being constructed
237
+ * @typeParam TPlugin - The plugin type being constructed
223
238
  */
224
239
  type PluginCtor<TPlugin extends Plugin = Plugin> = new (core: Core, ...args: any[]) => TPlugin;
225
240
  /**
226
241
  * Extracts the argument types for a plugin constructor (excluding the Core parameter)
227
- * @param Ctor - The plugin constructor to extract arguments from
242
+ * @typeParam Ctor - The plugin constructor to extract arguments from
228
243
  */
229
244
  type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;
230
245
  /**
@@ -300,10 +315,6 @@ declare class Bot extends Plugin {
300
315
  private readonly events;
301
316
  readonly commands: CommandRegistry;
302
317
  private readonly emojiInjector;
303
- /**
304
- * @param core - Seedcord core instance
305
- * @internal
306
- */
307
318
  constructor(core: Core);
308
319
  /**
309
320
  * Initializes Discord client and all controllers
@@ -385,6 +396,7 @@ interface Handler {
385
396
  * Should always accompany the `@Catchable` decorator. Will require the class to implement the `runChecks` method.
386
397
  *
387
398
  * @see {@link Checkable}
399
+ * @see {@link Catchable}
388
400
  */
389
401
  interface WithChecks {
390
402
  /**
@@ -396,8 +408,18 @@ interface WithChecks {
396
408
  */
397
409
  runChecks(): Promise<void>;
398
410
  }
411
+ /**
412
+ * Interface for handlers that implement pre-execution checks
413
+ *
414
+ * @internal
415
+ */
399
416
  interface HandlerWithChecks extends WithChecks, Handler {
400
417
  }
418
+ /**
419
+ * Base class for all handlers. Not meant to be used directly.
420
+ *
421
+ * @internal
422
+ */
401
423
  declare abstract class BaseHandler<ValidEvent extends ValidEventTypes> implements Handler {
402
424
  core: Core;
403
425
  protected checkable: boolean;
@@ -419,8 +441,8 @@ declare abstract class BaseHandler<ValidEvent extends ValidEventTypes> implement
419
441
  /**
420
442
  * Gets arguments parsed from interaction customId
421
443
  *
422
- * Arguments are extracted from customId using ":" and "-" separators.
423
- * For customId "accept:user123-guild456", returns ["user123", "guild456"]
444
+ * Arguments are extracted from customId using `:` and `-` separators.
445
+ * For customId `accept:user123-guild456`, returns `["user123", "guild456"]`
424
446
  */
425
447
  protected getArgs(): string[];
426
448
  /**
@@ -434,7 +456,7 @@ declare abstract class BaseHandler<ValidEvent extends ValidEventTypes> implement
434
456
  * Base class for Discord interaction handlers
435
457
  *
436
458
  * Extend this class to handle slash commands, buttons, modals, and select menus.
437
- * Use decorators like \@SlashRoute, \@ButtonRoute, etc. to define routing.
459
+ * Use decorators like `@SlashRoute`, `@ButtonRoute`, etc. to define routing.
438
460
  *
439
461
  * @typeParam Repliable - The interaction type this handler processes
440
462
  */
@@ -452,6 +474,14 @@ declare abstract class InteractionHandler<Repliable extends Repliables> extends
452
474
  declare abstract class InteractionMiddleware<Repliable extends Repliables> extends BaseHandler<Repliable> implements Handler {
453
475
  constructor(event: Repliable, core: Core, args?: string[]);
454
476
  }
477
+ /**
478
+ * Base class for Discord event middleware
479
+ *
480
+ * Middleware runs before event handlers and can modify behavior or block execution.
481
+ */
482
+ declare abstract class EventMiddleware<EventName extends keyof ClientEvents> extends BaseHandler<ClientEvents[EventName]> implements Handler {
483
+ constructor(event: ClientEvents[EventName], core: Core, args?: string[]);
484
+ }
455
485
  /**
456
486
  * Handler for Discord autocomplete interactions
457
487
  *
@@ -459,7 +489,7 @@ declare abstract class InteractionMiddleware<Repliable extends Repliables> exten
459
489
  * The focused option is automatically available via the `focused` property.
460
490
  */
461
491
  declare abstract class AutocompleteHandler extends BaseHandler<AutocompleteInteraction> implements Handler {
462
- /** The currently focused autocomplete option (Based on what you set in \@AutocompleteRoute) */
492
+ /** The currently focused autocomplete option (Based on what you set in `@AutocompleteRoute`) */
463
493
  protected readonly focused: AutocompleteFocusedOption;
464
494
  constructor(event: AutocompleteInteraction, core: Core, args?: string[]);
465
495
  }
@@ -467,7 +497,7 @@ declare abstract class AutocompleteHandler extends BaseHandler<AutocompleteInter
467
497
  * Base class for Discord client event handlers
468
498
  *
469
499
  * Extend this class to handle Discord events like messageCreate, guildMemberAdd, etc.
470
- * Use the \@EventRegisterable decorator to specify which event to listen for.
500
+ * Use the `EventRegisterable` decorator to specify which event to listen for.
471
501
  *
472
502
  * @typeParam Repliable - The Discord event type this handler processes
473
503
  */
@@ -477,12 +507,21 @@ declare abstract class EventHandler<Repliable extends keyof ClientEvents> extend
477
507
  /** Constructor type for interaction and autocomplete handlers */
478
508
  type HandlerConstructor = TypedConstructor<typeof InteractionHandler | typeof AutocompleteHandler>;
479
509
  /** Constructor type for interaction middleware */
480
- type MiddlewareConstructor = TypedConstructor<typeof InteractionMiddleware> & (new (event: Repliables, core: Core, args?: string[]) => InteractionMiddleware<Repliables>);
510
+ type InteractionMiddlewareConstructor = TypedConstructor<typeof InteractionMiddleware> & (new (event: Repliables, core: Core, args?: string[]) => InteractionMiddleware<Repliables>);
511
+ /** Constructor type for legacy interaction middleware */
512
+ type MiddlewareConstructor = InteractionMiddlewareConstructor;
513
+ /** Constructor type for event middleware */
514
+ type EventMiddlewareConstructor = TypedConstructor<typeof EventMiddleware> & (new <EventName extends keyof ClientEvents>(event: ClientEvents[EventName], core: Core, args?: string[]) => EventMiddleware<EventName>);
481
515
  /** Constructor type for autocomplete handlers */
482
516
  type AutocompleteHandlerConstructor = TypedConstructor<typeof AutocompleteHandler> & (new (event: AutocompleteInteraction, core: Core, args?: string[]) => AutocompleteHandler);
483
517
  /** Constructor type for Discord client event handlers */
484
518
  type EventHandlerConstructor = TypedConstructor<typeof EventHandler>;
485
519
 
520
+ /**
521
+ * Constructor type for handler classes.
522
+ *
523
+ * @internal
524
+ */
486
525
  type HandlerCtor = new (...args: any[]) => Handler;
487
526
  /**
488
527
  * Marks a handler class as requiring check execution.
@@ -490,12 +529,13 @@ type HandlerCtor = new (...args: any[]) => Handler;
490
529
  * Enables the runChecks() method to be called before execute()
491
530
  * for handlers that need pre-execution validation.
492
531
  *
493
- * @param ctor - The handler to mark as checkable (Do not pass this directly. Just call the decorator without a **()**)
532
+ * @typeParam TypeHandler - The type of the handler class being decorated
533
+ * @param ctor - The handler to mark as checkable (Do not pass this directly. Just call the decorator without a `()`)
494
534
  * @decorator
495
535
  * @example
496
536
  * ```typescript
497
537
  * \@Checkable
498
- * class AdminCommand extends InteractionHandler {
538
+ * class AdminCommand extends InteractionHandler implements WithChecks {
499
539
  * async runChecks() {
500
540
  * // Perform admin permission checks
501
541
  * }
@@ -508,9 +548,9 @@ declare function Checkable<TypeHandler extends HandlerCtor>(ctor: TypeHandler):
508
548
  * Configuration options for the Catchable decorator.
509
549
  */
510
550
  interface CatchableOptions {
511
- /** Whether to log errors to console (default: false) */
551
+ /** Whether to log errors to console (default: `false`) */
512
552
  log?: boolean;
513
- /** Always use followUp instead of reply/editReply (default: false) */
553
+ /** Always use followUp instead of reply/editReply (default: `false`) */
514
554
  forceFollowup?: boolean;
515
555
  }
516
556
  /**
@@ -533,9 +573,20 @@ interface CatchableOptions {
533
573
  */
534
574
  declare function Catchable(options?: CatchableOptions): (_target: RepliableInteractionHandler, _propertyKey: string, descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<void>>) => void;
535
575
 
576
+ /**
577
+ * Available Discord.js builder classes for use with BuilderComponent
578
+ *
579
+ * @internal
580
+ */
536
581
  declare const BuilderTypes: {
537
582
  command: typeof SlashCommandBuilder;
583
+ context_menu: typeof ContextMenuCommandBuilder;
584
+ subcommand: typeof SlashCommandSubcommandBuilder;
585
+ group: typeof SlashCommandSubcommandGroupBuilder;
538
586
  embed: typeof EmbedBuilder;
587
+ modal: typeof ModalBuilder;
588
+ label: typeof LabelBuilder;
589
+ text_input: typeof TextInputBuilder;
539
590
  button: typeof ButtonBuilder;
540
591
  menu_string: typeof StringSelectMenuBuilder;
541
592
  menu_option_string: typeof StringSelectMenuOptionBuilder;
@@ -543,10 +594,6 @@ declare const BuilderTypes: {
543
594
  menu_channel: typeof ChannelSelectMenuBuilder;
544
595
  menu_mentionable: typeof MentionableSelectMenuBuilder;
545
596
  menu_role: typeof RoleSelectMenuBuilder;
546
- modal: typeof ModalBuilder;
547
- context_menu: typeof ContextMenuCommandBuilder;
548
- subcommand: typeof SlashCommandSubcommandBuilder;
549
- group: typeof SlashCommandSubcommandGroupBuilder;
550
597
  container: typeof ContainerBuilder;
551
598
  text_display: typeof TextDisplayBuilder;
552
599
  file: typeof FileBuilder;
@@ -554,6 +601,11 @@ declare const BuilderTypes: {
554
601
  section: typeof SectionBuilder;
555
602
  separator: typeof SeparatorBuilder;
556
603
  };
604
+ /**
605
+ * Available Discord.js action row classes for use with RowComponent
606
+ *
607
+ * @internal
608
+ */
557
609
  declare const RowTypes: {
558
610
  button: typeof ActionRowBuilder<ButtonBuilder>;
559
611
  menu_string: typeof ActionRowBuilder<StringSelectMenuBuilder>;
@@ -561,23 +613,31 @@ declare const RowTypes: {
561
613
  menu_channel: typeof ActionRowBuilder<ChannelSelectMenuBuilder>;
562
614
  menu_mentionable: typeof ActionRowBuilder<MentionableSelectMenuBuilder>;
563
615
  menu_role: typeof ActionRowBuilder<RoleSelectMenuBuilder>;
564
- modal: typeof ActionRowBuilder<ModalActionRowComponentBuilder>;
565
- };
566
- declare const ModalTypes: {
567
- text: typeof TextInputBuilder;
568
616
  };
617
+ /**
618
+ * Available Discord.js builder types for use with BuilderComponent
619
+ */
569
620
  type BuilderType = keyof typeof BuilderTypes;
621
+ /**
622
+ * @internal
623
+ */
570
624
  type InstantiatedBuilder<BuilderKey extends BuilderType> = InstanceType<(typeof BuilderTypes)[BuilderKey]>;
625
+ /**
626
+ * Available Discord.js action row types for use with RowComponent
627
+ */
571
628
  type ActionRowComponentType = keyof typeof RowTypes;
629
+ /**
630
+ * @internal
631
+ */
572
632
  type InstantiatedActionRow<RowKey extends ActionRowComponentType> = InstanceType<(typeof RowTypes)[RowKey]>;
573
- type ModalFieldTypes = keyof typeof ModalTypes;
574
- type InstantiatedModalField<ModalKey extends ModalFieldTypes> = InstanceType<(typeof ModalTypes)[ModalKey]>;
575
633
  /**
576
634
  * Base class for Discord component wrappers
577
635
  *
578
636
  * Provides common functionality for building Discord components with proper typing.
579
637
  *
580
638
  * @typeParam TComponent - The Discord.js component type being wrapped
639
+ *
640
+ * @internal
581
641
  */
582
642
  declare abstract class BaseComponent<TComponent> {
583
643
  private readonly _component;
@@ -603,7 +663,7 @@ declare abstract class BaseComponent<TComponent> {
603
663
  /**
604
664
  * Builds a customId string for interactive components
605
665
  *
606
- * Creates customIds in the format "prefix:arg1-arg2-arg3" for buttons, modals, etc.
666
+ * Creates customIds in the format `prefix:arg1-arg2-arg3` for buttons, modals, etc.
607
667
  * Arguments are joined with hyphens and separated from prefix with a colon.
608
668
  *
609
669
  * @param prefix - The route prefix that handlers will match against
@@ -621,7 +681,13 @@ declare abstract class BaseComponent<TComponent> {
621
681
  * @typeParam BuilderKey - The type of Discord.js builder being wrapped
622
682
  */
623
683
  declare abstract class BuilderComponent<BuilderKey extends BuilderType> extends BaseComponent<InstantiatedBuilder<BuilderKey>> {
624
- private readonly botColor;
684
+ /**
685
+ * Bot color for the component
686
+ * Uses the DEFAULT_BOT_COLOR environment variable or falls back to 'Default' set by Discord.js.
687
+ *
688
+ * Set DEFAULT_BOT_COLOR to a hex code in your `.env` file to customize.
689
+ */
690
+ readonly botColor: ColorResolvable;
625
691
  protected constructor(type: BuilderKey);
626
692
  get component(): InstantiatedBuilder<BuilderKey>;
627
693
  }
@@ -636,18 +702,6 @@ declare abstract class RowComponent<RowKey extends ActionRowComponentType> exten
636
702
  protected constructor(type: RowKey);
637
703
  get component(): InstantiatedActionRow<RowKey>;
638
704
  }
639
- /**
640
- * Base class for modal field components
641
- *
642
- * Wraps Discord.js modal field builders (TextInputBuilder, etc.) and
643
- * packages them in action rows for use in modals.
644
- *
645
- * @typeParam ModalKey - The type of modal field builder being wrapped
646
- */
647
- declare abstract class ModalComponent<ModalKey extends ModalFieldTypes> extends BaseComponent<InstantiatedModalField<ModalKey>> {
648
- protected constructor(type: ModalKey);
649
- get component(): InstantiatedActionRow<'modal'>;
650
- }
651
705
  /**
652
706
  * Pre-configured error embed with default styling
653
707
  *
@@ -680,24 +734,36 @@ declare abstract class CustomError extends Error {
680
734
  get emit(): boolean;
681
735
  /**
682
736
  * Sets whether this error should be emitted to logs
683
- *
684
- * @see {@link emit}
685
737
  */
686
738
  set emit(value: boolean);
687
739
  }
688
740
  /** Constructor type for custom error classes */
689
741
  type CustomErrorConstructor = new (message: string, ...args: any[]) => CustomError;
690
742
 
743
+ /**
744
+ * Metadata key for command registration information.
745
+ *
746
+ * @internal
747
+ */
691
748
  declare const CommandMetadataKey: unique symbol;
749
+ /**
750
+ * Constructor type for command classes.
751
+ *
752
+ * @internal
753
+ */
692
754
  type CommandCtor = new (...args: any[]) => BuilderComponent<'command' | 'context_menu'>;
693
755
  /**
694
756
  * Metadata for global command registration.
757
+ *
758
+ * @internal
695
759
  */
696
760
  interface GlobalMeta {
697
761
  scope: 'global';
698
762
  }
699
763
  /**
700
764
  * Metadata for guild-specific command registration.
765
+ *
766
+ * @internal
701
767
  */
702
768
  interface GuildMeta {
703
769
  scope: 'guild';
@@ -705,8 +771,16 @@ interface GuildMeta {
705
771
  }
706
772
  /**
707
773
  * Union type for command registration metadata.
774
+ *
775
+ * @internal
708
776
  */
709
777
  type CommandMeta = GlobalMeta | GuildMeta;
778
+ /**
779
+ * Type representing command registration scope.
780
+ *
781
+ * @internal
782
+ */
783
+ type CommandScope = CommandMeta['scope'];
710
784
  /**
711
785
  * Registers a command for global deployment.
712
786
  *
@@ -743,7 +817,7 @@ declare function RegisterCommand(scope: 'guild', guilds: string[]): (ctor: Comma
743
817
  * Automatically handles errors in event handlers and sends error responses
744
818
  * if the event contains a Discord message object.
745
819
  *
746
- * @param log - Whether to log errors to console (default: false)
820
+ * @param log - Whether to log errors to console (default: `false`)
747
821
  * @decorator
748
822
  * @example
749
823
  * ```typescript
@@ -759,12 +833,13 @@ declare function EventCatchable(log?: boolean): (_target: EventHandler<keyof Cli
759
833
 
760
834
  declare const EventMetadataKey: unique symbol;
761
835
  /**
762
- * Registers an event handler class with a specific Discord.js event.
836
+ * Registers an event handler class with a one or multiple Discord.js event(s).
763
837
  *
764
- * Associates the decorated class with a Discord client event for automatic
838
+ * Associates the decorated class with the mentioned Discord client event(s) for automatic
765
839
  * registration and execution when the event is emitted.
766
840
  *
767
- * @param eventName - The Discord.js event name to listen for
841
+ * @typeParam KeyofEvents - The key of the Discord.js ClientEvents to register for
842
+ * @param events - The Discord.js event name(s) to listen for
768
843
  * @decorator
769
844
  * @example
770
845
  * ```typescript
@@ -775,9 +850,24 @@ declare const EventMetadataKey: unique symbol;
775
850
  * }
776
851
  * }
777
852
  * ```
853
+ *
854
+ * @example
855
+ * ```typescript
856
+ * \@RegisterEvent([Events.MessageCreate, Events.MessageUpdate])
857
+ * class MessageHandler extends EventHandler<Events.MessageCreate | Events.MessageUpdate> {
858
+ * async execute() {
859
+ * // Handle message creation or update
860
+ * }
861
+ * }
862
+ * ```
778
863
  */
779
- declare function RegisterEvent<KeyofEvents extends keyof ClientEvents>(eventName: KeyofEvents): (constructor: ConstructorFunction) => void;
864
+ declare function RegisterEvent<KeyofEvents extends keyof ClientEvents>(events: KeyofEvents | KeyofEvents[]): (constructor: Constructor<unknown>) => void;
780
865
 
866
+ /**
867
+ * Enum defining interaction route types for decorators
868
+ *
869
+ * @internal
870
+ */
781
871
  declare enum InteractionRoutes {
782
872
  Slash = "interaction:slash",
783
873
  Button = "interaction:button",
@@ -791,6 +881,9 @@ declare enum InteractionRoutes {
791
881
  UserContextMenu = "interaction:userContextMenu",
792
882
  Autocomplete = "interaction:autocomplete"
793
883
  }
884
+ /**
885
+ * Types of select menus supported for routing
886
+ */
794
887
  declare enum SelectMenuType {
795
888
  String = "string",
796
889
  User = "user",
@@ -798,6 +891,11 @@ declare enum SelectMenuType {
798
891
  Channel = "channel",
799
892
  Mentionable = "mentionable"
800
893
  }
894
+ /**
895
+ * Metadata key used to mark classes as interaction handlers
896
+ *
897
+ * @internal
898
+ */
801
899
  declare const InteractionMetadataKey: unique symbol;
802
900
  /**
803
901
  * Routes slash commands to handler classes
@@ -813,29 +911,36 @@ declare const InteractionMetadataKey: unique symbol;
813
911
  * class PingCommand extends InteractionHandler {
814
912
  * // handles /ping command
815
913
  * }
914
+ * ```
816
915
  *
916
+ * @example
917
+ * ```
817
918
  * \@SlashRoute(['ban', 'kick'])
818
919
  * class ModerationHandler extends InteractionHandler {
819
920
  * // handles /ban and /kick commands
820
921
  * }
922
+ * ```
821
923
  *
924
+ * @example
925
+ * ```
822
926
  * \@SlashRoute('admin/user/promote')
823
927
  * class PromoteHandler extends InteractionHandler {
824
928
  * // handles /admin user promote subcommand
825
929
  * }
826
930
  * ```
827
931
  */
828
- declare function SlashRoute(routeOrRoutes: string | string[]): (constructor: ConstructorFunction) => void;
932
+ declare function SlashRoute(routeOrRoutes: string | string[]): (constructor: Constructor<unknown>) => void;
829
933
  /**
830
934
  * Routes button interactions to handler classes
831
935
  *
832
936
  * Matches the customId prefix before the first colon.
833
- * For customId "accept:user123", use \@ButtonRoute("accept").
937
+ *
938
+ * For customId `accept:user123`, use `@ButtonRoute("accept")`.
834
939
  *
835
940
  * @param routeOrRoutes - CustomId prefix(es) to handle
836
941
  * @decorator
837
942
  */
838
- declare function ButtonRoute(routeOrRoutes: string | string[]): (constructor: ConstructorFunction) => void;
943
+ declare function ButtonRoute(routeOrRoutes: string | string[]): (constructor: Constructor<unknown>) => void;
839
944
  /**
840
945
  * Routes modal submissions to handler classes
841
946
  *
@@ -844,7 +949,7 @@ declare function ButtonRoute(routeOrRoutes: string | string[]): (constructor: Co
844
949
  * @param routeOrRoutes - CustomId prefix(es) to handle
845
950
  * @decorator
846
951
  */
847
- declare function ModalRoute(routeOrRoutes: string | string[]): (constructor: ConstructorFunction) => void;
952
+ declare function ModalRoute(routeOrRoutes: string | string[]): (constructor: Constructor<unknown>) => void;
848
953
  /**
849
954
  * Routes context menu commands to handler classes
850
955
  *
@@ -852,7 +957,7 @@ declare function ModalRoute(routeOrRoutes: string | string[]): (constructor: Con
852
957
  * @param routeOrRoutes - Command name(s) to handle
853
958
  * @decorator
854
959
  */
855
- declare function ContextMenuRoute(type: 'message' | 'user', routeOrRoutes: string | string[]): (constructor: ConstructorFunction) => void;
960
+ declare function ContextMenuRoute(type: 'message' | 'user', routeOrRoutes: string | string[]): (constructor: Constructor<unknown>) => void;
856
961
  /**
857
962
  * Routes autocomplete interactions to handler classes
858
963
  *
@@ -865,7 +970,7 @@ declare function ContextMenuRoute(type: 'message' | 'user', routeOrRoutes: strin
865
970
  * @example \@AutocompleteRoute(['user', 'profile'], ['name', 'bio']) // Multiple commands, multiple fields
866
971
  * @decorator
867
972
  */
868
- declare function AutocompleteRoute(commandRoutes: string | string[], focusedFields: string | string[]): (constructor: ConstructorFunction) => void;
973
+ declare function AutocompleteRoute(commandRoutes: string | string[], focusedFields: string | string[]): (constructor: Constructor<unknown>) => void;
869
974
  /**
870
975
  * Routes select menu interactions to handler classes
871
976
  *
@@ -873,9 +978,393 @@ declare function AutocompleteRoute(commandRoutes: string | string[], focusedFiel
873
978
  *
874
979
  * @param type - Select menu type from {@link SelectMenuType}
875
980
  * @param routeOrRoutes - CustomId prefix(es) to handle
981
+ *
982
+ * @decorator
983
+ *
984
+ * @example
985
+ * ```typescript
986
+ * \@SelectMenuRoute(SelectMenuType.String, 'fruits')
987
+ * class RoleSelectHandler extends InteractionHandler {
988
+ * // handles string select menus with customId starting with 'fruits'
989
+ * }
990
+ * ```
991
+ */
992
+ declare function SelectMenuRoute(type: SelectMenuType, routeOrRoutes: string | string[]): (constructor: Constructor<unknown>) => void;
993
+
994
+ /**
995
+ * Middleware types supported by Seedcord
996
+ */
997
+ declare enum MiddlewareType {
998
+ Interaction = "middleware:interaction",
999
+ Event = "middleware:event"
1000
+ }
1001
+ /**
1002
+ * Metadata key for middleware configuration
1003
+ *
1004
+ * @internal
1005
+ */
1006
+ declare const MiddlewareMetadataKey: unique symbol;
1007
+ /**
1008
+ * Additional middleware registration options
1009
+ */
1010
+ interface MiddlewareOptions {
1011
+ /**
1012
+ * Restrict event middleware execution to specific Discord client events
1013
+ */
1014
+ readonly events?: readonly (keyof ClientEvents)[];
1015
+ }
1016
+ /**
1017
+ * Metadata stored for middleware registration
1018
+ */
1019
+ interface MiddlewareMetadata {
1020
+ /**
1021
+ * Priority number used to order middleware
1022
+ */
1023
+ priority: number;
1024
+ /**
1025
+ * Middleware kind from {@link MiddlewareType}
1026
+ */
1027
+ type: MiddlewareType;
1028
+ /**
1029
+ * Optional list of Discord client events to target
1030
+ */
1031
+ events?: readonly (keyof ClientEvents)[];
1032
+ }
1033
+ /**
1034
+ * Decorator used to register middleware with priority ordering. The lower the priority number, the earlier it runs.
1035
+ *
1036
+ * Interaction middleware cannot specify event filters.
1037
+ *
1038
+ * @param type - Middleware kind from {@link MiddlewareType}
1039
+ * @param priority - Ordering value where lower runs earlier. Default is 0
1040
+ * @param options - Additional registration options
1041
+ *
876
1042
  * @decorator
1043
+ *
1044
+ * @example
1045
+ * ```ts
1046
+ * \@Middleware(MiddlewareType.Event, 10, { events: [Events.MessageCreate, Events.MessageUpdate] })
1047
+ * class MyEventMiddleware extends EventMiddleware {}
1048
+ * ```
1049
+ * @throws A {@link TypeError} If priority is not a finite number
1050
+ * @throws An {@link Error} If interaction middleware specifies event filters
1051
+ */
1052
+ declare function Middleware(type: MiddlewareType, priority?: number, options?: MiddlewareOptions): ClassDecorator;
1053
+
1054
+ /**
1055
+ * Manages Discord event handler registration and execution.
1056
+ *
1057
+ * Scans event handler directories, registers handlers with Discord client events,
1058
+ * and coordinates event execution through the handler system. Does not handle interactions.
1059
+ *
1060
+ * Multiple handlers can point to one event.
1061
+ *
1062
+ * @internal
877
1063
  */
878
- declare function SelectMenuRoute(type: SelectMenuType, routeOrRoutes: string | string[]): (constructor: ConstructorFunction) => void;
1064
+ declare class EventController implements Initializeable {
1065
+ protected core: Core;
1066
+ private readonly logger;
1067
+ private isInitialized;
1068
+ private readonly eventMap;
1069
+ private readonly middlewares;
1070
+ constructor(core: Core);
1071
+ init(): Promise<void>;
1072
+ private loadHandlers;
1073
+ private loadMiddlewares;
1074
+ private registerMiddleware;
1075
+ private runMiddlewares;
1076
+ private isEventHandlerClass;
1077
+ private isMiddlewareClass;
1078
+ private registerHandler;
1079
+ private attachToClient;
1080
+ private processEvent;
1081
+ }
1082
+
1083
+ /**
1084
+ * Manages Discord interaction handling and routing.
1085
+ *
1086
+ * Scans handler directories, registers handlers with Discord client events,
1087
+ * and coordinates event execution through the handler system. Only handles interactions.
1088
+ *
1089
+ * Enforces that there is only one handler per interaction.
1090
+ *
1091
+ * @internal
1092
+ */
1093
+ declare class InteractionController implements Initializeable {
1094
+ protected core: Core;
1095
+ private readonly logger;
1096
+ private isInitialized;
1097
+ private readonly slashMap;
1098
+ private readonly buttonMap;
1099
+ private readonly modalMap;
1100
+ private readonly stringSelectMap;
1101
+ private readonly userSelectMap;
1102
+ private readonly roleSelectMap;
1103
+ private readonly channelSelectMap;
1104
+ private readonly mentionableSelectMap;
1105
+ private readonly messageContextMenuMap;
1106
+ private readonly userContextMenuMap;
1107
+ private readonly autocompleteMap;
1108
+ private readonly keysToIgnore;
1109
+ private readonly middlewares;
1110
+ constructor(core: Core);
1111
+ init(): Promise<void>;
1112
+ private loadHandlers;
1113
+ private loadMiddlewares;
1114
+ private registerMiddleware;
1115
+ private isHandlerClass;
1116
+ private isMiddlewareClass;
1117
+ private registerHandler;
1118
+ private attachToClient;
1119
+ private parseCustomId;
1120
+ private handleCustomIdInteraction;
1121
+ processInteraction<TInteraction extends Interaction>(interaction: TInteraction, extractKey: (i: TInteraction) => string, getHandler: (key: string) => HandlerConstructor | undefined, args?: string[]): Promise<void>;
1122
+ private handleInteraction;
1123
+ private handleSlashCommand;
1124
+ private handleButton;
1125
+ private handleModal;
1126
+ private handleStringSelectMenu;
1127
+ private handleUserSelectMenu;
1128
+ private handleRoleSelectMenu;
1129
+ private handleChannelSelectMenu;
1130
+ private handleMentionableSelectMenu;
1131
+ private handleMessageContextMenu;
1132
+ private handleUserContextMenu;
1133
+ private handleAutocomplete;
1134
+ }
1135
+
1136
+ /**
1137
+ * Error thrown when a requested channel cannot be found.
1138
+ */
1139
+ declare class ChannelNotFoundError extends CustomError {
1140
+ readonly channelId: string;
1141
+ /**
1142
+ * Creates a new ChannelNotFoundError.
1143
+ *
1144
+ * @param message - The error message
1145
+ * @param channelId - The ID of the channel that could not be found
1146
+ */
1147
+ constructor(message: string, channelId: string);
1148
+ }
1149
+ /**
1150
+ * Error thrown when the bot cannot send embeds in a channel.
1151
+ */
1152
+ declare class CannotSendEmbedsError extends CustomError {
1153
+ readonly channelId: string;
1154
+ /**
1155
+ * Creates a new CannotSendEmbedsError.
1156
+ *
1157
+ * @param message - The error message
1158
+ * @param channelId - The ID of the channel where embeds cannot be sent
1159
+ */
1160
+ constructor(message: string, channelId: string);
1161
+ }
1162
+ /**
1163
+ * Error thrown when a channel could not be found or accessed.
1164
+ */
1165
+ declare class CouldNotFindChannel extends CustomError {
1166
+ readonly channelId: string;
1167
+ /**
1168
+ * Creates a new CouldNotFindChannel error.
1169
+ *
1170
+ * @param message - The error message
1171
+ * @param channelId - The ID of the channel that could not be found
1172
+ */
1173
+ constructor(message: string, channelId: string);
1174
+ }
1175
+ /**
1176
+ * Error thrown when a channel is not a text channel.
1177
+ */
1178
+ declare class ChannelNotTextChannel extends CustomError {
1179
+ readonly channelId: string;
1180
+ /**
1181
+ * Creates a new ChannelNotTextChannel error.
1182
+ *
1183
+ * @param message - The error message
1184
+ * @param channelId - The ID of the channel that is not a text channel
1185
+ */
1186
+ constructor(message: string, channelId: string);
1187
+ }
1188
+
1189
+ /**
1190
+ * Generic database operation error with UUID tracking.
1191
+ *
1192
+ * Thrown for various database operation failures and includes
1193
+ * a UUID for error tracking and debugging purposes.
1194
+ */
1195
+ declare class DatabaseError extends CustomError {
1196
+ uuid: UUID;
1197
+ /**
1198
+ * Creates a new DatabaseError.
1199
+ *
1200
+ * @param message - The error message describing what went wrong
1201
+ * @param uuid - A unique identifier for this specific error instance
1202
+ */
1203
+ constructor(message: string, uuid: UUID);
1204
+ }
1205
+
1206
+ /**
1207
+ * Error thrown when the bot lacks necessary permissions to perform an action.
1208
+ */
1209
+ declare class MissingPermissions extends CustomError {
1210
+ missingPerms: string[];
1211
+ roleOrChannel: Role | TextChannel;
1212
+ /**
1213
+ * Creates a new BotMissingPermissionsError.
1214
+ *
1215
+ * @param message - The error message
1216
+ * @param missingPerms - Array of missing permission names
1217
+ * @param roleOrChannel - The role or channel where permissions are missing
1218
+ */
1219
+ constructor(message: string, missingPerms: string[], roleOrChannel: Role | TextChannel);
1220
+ }
1221
+ /**
1222
+ * Error thrown when attempting to modify a role higher than the bot's highest role.
1223
+ */
1224
+ declare class RoleHigherThanMe extends CustomError {
1225
+ role: Role;
1226
+ botRole: Role;
1227
+ /**
1228
+ * Creates a new RoleHigherThanMe error.
1229
+ *
1230
+ * @param message - The error message
1231
+ */
1232
+ constructor(message: string, role: Role, botRole: Role);
1233
+ }
1234
+ /**
1235
+ * Error thrown when attempting to assign a managed/bot role.
1236
+ */
1237
+ declare class CannotAssignBotRole extends CustomError {
1238
+ /**
1239
+ * Creates a new CannotAssignBotRole error.
1240
+ *
1241
+ * @param message - The error message
1242
+ */
1243
+ constructor(message?: string);
1244
+ }
1245
+ /**
1246
+ * Error thrown when a requested role does not exist.
1247
+ */
1248
+ declare class RoleDoesNotExist extends CustomError {
1249
+ roleId: string;
1250
+ /**
1251
+ * Creates a new RoleDoesNotExist error.
1252
+ *
1253
+ * @param message - The error message
1254
+ * @param roleId - The ID of the role that doesn't exist
1255
+ */
1256
+ constructor(message: string, roleId: string);
1257
+ }
1258
+ /**
1259
+ * Error thrown when a role has dangerous permissions that shouldn't be assigned.
1260
+ */
1261
+ declare class HasDangerousPermissions extends CustomError {
1262
+ role: Role;
1263
+ dangerousPerms: string[];
1264
+ /**
1265
+ * Creates a new HasDangerousPermissions error.
1266
+ *
1267
+ * @param message - The error message
1268
+ * @param role - The role with dangerous permissions
1269
+ * @param dangerousPerms - Array of dangerous permission names
1270
+ */
1271
+ constructor(message: string, role: Role, dangerousPerms: string[]);
1272
+ }
1273
+
1274
+ /**
1275
+ * Error thrown when attempting to perform actions on a user not in the guild.
1276
+ */
1277
+ declare class UserNotInGuild extends CustomError {
1278
+ /**
1279
+ * Creates a new UserNotInGuild error.
1280
+ *
1281
+ * @param message - The error message
1282
+ */
1283
+ constructor(message?: string);
1284
+ }
1285
+ /**
1286
+ * Error thrown when a requested user cannot be found.
1287
+ */
1288
+ declare class UserNotFound extends CustomError {
1289
+ readonly userArg: string;
1290
+ /**
1291
+ * Creates a new UserNotFound error.
1292
+ *
1293
+ * @param userArg - The user argument that could not be resolved
1294
+ */
1295
+ constructor(userArg: string);
1296
+ }
1297
+
1298
+ declare class EmojiInjector {
1299
+ private readonly core;
1300
+ private readonly logger;
1301
+ constructor(core: Core);
1302
+ init(): Promise<void>;
1303
+ }
1304
+
1305
+ /**
1306
+ * Fetches and validates a text channel.
1307
+ *
1308
+ * @param client - The Discord client instance
1309
+ * @param channelId - Channel ID or TextChannel instance
1310
+ * @returns Promise resolving to the text channel
1311
+ * @throws A {@link CouldNotFindChannel} When the channel doesn't exist or isn't text-based
1312
+ */
1313
+ declare function fetchText(client: Client, channelId: TextChannelResolvable): Promise<TextChannel>;
1314
+
1315
+ /** Discord message content with embeds and components */
1316
+ interface MessageContent {
1317
+ embeds: EmbedBuilder[];
1318
+ components: [ActionRowBuilder<MessageActionRowComponentBuilder>];
1319
+ }
1320
+ /** Discord message that requires at least one of content, embeds, or components */
1321
+ type AtleastOneMessageComponent = RequireAtLeastOne<{
1322
+ content: string;
1323
+ } & MessageContent>;
1324
+
1325
+ /**
1326
+ * Sends a message to a text channel by ID.
1327
+ *
1328
+ * @param client - The Discord client instance
1329
+ * @param channelId - Channel ID or TextChannel instance
1330
+ * @param message - Message content to send
1331
+ * @returns Promise resolving to the sent message
1332
+ * @throws A {@link CouldNotFindChannel} When the channel doesn't exist or isn't text-based
1333
+ */
1334
+ declare function sendInText(client: Client, channelId: TextChannelResolvable, message: AtleastOneMessageComponent): Promise<Message>;
1335
+
1336
+ /**
1337
+ * Structure representing the extracted error response.
1338
+ */
1339
+ interface ExtractedErrorResponse {
1340
+ /** The unique identifier for the error instance */
1341
+ uuid: UUID$1;
1342
+ /** The formatted error response to be sent to the user */
1343
+ response: EmbedBuilder;
1344
+ }
1345
+ /**
1346
+ * Processes an error and extracts the standardized response, if available (else returns a {@link GenericError}).
1347
+ *
1348
+ * Handles different error types (CustomError, DatabaseError) with appropriate
1349
+ * logging, side effects, and user-facing error messages.
1350
+ *
1351
+ * @param error - The error to process
1352
+ * @param core - The core framework instance
1353
+ * @param guild - The guild where the error occurred (if any)
1354
+ * @param user - The user who triggered the error (if any)
1355
+ * @returns Object containing UUID and formatted error response embed
1356
+ */
1357
+ declare function extractErrorResponse(error: Error, core: Core, guild: Nullable<Guild>, user: Nullable<User>, metadata?: unknown): ExtractedErrorResponse;
1358
+ /**
1359
+ * Generic error shown to users when an unknown error occurs
1360
+ *
1361
+ * Set an environment variable called `DEVELOPER_DISCORD_USERNAME` in your `.env` file to customize the contact name.
1362
+ */
1363
+ declare class GenericError extends CustomError {
1364
+ private readonly uuid;
1365
+ private readonly developerUsername;
1366
+ constructor(uuid: UUID$1);
1367
+ }
879
1368
 
880
1369
  /**
881
1370
  * Throws a custom error with a formatted message and optional UUID.
@@ -883,7 +1372,7 @@ declare function SelectMenuRoute(type: SelectMenuType, routeOrRoutes: string | s
883
1372
  * Wraps an unknown error in a {@link CustomError} subclass. If the error class
884
1373
  * is {@link DatabaseError}, a UUID is generated and passed to the constructor.
885
1374
  *
886
- * @typeParam T - A constructor for a {@link CustomError} subclass
1375
+ * @typeParam Ctor - A constructor for a {@link CustomError} subclass
887
1376
  * @param error - The original error or value
888
1377
  * @param message - Custom message to include
889
1378
  * @param CustomError - Error class to instantiate and throw
@@ -900,6 +1389,171 @@ declare function SelectMenuRoute(type: SelectMenuType, routeOrRoutes: string | s
900
1389
  */
901
1390
  declare function throwCustomError<Ctor extends CustomErrorConstructor>(error: unknown, message: string, CustomError: Ctor): never;
902
1391
 
1392
+ /**
1393
+ * Sends a direct message to a user.
1394
+ *
1395
+ * @param user - The user to send the DM to
1396
+ * @param content - Message content with embeds, components, etc.
1397
+ * @returns Promise resolving to the sent message, or null if DM failed
1398
+ */
1399
+ declare function attemptSendDM(user: User, content: AtleastOneMessageComponent): Promise<Nullable<Message>>;
1400
+
1401
+ /**
1402
+ * Route string computed from provided parts.
1403
+ *
1404
+ * @typeParam Cmmd - Main command name
1405
+ * @typeParam Subc - Subcommand name
1406
+ * @typeParam Grp - Group name (will be ignored if subcommand is not provided with it)
1407
+ */
1408
+ type CommandRouteString<Cmmd extends string, Subc extends string | undefined, Grp extends string | undefined> = Subc extends string ? (Grp extends string ? `${Cmmd}/${Grp}/${Subc}` : `${Cmmd}/${Subc}`) : Cmmd;
1409
+ /**
1410
+ * From provided positional arguments. Either provide the route to either {@link SlashRoute} or {@link AutocompleteRoute} manually, or use this utility to build it.
1411
+ *
1412
+ * @param command - Main command name
1413
+ * @param subcommand - Optional subcommand name
1414
+ * @param group - Optional group name (will be ignored if subcommand is not provided with it)
1415
+ */
1416
+ declare function buildSlashRoute<Cmmd extends string, Subc extends string | undefined = undefined, Grp extends string | undefined = undefined>(command: Cmmd, subcommand?: Subc, group?: Grp): CommandRouteString<Cmmd, Subc, Grp>;
1417
+ /**
1418
+ * From a Discord interaction. The {@link InteractionController} uses this internally to build the route string to then route the correct handler.
1419
+ *
1420
+ * @internal
1421
+ */
1422
+ declare function buildSlashRoute(interaction: ChatInputCommandInteraction | AutocompleteInteraction): string;
1423
+
1424
+ /**
1425
+ * Map of permission bits to their prettified human-readable names.
1426
+ */
1427
+ declare const PermissionNames: Map<bigint, string>;
1428
+ /**
1429
+ * Defines the scope types for bot permission validation.
1430
+ */
1431
+ type BotPermissionScope = 'manage' | 'others' | 'all' | bigint[] | 'embed';
1432
+ /**
1433
+ * Defines the valid group types for permission checking, excluding 'all' and bigint[].
1434
+ */
1435
+ type BotPermissionScopeGroups = TypedExclude<BotPermissionScope, 'all' | bigint[]>;
1436
+ /**
1437
+ * Predefined permission groups for different scopes.
1438
+ */
1439
+ declare const PERM_GROUPS: Record<BotPermissionScopeGroups, Map<bigint, string>>;
1440
+ /**
1441
+ * Checks permissions for a {@link Role}.
1442
+ *
1443
+ * @param client - The Discord client instance
1444
+ * @param roleOrChannel - Role to check permissions for
1445
+ * @param scope - Permission scope to validate
1446
+ * @param inverse - Whether to check for absence of permissions (role only). Defaults to false.
1447
+ * @throws A {@link MissingPermissions} When required permissions are missing
1448
+ * @throws A {@link HasDangerousPermissions} When role has dangerous permissions (if inverse is true)
1449
+ */
1450
+ declare function checkPermissions(client: Client, roleOrChannel: Role, scope: BotPermissionScope, inverse?: boolean): void;
1451
+ /**
1452
+ * Checks permissions for a {@link TextChannel}.
1453
+ *
1454
+ * @param client - The Discord client instance
1455
+ * @param roleOrChannel - TextChannel to check permissions for
1456
+ * @param scope - Permission scope to validate
1457
+ * @throws A {@link MissingPermissions} When required permissions are missing
1458
+ */
1459
+ declare function checkPermissions(client: Client, roleOrChannel: TextChannel, scope?: BotPermissionScope): void;
1460
+
1461
+ /**
1462
+ * Checks if the bot has required permissions in a guild or channel.
1463
+ *
1464
+ * @param client - The Discord client instance
1465
+ * @param guildOrChannel - Guild or text channel to check permissions in
1466
+ * @param scope - Permission scope to validate
1467
+ * @param inverse - Whether to check for absence of permissions
1468
+ * @throws A {@link MissingPermissions} When bot lacks required permissions
1469
+ */
1470
+ declare function checkBotPermissions(client: Client, guildOrChannel: Guild | TextChannel, scope?: BotPermissionScope, inverse?: boolean): void;
1471
+
1472
+ /**
1473
+ * Fetches a role by ID from a client or guild.
1474
+ *
1475
+ * @param clientOrGuild - Discord client or guild instance
1476
+ * @param roleId - The role ID to fetch
1477
+ * @returns Promise resolving to the role
1478
+ * @throws A {@link RoleDoesNotExist} When the role doesn't exist
1479
+ */
1480
+ declare function fetchRole(clientOrGuild: Client | Guild, roleId: string): Promise<Role>;
1481
+
1482
+ /**
1483
+ * Gets the bot's highest role in a guild.
1484
+ *
1485
+ * @param client - The Discord client instance
1486
+ * @param guild - The guild to get the bot's role from
1487
+ * @returns The bot's highest role in the guild
1488
+ * @throws An {@link Error} When the bot is not in the guild
1489
+ */
1490
+ declare function getBotRole(client: Client, guild: Guild): Role;
1491
+
1492
+ /**
1493
+ * Validates if the bot has permission to assign a target role.
1494
+ *
1495
+ * @param targetRole - The role to check assignment permissions for
1496
+ * @throws A {@link RoleHigherThanMe} When the target role is higher than bot's role
1497
+ * @throws A {@link CannotAssignBotRole} When trying to assign a managed/bot role
1498
+ * @throws A {@link MissingPermissions} When bot lacks Manage Roles permission
1499
+ */
1500
+ declare function hasPermsToAssign(targetRole: Role): void;
1501
+
1502
+ /**
1503
+ * Fetches a guild member by user ID with error handling.
1504
+ *
1505
+ * @param guild - The guild to fetch the member from
1506
+ * @param userId - The Discord user ID
1507
+ * @returns Promise resolving to the guild member
1508
+ * @throws A {@link UserNotInGuild} When the user is not found in the guild
1509
+ */
1510
+ declare function fetchGuildMember(guild: Guild, userId: string): Promise<GuildMember>;
1511
+
1512
+ /**
1513
+ * Fetches multiple guild members by user IDs.
1514
+ *
1515
+ * @param guild - The guild to fetch members from
1516
+ * @param userIds - Array of Discord user IDs
1517
+ * @returns Promise resolving to array of successfully fetched members
1518
+ */
1519
+ declare function fetchManyGuildMembers(guild: Guild, userIds: string[]): Promise<GuildMember[]>;
1520
+
1521
+ /**
1522
+ * Fetches multiple Discord users by IDs.
1523
+ *
1524
+ * @param client - The Discord client instance
1525
+ * @param userIds - Array of Discord user IDs
1526
+ * @returns Promise resolving to array of successfully fetched users
1527
+ */
1528
+ declare function fetchManyUsers(client: Client, userIds: string[]): Promise<User[]>;
1529
+
1530
+ /**
1531
+ * Fetches a Discord user by ID with error handling.
1532
+ *
1533
+ * @param client - The Discord client instance
1534
+ * @param userId - The Discord user ID
1535
+ * @returns Promise resolving to the user
1536
+ * @throws A {@link UserNotFound} When the user doesn't exist
1537
+ */
1538
+ declare function fetchUser(client: Client, userId: string): Promise<User>;
1539
+
1540
+ /**
1541
+ * Updates a guild member's roles by adding and removing specified roles.
1542
+ *
1543
+ * @param rolesToAdd - Array of role IDs to add to the member
1544
+ * @param rolesToRemove - Array of role IDs to remove from the member
1545
+ * @param member - The guild member to update
1546
+ * @returns Promise that resolves when roles are updated
1547
+ */
1548
+ declare function updateMemberRoles(rolesToAdd: Snowflake[], rolesToRemove: Snowflake[], member: GuildMember): Promise<void>;
1549
+
1550
+ /**
1551
+ * Default handler for unhandled interaction.
1552
+ */
1553
+ declare class UnhandledEvent extends InteractionHandler<Repliables> {
1554
+ execute(): Promise<void>;
1555
+ }
1556
+
903
1557
  /**
904
1558
  * Type-safe event emitter for application effects.
905
1559
  *
@@ -907,6 +1561,8 @@ declare function throwCustomError<Ctor extends CustomErrorConstructor>(error: un
907
1561
  * for Seedcord's effect system.
908
1562
  *
909
1563
  * @typeParam AllEffects - Side effect definitions mapping event names to data types
1564
+ *
1565
+ * @internal
910
1566
  */
911
1567
  declare class EffectsEmitter {
912
1568
  private readonly emitter;
@@ -939,6 +1595,11 @@ declare class EffectsEmitter {
939
1595
  emit<KeyOfEffects extends EffectKeys>(event: KeyOfEffects, data: AllEffects[KeyOfEffects]): boolean;
940
1596
  }
941
1597
 
1598
+ /**
1599
+ * Metadata key used to store effect handler information
1600
+ *
1601
+ * @internal
1602
+ */
942
1603
  declare const EffectMetadataKey: unique symbol;
943
1604
  /**
944
1605
  * Registers a side effect handler class with a specific side effect event.
@@ -946,6 +1607,7 @@ declare const EffectMetadataKey: unique symbol;
946
1607
  * Associates the decorated class with a side effect event type for automatic
947
1608
  * registration and execution when the side effect is emitted.
948
1609
  *
1610
+ * @typeParam TEffect - The side effect event name to register for
949
1611
  * @param effect - The side effect event name to register for
950
1612
  * @decorator
951
1613
  * @example
@@ -958,7 +1620,7 @@ declare const EffectMetadataKey: unique symbol;
958
1620
  * }
959
1621
  * ```
960
1622
  */
961
- declare function RegisterEffect<TEffect extends EffectKeys>(effect: TEffect): (constructor: ConstructorFunction) => void;
1623
+ declare function RegisterEffect<TEffect extends EffectKeys>(effect: TEffect): (constructor: Constructor<unknown>) => void;
962
1624
 
963
1625
  /**
964
1626
  * Abstract base class for handling application side effects.
@@ -1000,20 +1662,24 @@ declare abstract class WebhookLog<KeyOfEffects extends EffectKeys> extends Effec
1000
1662
  }
1001
1663
 
1002
1664
  /**
1003
- * Generic database operation error with UUID tracking.
1665
+ * Default effect to log unhandled exceptions via webhook. It provides basic information about the error:
1666
+ * - Error stack trace
1667
+ * - Guild ID and name (if applicable)
1668
+ * - User ID and username (if applicable)
1669
+ * - A unique UUID for tracking
1670
+ * - Timestamps comparing interaction time and error log time (if applicable)
1671
+ * - Metadata associated with the error (if provided)
1004
1672
  *
1005
- * Thrown for various database operation failures and includes
1006
- * a UUID for error tracking and debugging purposes.
1673
+ * Developers need to set the UNKNOWN_EXCEPTION_WEBHOOK_URL environment variable in their .env file otherwise this effect will throw an error during initialization.
1674
+ *
1675
+ * @throws Error if UNKNOWN_EXCEPTION_WEBHOOK_URL is not set or is invalid
1007
1676
  */
1008
- declare class DatabaseError extends CustomError {
1009
- uuid: UUID;
1010
- /**
1011
- * Creates a new DatabaseError.
1012
- *
1013
- * @param message - The error message describing what went wrong
1014
- * @param uuid - A unique identifier for this specific error instance
1015
- */
1016
- constructor(message: string, uuid: UUID);
1677
+ declare class UnknownException extends WebhookLog<'unknownException'> {
1678
+ private static readonly logger;
1679
+ static readonly unknownExceptionWebhookUrl: string;
1680
+ webhook: WebhookClient;
1681
+ execute(): Promise<void>;
1682
+ private prepareMetadataFile;
1017
1683
  }
1018
1684
 
1019
- export { type AllEffects, AutocompleteHandler, type AutocompleteHandlerConstructor, AutocompleteRoute, BaseErrorEmbed, Bot, BuilderComponent, ButtonRoute, Catchable, Checkable, type CommandMeta, CommandMetadataKey, type Config, ContextMenuRoute, type Core, CustomError, type CustomErrorConstructor, DatabaseError, type DefaultEffects, type EffectKeys, EffectMetadataKey, type EffectParams, type Effects, EffectsEmitter, EffectsHandler, EffectsRegistry, EventCatchable, EventHandler, type EventHandlerConstructor, EventMetadataKey, type Handler, type HandlerConstructor, type Initializeable, InteractionHandler, InteractionMetadataKey, InteractionMiddleware, InteractionRoutes, type MiddlewareConstructor, ModalComponent, ModalRoute, Pluggable, Plugin, type PluginArgs, type PluginCtor, RegisterCommand, RegisterEffect, RegisterEvent, type RepliableInteractionHandler, type Repliables, RowComponent, Seedcord, SelectMenuRoute, SelectMenuType, SlashRoute, type ValidEventTypes, type ValidInteractionTypes, type ValidNonInteractionTypes, WebhookLog, type WithChecks, throwCustomError };
1685
+ export { type ActionRowComponentType, type AllEffects, type AtleastOneMessageComponent, AutocompleteHandler, type AutocompleteHandlerConstructor, AutocompleteRoute, BaseComponent, type BaseCore, BaseErrorEmbed, BaseHandler, Bot, type BotConfig, type BotPermissionScope, type BotPermissionScopeGroups, BuilderComponent, type BuilderType, BuilderTypes, ButtonRoute, CannotAssignBotRole, CannotSendEmbedsError, Catchable, type CatchableOptions, ChannelNotFoundError, ChannelNotTextChannel, Checkable, type CommandCtor, type CommandMeta, CommandMetadataKey, CommandRegistry, type CommandRouteString, type CommandScope, type CommandsConfig, type Config, ContextMenuRoute, type Core, CouldNotFindChannel, CustomError, type CustomErrorConstructor, DatabaseError, type DefaultEffects, type EffectKeys, EffectMetadataKey, type EffectParams, type Effects, type EffectsConfig, EffectsEmitter, EffectsHandler, EffectsRegistry, EmojiInjector, EventCatchable, EventController, EventHandler, type EventHandlerConstructor, EventMetadataKey, EventMiddleware, type EventMiddlewareConstructor, type EventsConfig, type ExtractedErrorResponse, GenericError, type GlobalMeta, type GuildMeta, type Handler, type HandlerConstructor, type HandlerCtor, type HandlerWithChecks, HasDangerousPermissions, type Initializeable, type InstantiatedActionRow, type InstantiatedBuilder, InteractionController, InteractionHandler, InteractionMetadataKey, InteractionMiddleware, type InteractionMiddlewareConstructor, InteractionRoutes, type InteractionsConfig, type MessageContent, Middleware, type MiddlewareConstructor, type MiddlewareMetadata, MiddlewareMetadataKey, type MiddlewareOptions, MiddlewareType, MissingPermissions, ModalRoute, PERM_GROUPS, PermissionNames, Pluggable, Plugin, type PluginArgs, type PluginCtor, RegisterCommand, RegisterEffect, RegisterEvent, type RepliableInteractionHandler, type Repliables, RoleDoesNotExist, RoleHigherThanMe, RowComponent, RowTypes, Seedcord, SelectMenuRoute, SelectMenuType, SlashRoute, UnhandledEvent, UnknownException, UserNotFound, UserNotInGuild, type ValidEventTypes, type ValidInteractionTypes, type ValidNonInteractionTypes, WebhookLog, type WithChecks, attemptSendDM, buildSlashRoute, checkBotPermissions, checkPermissions, extractErrorResponse, fetchGuildMember, fetchManyGuildMembers, fetchManyUsers, fetchRole, fetchText, fetchUser, getBotRole, hasPermsToAssign, sendInText, throwCustomError, updateMemberRoles };