@julanzw/ttoolbox-discordjs-framework 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +675 -0
  2. package/README.md +77 -0
  3. package/dist/classes/Command.class.d.ts +169 -0
  4. package/dist/classes/Command.class.js +156 -0
  5. package/dist/classes/CommandManager.class.d.ts +69 -0
  6. package/dist/classes/CommandManager.class.js +149 -0
  7. package/dist/classes/DiscordHandler.class.d.ts +241 -0
  8. package/dist/classes/DiscordHandler.class.js +222 -0
  9. package/dist/classes/InteractionError.class.d.ts +8 -0
  10. package/dist/classes/InteractionError.class.js +11 -0
  11. package/dist/classes/ModalManager.class.d.ts +154 -0
  12. package/dist/classes/ModalManager.class.js +205 -0
  13. package/dist/classes/SubcommandGroup.class.d.ts +127 -0
  14. package/dist/classes/SubcommandGroup.class.js +156 -0
  15. package/dist/index.d.ts +18 -0
  16. package/dist/index.js +17 -0
  17. package/dist/types/button.d.ts +2 -0
  18. package/dist/types/button.js +1 -0
  19. package/dist/types/channel.d.ts +2 -0
  20. package/dist/types/channel.js +1 -0
  21. package/dist/types/logger.d.ts +37 -0
  22. package/dist/types/logger.js +1 -0
  23. package/dist/types/modal.d.ts +77 -0
  24. package/dist/types/modal.js +1 -0
  25. package/dist/types/permission.d.ts +2 -0
  26. package/dist/types/permission.js +1 -0
  27. package/dist/utils/PaginatedEmbed.class.d.ts +25 -0
  28. package/dist/utils/PaginatedEmbed.class.js +102 -0
  29. package/dist/utils/TToolboxLogger.class.d.ts +176 -0
  30. package/dist/utils/TToolboxLogger.class.js +252 -0
  31. package/dist/utils/cooldown.d.ts +13 -0
  32. package/dist/utils/cooldown.js +43 -0
  33. package/dist/utils/editAndReply.d.ts +37 -0
  34. package/dist/utils/editAndReply.js +85 -0
  35. package/dist/utils/embeds.d.ts +55 -0
  36. package/dist/utils/embeds.js +94 -0
  37. package/dist/utils/formatting.d.ts +44 -0
  38. package/dist/utils/formatting.js +87 -0
  39. package/dist/utils/miliseconds.d.ts +10 -0
  40. package/dist/utils/miliseconds.js +11 -0
  41. package/dist/utils/permissions.d.ts +8 -0
  42. package/dist/utils/permissions.js +24 -0
  43. package/dist/utils/slashCommandOptions.d.ts +8 -0
  44. package/dist/utils/slashCommandOptions.js +11 -0
  45. package/package.json +50 -0
@@ -0,0 +1,205 @@
1
+ // core/utils/ModalManager.js
2
+ import { ActionRowBuilder, TextInputBuilder, ModalBuilder, } from 'discord.js';
3
+ /**
4
+ * Manages modal creation, registration, and submission handling.
5
+ *
6
+ * Provides a centralized way to create and track modals throughout the bot.
7
+ * Modals can be registered with their submission handlers and automatically
8
+ * cleaned up after use if marked as ephemeral.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const modalManager = new ModalManager();
13
+ *
14
+ * // Create and register a modal
15
+ * const modal = modalManager.buildAndRegister({
16
+ * id: 'feedback-modal',
17
+ * title: 'Submit Feedback',
18
+ * ephemeral: true,
19
+ * fields: [
20
+ * {
21
+ * customId: 'message',
22
+ * name: 'Your Feedback',
23
+ * style: TextInputStyle.Paragraph,
24
+ * required: true,
25
+ * }
26
+ * ],
27
+ * onSubmit: async (interaction) => {
28
+ * const feedback = interaction.fields.getTextInputValue('message');
29
+ * await interaction.reply('Thank you for your feedback!');
30
+ * }
31
+ * });
32
+ *
33
+ * await interaction.showModal(modal);
34
+ * ```
35
+ */
36
+ export class ModalManager {
37
+ constructor() {
38
+ this.modals = new Map();
39
+ }
40
+ /**
41
+ * Builds a Discord ModalBuilder and registers the modal for submission handling.
42
+ *
43
+ * Creates a modal with the specified fields and registers it so that when
44
+ * a user submits it, the onSubmit handler will be called.
45
+ *
46
+ * @param data - The modal configuration including fields and submission handler
47
+ * @returns A ModalBuilder ready to be shown to the user
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const modal = modalManager.buildAndRegister({
52
+ * id: 'edit-reminder',
53
+ * title: 'Edit Reminder',
54
+ * ephemeral: true,
55
+ * fields: [
56
+ * {
57
+ * customId: 'message',
58
+ * name: 'Reminder Message',
59
+ * style: TextInputStyle.Short,
60
+ * required: true,
61
+ * value: existingMessage,
62
+ * }
63
+ * ],
64
+ * onSubmit: async (interaction) => {
65
+ * const newMessage = interaction.fields.getTextInputValue('message');
66
+ * await updateReminder(id, newMessage);
67
+ * }
68
+ * });
69
+ *
70
+ * await buttonInteraction.showModal(modal);
71
+ * ```
72
+ */
73
+ buildAndRegister(data) {
74
+ const modal = new ModalBuilder().setCustomId(data.id).setTitle(data.title);
75
+ for (const field of data.fields) {
76
+ const input = new TextInputBuilder()
77
+ .setCustomId(field.customId)
78
+ .setLabel(field.name)
79
+ .setStyle(field.style)
80
+ .setRequired(field.required ?? true);
81
+ if (field.placeholder)
82
+ input.setPlaceholder(field.placeholder);
83
+ if (field.minLength)
84
+ input.setMinLength(field.minLength);
85
+ if (field.maxLength)
86
+ input.setMaxLength(field.maxLength);
87
+ if (field.value)
88
+ input.setValue(field.value);
89
+ const row = new ActionRowBuilder().addComponents(input);
90
+ modal.addComponents(row);
91
+ }
92
+ this.modals.set(data.id, data);
93
+ return modal;
94
+ }
95
+ /**
96
+ * Retrieves a registered modal by its ID.
97
+ *
98
+ * Supports dynamic IDs - if the exact ID isn't found, attempts to match
99
+ * using the base ID (before the first colon). This allows for modals with
100
+ * dynamic suffixes like "edit-reminder:123".
101
+ *
102
+ * @param id - The modal ID to look up
103
+ * @returns The modal configuration, or undefined if not found
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * // Register with base ID
108
+ * modalManager.buildAndRegister({ id: 'edit-reminder', ... });
109
+ *
110
+ * // Can retrieve with dynamic ID
111
+ * const modal = modalManager.get('edit-reminder:123'); // Works!
112
+ * ```
113
+ */
114
+ get(id) {
115
+ // Try exact match first
116
+ const modal = this.modals.get(id);
117
+ if (modal)
118
+ return modal;
119
+ // Try base ID (before colon) for dynamic IDs
120
+ const baseId = id.split(':')[0];
121
+ return this.modals.get(baseId);
122
+ }
123
+ /**
124
+ * Removes a modal from the registry.
125
+ *
126
+ * Useful for cleaning up ephemeral modals after they've been submitted,
127
+ * or for unregistering modals that are no longer needed.
128
+ *
129
+ * @param id - The modal ID to remove
130
+ * @returns true if the modal was removed, false if it didn't exist
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * // Clean up after submission
135
+ * await modalManager.handleSubmit(interaction);
136
+ * modalManager.remove(interaction.customId); // If ephemeral
137
+ * ```
138
+ */
139
+ remove(id) {
140
+ return this.modals.delete(id);
141
+ }
142
+ /**
143
+ * Handles a modal submission by calling the registered onSubmit handler.
144
+ *
145
+ * Looks up the modal by ID, calls its onSubmit handler, and automatically
146
+ * removes ephemeral modals from the registry after submission.
147
+ *
148
+ * @param interaction - The modal submit interaction
149
+ * @throws {Error} If no modal is found for the interaction's custom ID
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * // In your interaction handler
154
+ * client.on('interactionCreate', async (interaction) => {
155
+ * if (interaction.isModalSubmit()) {
156
+ * await modalManager.handleSubmit(interaction);
157
+ * }
158
+ * });
159
+ * ```
160
+ */
161
+ async handleSubmit(interaction) {
162
+ const modal = this.get(interaction.customId);
163
+ if (!modal) {
164
+ throw new Error(`Modal not found: ${interaction.customId}`);
165
+ }
166
+ await modal.onSubmit(interaction);
167
+ // Clean up ephemeral modals
168
+ if (modal.ephemeral) {
169
+ this.remove(interaction.customId);
170
+ }
171
+ }
172
+ /**
173
+ * Checks if a modal with the given ID is registered.
174
+ *
175
+ * @param id - The modal ID to check
176
+ * @returns true if the modal exists in the registry
177
+ */
178
+ has(id) {
179
+ return this.modals.has(id) || this.modals.has(id.split(':')[0]);
180
+ }
181
+ /**
182
+ * Clears all registered modals from the registry.
183
+ *
184
+ * Useful for cleanup during bot shutdown or for testing.
185
+ */
186
+ clear() {
187
+ this.modals.clear();
188
+ }
189
+ /**
190
+ * Gets the total number of registered modals.
191
+ *
192
+ * @returns The count of modals in the registry
193
+ */
194
+ get size() {
195
+ return this.modals.size;
196
+ }
197
+ /**
198
+ * Gets all registered modal IDs.
199
+ *
200
+ * @returns Array of modal IDs currently in the registry
201
+ */
202
+ getModalIds() {
203
+ return Array.from(this.modals.keys());
204
+ }
205
+ }
@@ -0,0 +1,127 @@
1
+ import { ChatInputCommandInteraction, Client, RESTPostAPIChatInputApplicationCommandsJSONBody } from 'discord.js';
2
+ import { ILogger } from '../types/logger.js';
3
+ import { Command } from './Command.class.js';
4
+ /**
5
+ * Abstract base class for Discord slash command groups with subcommands.
6
+ *
7
+ * Use this when you have multiple related commands that should be grouped together
8
+ * under a single parent command.
9
+ *
10
+ * For example, `/birthday set` and `/birthday calendar`
11
+ * would both be subcommands of a `BirthdayCommands` subcommand group.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * export class BirthdayCommands extends SubcommandGroup {
16
+ * name = 'birthday';
17
+ * description = 'All commands related to birthdays';
18
+ *
19
+ * protected subcommands = new Map<string, Command>([
20
+ * ['set', new SetBirthdayCommand()],
21
+ * ['calendar', new CalendarCommand()],
22
+ * ]);
23
+ * }
24
+ * ```
25
+ */
26
+ export declare abstract class SubcommandGroup {
27
+ /** The parent command name (e.g., 'birthday' for `/birthday set`) */
28
+ abstract name: string;
29
+ /** A brief description of the command group */
30
+ abstract description: string;
31
+ /** Map of subcommand names to Command instances */
32
+ protected abstract subcommands: Map<string, Command>;
33
+ /** The logger instance used in the subcommand group */
34
+ protected logger?: ILogger;
35
+ /**
36
+ * Safely executes a function with error handling and logging.
37
+ *
38
+ * Wraps the execution in a try-catch block, logs successful executions,
39
+ * and automatically handles errors by logging them and sending a user-friendly
40
+ * error message.
41
+ *
42
+ * @param commandName - The name of the parent command
43
+ * @param scope - The logging scope for this execution
44
+ * @param interaction - The command interaction
45
+ * @param fn - The function to execute
46
+ * @private
47
+ */
48
+ private safeExecute;
49
+ /**
50
+ * Executes the appropriate subcommand based on the user's interaction.
51
+ *
52
+ * This method:
53
+ * 1. Determines which subcommand was invoked
54
+ * 2. Looks up the corresponding Command instance
55
+ * 3. Executes the subcommand with error handling
56
+ *
57
+ * Called automatically by the CommandManager when this command group is invoked.
58
+ *
59
+ * @param interaction - The command interaction
60
+ * @param client - The Discord client instance
61
+ * @throws {Error} If the subcommand name doesn't exist in the subcommands map
62
+ *
63
+ * @example
64
+ * When a user runs `/birthday set`, this method:
65
+ * - Gets "set" from interaction.options.getSubcommand()
66
+ * - Looks up the SetBirthdayCommand in the subcommands map
67
+ * - Calls SetBirthdayCommand.execute()
68
+ */
69
+ execute(interaction: ChatInputCommandInteraction, client: Client): Promise<void>;
70
+ /**
71
+ * Converts the command group to Discord API JSON format for registration.
72
+ *
73
+ * This method:
74
+ * 1. Creates a SlashCommandBuilder with the group's name and description
75
+ * 2. Adds each subcommand from the subcommands map
76
+ * 3. Applies any custom options from each subcommand's `customize` method
77
+ * 4. Returns the JSON representation needed for Discord's API
78
+ *
79
+ * Called automatically by CommandManager when registering commands.
80
+ *
81
+ * @returns The command group in Discord API JSON format
82
+ *
83
+ * @example
84
+ * For a birthday command group with "set" and "calendar" subcommands,
85
+ * this creates the structure for:
86
+ * - `/birthday set <options>`
87
+ * - `/birthday calendar`
88
+ */
89
+ toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody;
90
+ /**
91
+ * Gets a list of all subcommands with their names and descriptions.
92
+ *
93
+ * Useful for generating help text or documentation about available subcommands.
94
+ * Used by CommandManager's `getHelpPages` method to display subcommands in the help command.
95
+ *
96
+ * @returns Array of objects containing subcommand names and descriptions
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * const subcommands = birthdayCommands.getSubcommandList();
101
+ * // Returns:
102
+ * // [
103
+ * // { name: 'set', description: 'Set your birthday' },
104
+ * // { name: 'calendar', description: 'View birthday calendar' }
105
+ * // ]
106
+ * ```
107
+ */
108
+ getSubcommandList(): Array<{
109
+ name: string;
110
+ description: string;
111
+ }>;
112
+ /**
113
+ * Sets the logger for this subcommand group.
114
+ *
115
+ * @param logger - Logger instance implementing ILogger interface
116
+ */
117
+ setLogger(logger: ILogger): void;
118
+ /**
119
+ * Log a message using the configured logger.
120
+ *
121
+ * @param message - The message to log
122
+ * @param level - The log level
123
+ * @param scope - The scope/context
124
+ * @param logToConsole - Whether to also log to console
125
+ */
126
+ protected log(message: string, level: string, scope: string, logToConsole?: boolean): void;
127
+ }
@@ -0,0 +1,156 @@
1
+ import { SlashCommandBuilder, } from 'discord.js';
2
+ import { safeReply } from '../utils/editAndReply.js';
3
+ /**
4
+ * Abstract base class for Discord slash command groups with subcommands.
5
+ *
6
+ * Use this when you have multiple related commands that should be grouped together
7
+ * under a single parent command.
8
+ *
9
+ * For example, `/birthday set` and `/birthday calendar`
10
+ * would both be subcommands of a `BirthdayCommands` subcommand group.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * export class BirthdayCommands extends SubcommandGroup {
15
+ * name = 'birthday';
16
+ * description = 'All commands related to birthdays';
17
+ *
18
+ * protected subcommands = new Map<string, Command>([
19
+ * ['set', new SetBirthdayCommand()],
20
+ * ['calendar', new CalendarCommand()],
21
+ * ]);
22
+ * }
23
+ * ```
24
+ */
25
+ export class SubcommandGroup {
26
+ /**
27
+ * Safely executes a function with error handling and logging.
28
+ *
29
+ * Wraps the execution in a try-catch block, logs successful executions,
30
+ * and automatically handles errors by logging them and sending a user-friendly
31
+ * error message.
32
+ *
33
+ * @param commandName - The name of the parent command
34
+ * @param scope - The logging scope for this execution
35
+ * @param interaction - The command interaction
36
+ * @param fn - The function to execute
37
+ * @private
38
+ */
39
+ async safeExecute(commandName, scope, interaction, fn) {
40
+ try {
41
+ await fn();
42
+ const subcommandName = interaction.options.getSubcommand(false);
43
+ this.logger?.log(`${commandName} ${subcommandName ? `(${subcommandName}) ` : ``}command executed`, 'info', scope);
44
+ }
45
+ catch (err) {
46
+ this.logger?.log('An Error occured' + err, 'error', scope, true);
47
+ return await safeReply(interaction, 'An unexpected error occurred.');
48
+ }
49
+ }
50
+ /**
51
+ * Executes the appropriate subcommand based on the user's interaction.
52
+ *
53
+ * This method:
54
+ * 1. Determines which subcommand was invoked
55
+ * 2. Looks up the corresponding Command instance
56
+ * 3. Executes the subcommand with error handling
57
+ *
58
+ * Called automatically by the CommandManager when this command group is invoked.
59
+ *
60
+ * @param interaction - The command interaction
61
+ * @param client - The Discord client instance
62
+ * @throws {Error} If the subcommand name doesn't exist in the subcommands map
63
+ *
64
+ * @example
65
+ * When a user runs `/birthday set`, this method:
66
+ * - Gets "set" from interaction.options.getSubcommand()
67
+ * - Looks up the SetBirthdayCommand in the subcommands map
68
+ * - Calls SetBirthdayCommand.execute()
69
+ */
70
+ async execute(interaction, client) {
71
+ const subcommandName = interaction.options.getSubcommand();
72
+ const subcommand = this.subcommands.get(subcommandName);
73
+ if (!subcommand) {
74
+ throw new Error(`Unknown subcommand: ${subcommandName}`);
75
+ }
76
+ const scope = `${subcommand.name}_EXECUTION`;
77
+ await this.safeExecute(this.name, scope, interaction, () => subcommand.execute(interaction, client));
78
+ }
79
+ /**
80
+ * Converts the command group to Discord API JSON format for registration.
81
+ *
82
+ * This method:
83
+ * 1. Creates a SlashCommandBuilder with the group's name and description
84
+ * 2. Adds each subcommand from the subcommands map
85
+ * 3. Applies any custom options from each subcommand's `customize` method
86
+ * 4. Returns the JSON representation needed for Discord's API
87
+ *
88
+ * Called automatically by CommandManager when registering commands.
89
+ *
90
+ * @returns The command group in Discord API JSON format
91
+ *
92
+ * @example
93
+ * For a birthday command group with "set" and "calendar" subcommands,
94
+ * this creates the structure for:
95
+ * - `/birthday set <options>`
96
+ * - `/birthday calendar`
97
+ */
98
+ toJSON() {
99
+ const builder = new SlashCommandBuilder()
100
+ .setName(this.name)
101
+ .setDescription(this.description);
102
+ for (const cmd of this.subcommands.values()) {
103
+ builder.addSubcommand((sc) => {
104
+ sc.setName(cmd.name).setDescription(cmd.description);
105
+ if (cmd.customize) {
106
+ cmd.customize(sc);
107
+ }
108
+ return sc;
109
+ });
110
+ }
111
+ return builder.toJSON();
112
+ }
113
+ /**
114
+ * Gets a list of all subcommands with their names and descriptions.
115
+ *
116
+ * Useful for generating help text or documentation about available subcommands.
117
+ * Used by CommandManager's `getHelpPages` method to display subcommands in the help command.
118
+ *
119
+ * @returns Array of objects containing subcommand names and descriptions
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * const subcommands = birthdayCommands.getSubcommandList();
124
+ * // Returns:
125
+ * // [
126
+ * // { name: 'set', description: 'Set your birthday' },
127
+ * // { name: 'calendar', description: 'View birthday calendar' }
128
+ * // ]
129
+ * ```
130
+ */
131
+ getSubcommandList() {
132
+ return Array.from(this.subcommands.values()).map((sub) => ({
133
+ name: sub.name,
134
+ description: sub.description,
135
+ }));
136
+ }
137
+ /**
138
+ * Sets the logger for this subcommand group.
139
+ *
140
+ * @param logger - Logger instance implementing ILogger interface
141
+ */
142
+ setLogger(logger) {
143
+ this.logger = logger;
144
+ }
145
+ /**
146
+ * Log a message using the configured logger.
147
+ *
148
+ * @param message - The message to log
149
+ * @param level - The log level
150
+ * @param scope - The scope/context
151
+ * @param logToConsole - Whether to also log to console
152
+ */
153
+ log(message, level, scope, logToConsole = false) {
154
+ this.logger?.log(message, level, scope, logToConsole);
155
+ }
156
+ }
@@ -0,0 +1,18 @@
1
+ export { Command } from './classes/Command.class.js';
2
+ export { SubcommandGroup } from './classes/SubcommandGroup.class.js';
3
+ export { CommandManager } from './classes/CommandManager.class.js';
4
+ export { DiscordHandler } from './classes/DiscordHandler.class.js';
5
+ export { ModalManager } from './classes/ModalManager.class.js';
6
+ export { PaginatedEmbed } from './utils/PaginatedEmbed.class.js';
7
+ export type { PermissionLevel } from './types/permission.js';
8
+ export type { Modal, ModalField } from './types/modal.js';
9
+ export type { ButtonType } from './types/button.js';
10
+ export type { ILogger } from './types/logger.js';
11
+ export { getPermissionsForLevel } from './utils/permissions.js';
12
+ export { embedBuilder, createButton, createButtonsRow, createPaginationButtons, } from './utils/embeds.js';
13
+ export { stringOption, integerOption, booleanOption, userOption, channelOption, roleOption, } from './utils/slashCommandOptions.js';
14
+ export { safeReply, safeEdit } from './utils/editAndReply.js';
15
+ export { formatDuration, formatDateToString, formatDateToYYYYMMDDHHMMSS, formatDateToDDMMYYYY, getDaySuffix, capitalizeFirst, } from './utils/formatting.js';
16
+ export { TIMES_MILISECONDS } from './utils/miliseconds.js';
17
+ export { TToolboxLogger } from './utils/TToolboxLogger.class.js';
18
+ export { InteractionError } from './classes/InteractionError.class.js';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ // Classes
2
+ export { Command } from './classes/Command.class.js';
3
+ export { SubcommandGroup } from './classes/SubcommandGroup.class.js';
4
+ export { CommandManager } from './classes/CommandManager.class.js';
5
+ export { DiscordHandler } from './classes/DiscordHandler.class.js';
6
+ export { ModalManager } from './classes/ModalManager.class.js';
7
+ export { PaginatedEmbed } from './utils/PaginatedEmbed.class.js';
8
+ // Utilities
9
+ export { getPermissionsForLevel } from './utils/permissions.js';
10
+ export { embedBuilder, createButton, createButtonsRow, createPaginationButtons, } from './utils/embeds.js';
11
+ export { stringOption, integerOption, booleanOption, userOption, channelOption, roleOption, } from './utils/slashCommandOptions.js';
12
+ export { safeReply, safeEdit } from './utils/editAndReply.js';
13
+ export { formatDuration, formatDateToString, formatDateToYYYYMMDDHHMMSS, formatDateToDDMMYYYY, getDaySuffix, capitalizeFirst, } from './utils/formatting.js';
14
+ export { TIMES_MILISECONDS } from './utils/miliseconds.js';
15
+ export { TToolboxLogger } from './utils/TToolboxLogger.class.js';
16
+ // Errors
17
+ export { InteractionError } from './classes/InteractionError.class.js';
@@ -0,0 +1,2 @@
1
+ export type ButtonType = 'prev' | 'next' | 'edit' | 'delete';
2
+ export type PaginationButtonLocation = 'embrace' | 'start' | 'end';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import { ChannelType } from 'discord.js';
2
+ export type AllowedChannelTypeChannelOption = ChannelType.GuildText | ChannelType.GuildVoice | ChannelType.GuildCategory | ChannelType.GuildAnnouncement | ChannelType.AnnouncementThread | ChannelType.PublicThread | ChannelType.PrivateThread | ChannelType.GuildStageVoice | ChannelType.GuildForum | ChannelType.GuildMedia;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Configuration options for TToolboxLogger.
3
+ */
4
+ export type LoggerOptions = {
5
+ /** Directory where log files should be stored */
6
+ logDir?: string;
7
+ /** Name of the log file */
8
+ logFileName?: string;
9
+ /** Custom log levels to use instead of defaults */
10
+ customLevels?: Record<string, string>;
11
+ /** Whether to extend default levels or replace them entirely */
12
+ extendDefaultLevels?: boolean;
13
+ };
14
+ /**
15
+ * Logger interface for TToolbox framework.
16
+ *
17
+ * Allows any logger implementation to be used with the framework,
18
+ * as long as it provides these core methods.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const customLogger: ILogger = {
23
+ * log: (msg, level, scope, console) => myCustomLog(msg),
24
+ * info: (msg, scope, console) => console.log(msg),
25
+ * warn: (msg, scope, console) => console.warn(msg),
26
+ * error: (msg, scope, console) => console.error(msg),
27
+ * };
28
+ *
29
+ * commandManager.setLogger(customLogger);
30
+ * ```
31
+ */
32
+ export interface ILogger {
33
+ log(message: string, level: string, scope: string, logToConsole?: boolean): void;
34
+ info(message: string, scope: string, logToConsole?: boolean): void;
35
+ warn(message: string, scope: string, logToConsole?: boolean): void;
36
+ error(message: string, scope: string, logToConsole?: boolean): void;
37
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,77 @@
1
+ import { TextInputStyle, ModalSubmitInteraction } from 'discord.js';
2
+ /**
3
+ * Represents a single input field within a Discord modal.
4
+ */
5
+ export type ModalField = {
6
+ /**
7
+ * The label text shown above the input field.
8
+ */
9
+ name: string;
10
+ /**
11
+ * The type of input to display.
12
+ * Use {@link TextInputStyle.Short} for a single-line field
13
+ * or {@link TextInputStyle.Paragraph} for a multi-line field.
14
+ */
15
+ style: TextInputStyle;
16
+ /**
17
+ * Unique identifier for this field within the modal.
18
+ * Used to retrieve the value in the `onSubmit` handler.
19
+ */
20
+ customId: string;
21
+ /**
22
+ * Optional placeholder text shown when the field is empty.
23
+ */
24
+ placeholder?: string;
25
+ /**
26
+ * Whether this field is required to be filled out.
27
+ * Defaults to `true`.
28
+ */
29
+ required?: boolean;
30
+ /**
31
+ * Minimum number of characters the input must contain.
32
+ */
33
+ minLength?: number;
34
+ /**
35
+ * Maximum number of characters the input can contain.
36
+ */
37
+ maxLength?: number;
38
+ /**
39
+ * Pre-filled value shown in the input field when the modal opens.
40
+ */
41
+ value?: string;
42
+ };
43
+ /**
44
+ * Represents a Discord modal dialog configuration.
45
+ */
46
+ export type Modal = {
47
+ /**
48
+ * The custom ID of the modal, used to match submissions.
49
+ *
50
+ * When using dynamic IDs (e.g., `edit-reminder:123`), the ModalManager
51
+ * will match based on the base ID before the colon.
52
+ */
53
+ id: string;
54
+ /**
55
+ * Indicates whether this modal is **ephemeral** — meaning it's tied to specific
56
+ * context or data from its creation (e.g., a user, reminder ID, or other state).
57
+ *
58
+ * When `true`, the modal is automatically removed from the registry after
59
+ * submission to prevent reuse or context leakage. This is typically used for
60
+ * one-shot modals whose handlers depend on creation-time data.
61
+ */
62
+ ephemeral: boolean;
63
+ /**
64
+ * The title displayed at the top of the modal window.
65
+ */
66
+ title: string;
67
+ /**
68
+ * The input fields displayed within the modal.
69
+ */
70
+ fields: ModalField[];
71
+ /**
72
+ * Handler function called when the modal is submitted.
73
+ * Provides the `ModalSubmitInteraction` to access input values
74
+ * and reply to the user.
75
+ */
76
+ onSubmit: (interaction: ModalSubmitInteraction) => Promise<any>;
77
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import { PermissionFlagsBits } from 'discord.js';
2
+ export type PermissionLevel = 'admin' | 'owner' | 'disabled' | 'user' | null | undefined | bigint | number | (keyof typeof PermissionFlagsBits)[];
@@ -0,0 +1 @@
1
+ export {};