@julanzw/ttoolbox-discordjs-framework 1.3.0 → 1.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.
@@ -0,0 +1,79 @@
1
+ import { MessageContextMenuCommandInteraction, Client } from 'discord.js';
2
+ import type { ILogger } from '../types/logger.js';
3
+ import type { ErrorReporter } from '../utils/ErrorReporter.js';
4
+ import { PermissionLevel } from '../types/permission.js';
5
+ /**
6
+ * Base class for Message Context Menu Commands.
7
+ *
8
+ * Message context menu commands appear when right-clicking on a message and
9
+ * selecting "Apps" in the context menu.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * export class ReportMessageCommand extends MessageContextMenuCommand {
14
+ * name = 'Report Message';
15
+ * guildOnly = true;
16
+ * permissionLevel = 'user' as const;
17
+ *
18
+ * protected async run(interaction: MessageContextMenuCommandInteraction) {
19
+ * const message = interaction.targetMessage;
20
+ * await reportMessage(message);
21
+ * await interaction.reply({ content: 'Message reported!', ephemeral: true });
22
+ * }
23
+ * }
24
+ * ```
25
+ */
26
+ export declare abstract class MessageContextMenuCommand {
27
+ abstract name: string;
28
+ abstract guildOnly: boolean;
29
+ abstract permissionLevel: PermissionLevel;
30
+ protected logger?: ILogger;
31
+ protected errorReporter?: ErrorReporter;
32
+ /**
33
+ * The main execution method - implement your command logic here.
34
+ */
35
+ protected abstract run(interaction: MessageContextMenuCommandInteraction, client: Client): Promise<void>;
36
+ /**
37
+ * Optional: Called before command execution.
38
+ * Return false to stop execution.
39
+ */
40
+ protected beforeExecute?(interaction: MessageContextMenuCommandInteraction, client: Client): Promise<boolean | void>;
41
+ /**
42
+ * Optional: Called after successful command execution.
43
+ */
44
+ protected afterExecute?(interaction: MessageContextMenuCommandInteraction, client: Client): Promise<void>;
45
+ /**
46
+ * Optional: Called when command execution fails.
47
+ */
48
+ protected onError?(interaction: MessageContextMenuCommandInteraction, error: Error, client: Client): Promise<void>;
49
+ /**
50
+ * Set the logger for this command.
51
+ */
52
+ setLogger(logger: ILogger): void;
53
+ /**
54
+ * Set the error reporter for this command.
55
+ */
56
+ setErrorReporter(reporter: ErrorReporter): void;
57
+ /**
58
+ * Log a message using the configured logger.
59
+ */
60
+ protected log(message: string, level: string, scope: string, logToConsole?: boolean): void;
61
+ /**
62
+ * Validate the interaction (guild-only check).
63
+ */
64
+ protected validate(interaction: MessageContextMenuCommandInteraction): string | null;
65
+ /**
66
+ * Check if the user has permission to use this command.
67
+ * Override this method to implement custom permission logic.
68
+ */
69
+ protected hasPermission(interaction: MessageContextMenuCommandInteraction): Promise<boolean>;
70
+ /**
71
+ * Execute the command with validation and error handling.
72
+ */
73
+ execute(interaction: MessageContextMenuCommandInteraction, client: Client): Promise<void>;
74
+ private safeExecute;
75
+ /**
76
+ * Convert this command to Discord API JSON format.
77
+ */
78
+ toJSON(): import("discord.js").RESTPostAPIContextMenuApplicationCommandsJSONBody;
79
+ }
@@ -0,0 +1,120 @@
1
+ import { ContextMenuCommandBuilder, ApplicationCommandType, } from 'discord.js';
2
+ import { safeReply } from '../utils/editAndReply.js';
3
+ /**
4
+ * Base class for Message Context Menu Commands.
5
+ *
6
+ * Message context menu commands appear when right-clicking on a message and
7
+ * selecting "Apps" in the context menu.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * export class ReportMessageCommand extends MessageContextMenuCommand {
12
+ * name = 'Report Message';
13
+ * guildOnly = true;
14
+ * permissionLevel = 'user' as const;
15
+ *
16
+ * protected async run(interaction: MessageContextMenuCommandInteraction) {
17
+ * const message = interaction.targetMessage;
18
+ * await reportMessage(message);
19
+ * await interaction.reply({ content: 'Message reported!', ephemeral: true });
20
+ * }
21
+ * }
22
+ * ```
23
+ */
24
+ export class MessageContextMenuCommand {
25
+ /**
26
+ * Set the logger for this command.
27
+ */
28
+ setLogger(logger) {
29
+ this.logger = logger;
30
+ }
31
+ /**
32
+ * Set the error reporter for this command.
33
+ */
34
+ setErrorReporter(reporter) {
35
+ this.errorReporter = reporter;
36
+ }
37
+ /**
38
+ * Log a message using the configured logger.
39
+ */
40
+ log(message, level, scope, logToConsole = false) {
41
+ this.logger?.log(message, level, scope, logToConsole);
42
+ }
43
+ /**
44
+ * Validate the interaction (guild-only check).
45
+ */
46
+ validate(interaction) {
47
+ if (this.guildOnly && !interaction.guildId) {
48
+ return 'This command can only be used in a server.';
49
+ }
50
+ return null;
51
+ }
52
+ /**
53
+ * Check if the user has permission to use this command.
54
+ * Override this method to implement custom permission logic.
55
+ */
56
+ async hasPermission(interaction) {
57
+ // Default: everyone has permission
58
+ return true;
59
+ }
60
+ /**
61
+ * Execute the command with validation and error handling.
62
+ */
63
+ async execute(interaction, client) {
64
+ await this.safeExecute(this.name, interaction, client, async () => {
65
+ const error = this.validate(interaction);
66
+ if (error)
67
+ return await safeReply(interaction, error, true);
68
+ if (!(await this.hasPermission(interaction))) {
69
+ return await safeReply(interaction, 'You do not have permission to use this command.', true);
70
+ }
71
+ if (this.beforeExecute) {
72
+ const shouldContinue = await this.beforeExecute(interaction, client);
73
+ if (shouldContinue === false)
74
+ return;
75
+ }
76
+ try {
77
+ await this.run(interaction, client);
78
+ if (this.afterExecute) {
79
+ await this.afterExecute(interaction, client);
80
+ }
81
+ }
82
+ catch (err) {
83
+ if (this.onError) {
84
+ await this.onError(interaction, err, client);
85
+ }
86
+ throw err;
87
+ }
88
+ });
89
+ }
90
+ async safeExecute(commandName, interaction, client, fn) {
91
+ const scope = `${commandName}_EXECUTION`;
92
+ try {
93
+ await fn();
94
+ this.log(`${commandName} context menu command executed`, 'info', scope);
95
+ }
96
+ catch (err) {
97
+ this.log('An Error occurred: ' + err, 'error', scope, true);
98
+ if (this.errorReporter) {
99
+ await this.errorReporter.reportError(err, `Context Menu: ${commandName}`, {
100
+ user: interaction.user.tag,
101
+ userId: interaction.user.id,
102
+ messageAuthor: interaction.targetMessage.author.tag,
103
+ messageContent: interaction.targetMessage.content.slice(0, 100),
104
+ guild: interaction.guild?.name,
105
+ guildId: interaction.guildId,
106
+ });
107
+ }
108
+ return await safeReply(interaction, 'An unexpected error occurred.');
109
+ }
110
+ }
111
+ /**
112
+ * Convert this command to Discord API JSON format.
113
+ */
114
+ toJSON() {
115
+ return new ContextMenuCommandBuilder()
116
+ .setName(this.name)
117
+ .setType(ApplicationCommandType.Message)
118
+ .toJSON();
119
+ }
120
+ }
@@ -35,20 +35,6 @@ export declare abstract class SubcommandGroup {
35
35
  protected logger?: ILogger;
36
36
  /** ErrorReporter instance to use inside the subcommand group */
37
37
  private errorReporter?;
38
- /**
39
- * Safely executes a function with error handling and logging.
40
- *
41
- * Wraps the execution in a try-catch block, logs successful executions,
42
- * and automatically handles errors by logging them and sending a user-friendly
43
- * error message.
44
- *
45
- * @param subcommandName - The name of the subcommand
46
- * @param scope - The logging scope for this execution
47
- * @param interaction - The command interaction
48
- * @param fn - The function to execute
49
- * @private
50
- */
51
- private safeExecute;
52
38
  /**
53
39
  * Executes the appropriate subcommand based on the user's interaction.
54
40
  *
@@ -131,4 +117,19 @@ export declare abstract class SubcommandGroup {
131
117
  * Set the error reporter for this subcommand group.
132
118
  */
133
119
  setErrorReporter(reporter: ErrorReporter): this;
120
+ /**
121
+ * Lifecycle hook called before any subcommand in this group executes.
122
+ *
123
+ * @param interaction - The command interaction
124
+ * @returns true to continue, false to stop execution
125
+ */
126
+ protected beforeExecute?(interaction: ChatInputCommandInteraction, client: Client): Promise<boolean | void>;
127
+ /**
128
+ * Lifecycle hook called after any subcommand in this group executes successfully.
129
+ */
130
+ protected afterExecute?(interaction: ChatInputCommandInteraction, client: Client): Promise<void>;
131
+ /**
132
+ * Lifecycle hook called when any subcommand in this group fails.
133
+ */
134
+ protected onError?(interaction: ChatInputCommandInteraction, error: Error, client: Client): Promise<void>;
134
135
  }
@@ -1,5 +1,4 @@
1
1
  import { SlashCommandBuilder, } from 'discord.js';
2
- import { safeReply } from '../utils/editAndReply.js';
3
2
  /**
4
3
  * Abstract base class for Discord slash command groups with subcommands.
5
4
  *
@@ -23,36 +22,6 @@ import { safeReply } from '../utils/editAndReply.js';
23
22
  * ```
24
23
  */
25
24
  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 subcommandName - The name of the subcommand
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(subcommandName, scope, interaction, fn) {
40
- try {
41
- await fn();
42
- this.logger?.log(`${this.name} (${subcommandName}) command executed`, 'info', scope);
43
- }
44
- catch (err) {
45
- this.logger?.log('An Error occured' + err, 'error', scope, true);
46
- await this.errorReporter?.reportError(err, `Command: ${subcommandName} in SubcommandGroup: ${this.name}`, {
47
- user: interaction.user.tag,
48
- userId: interaction.user.id,
49
- guild: interaction.guild?.name,
50
- guildId: interaction.guildId,
51
- channel: interaction.channel?.id,
52
- });
53
- return await safeReply(interaction, 'An unexpected error occurred.');
54
- }
55
- }
56
25
  /**
57
26
  * Executes the appropriate subcommand based on the user's interaction.
58
27
  *
@@ -79,8 +48,24 @@ export class SubcommandGroup {
79
48
  if (!subcommand) {
80
49
  throw new Error(`Unknown subcommand: ${subcommandName}`);
81
50
  }
82
- const scope = `${subcommand.name}_EXECUTION`;
83
- await this.safeExecute(subcommandName, scope, interaction, () => subcommand.execute(interaction, client));
51
+ if (this.beforeExecute) {
52
+ const shouldContinue = await this.beforeExecute(interaction, client);
53
+ if (shouldContinue === false) {
54
+ return;
55
+ }
56
+ }
57
+ try {
58
+ await subcommand.execute(interaction, client);
59
+ if (this.afterExecute) {
60
+ await this.afterExecute(interaction, client);
61
+ }
62
+ }
63
+ catch (err) {
64
+ if (this.onError) {
65
+ await this.onError(interaction, err, client);
66
+ }
67
+ throw err;
68
+ }
84
69
  }
85
70
  /**
86
71
  * Converts the command group to Discord API JSON format for registration.
@@ -0,0 +1,78 @@
1
+ import { UserContextMenuCommandInteraction, Client } from 'discord.js';
2
+ import type { ILogger } from '../types/logger.js';
3
+ import type { ErrorReporter } from '../utils/ErrorReporter.js';
4
+ import { PermissionLevel } from '../types/permission.js';
5
+ /**
6
+ * Base class for User Context Menu Commands.
7
+ *
8
+ * User context menu commands appear when right-clicking on a user and
9
+ * selecting "Apps" in the context menu.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * export class GetUserInfoCommand extends UserContextMenuCommand {
14
+ * name = 'Get User Info';
15
+ * guildOnly = false;
16
+ * permissionLevel = 'user' as const;
17
+ *
18
+ * protected async run(interaction: UserContextMenuCommandInteraction) {
19
+ * const user = interaction.targetUser;
20
+ * await interaction.reply(`User: ${user.tag}\nID: ${user.id}`);
21
+ * }
22
+ * }
23
+ * ```
24
+ */
25
+ export declare abstract class UserContextMenuCommand {
26
+ abstract name: string;
27
+ abstract guildOnly: boolean;
28
+ abstract permissionLevel: PermissionLevel;
29
+ protected logger?: ILogger;
30
+ protected errorReporter?: ErrorReporter;
31
+ /**
32
+ * The main execution method - implement your command logic here.
33
+ */
34
+ protected abstract run(interaction: UserContextMenuCommandInteraction, client: Client): Promise<void>;
35
+ /**
36
+ * Optional: Called before command execution.
37
+ * Return false to stop execution.
38
+ */
39
+ protected beforeExecute?(interaction: UserContextMenuCommandInteraction, client: Client): Promise<boolean | void>;
40
+ /**
41
+ * Optional: Called after successful command execution.
42
+ */
43
+ protected afterExecute?(interaction: UserContextMenuCommandInteraction, client: Client): Promise<void>;
44
+ /**
45
+ * Optional: Called when command execution fails.
46
+ */
47
+ protected onError?(interaction: UserContextMenuCommandInteraction, error: Error, client: Client): Promise<void>;
48
+ /**
49
+ * Set the logger for this command.
50
+ */
51
+ setLogger(logger: ILogger): void;
52
+ /**
53
+ * Set the error reporter for this command.
54
+ */
55
+ setErrorReporter(reporter: ErrorReporter): void;
56
+ /**
57
+ * Log a message using the configured logger.
58
+ */
59
+ protected log(message: string, level: string, scope: string, logToConsole?: boolean): void;
60
+ /**
61
+ * Validate the interaction (guild-only check).
62
+ */
63
+ protected validate(interaction: UserContextMenuCommandInteraction): string | null;
64
+ /**
65
+ * Check if the user has permission to use this command.
66
+ * Override this method to implement custom permission logic.
67
+ */
68
+ protected hasPermission(interaction: UserContextMenuCommandInteraction): Promise<boolean>;
69
+ /**
70
+ * Execute the command with validation and error handling.
71
+ */
72
+ execute(interaction: UserContextMenuCommandInteraction, client: Client): Promise<void>;
73
+ private safeExecute;
74
+ /**
75
+ * Convert this command to Discord API JSON format.
76
+ */
77
+ toJSON(): import("discord.js").RESTPostAPIContextMenuApplicationCommandsJSONBody;
78
+ }
@@ -0,0 +1,119 @@
1
+ import { ContextMenuCommandBuilder, ApplicationCommandType, } from 'discord.js';
2
+ import { safeReply } from '../utils/editAndReply.js';
3
+ /**
4
+ * Base class for User Context Menu Commands.
5
+ *
6
+ * User context menu commands appear when right-clicking on a user and
7
+ * selecting "Apps" in the context menu.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * export class GetUserInfoCommand extends UserContextMenuCommand {
12
+ * name = 'Get User Info';
13
+ * guildOnly = false;
14
+ * permissionLevel = 'user' as const;
15
+ *
16
+ * protected async run(interaction: UserContextMenuCommandInteraction) {
17
+ * const user = interaction.targetUser;
18
+ * await interaction.reply(`User: ${user.tag}\nID: ${user.id}`);
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+ export class UserContextMenuCommand {
24
+ /**
25
+ * Set the logger for this command.
26
+ */
27
+ setLogger(logger) {
28
+ this.logger = logger;
29
+ }
30
+ /**
31
+ * Set the error reporter for this command.
32
+ */
33
+ setErrorReporter(reporter) {
34
+ this.errorReporter = reporter;
35
+ }
36
+ /**
37
+ * Log a message using the configured logger.
38
+ */
39
+ log(message, level, scope, logToConsole = false) {
40
+ this.logger?.log(message, level, scope, logToConsole);
41
+ }
42
+ /**
43
+ * Validate the interaction (guild-only check).
44
+ */
45
+ validate(interaction) {
46
+ if (this.guildOnly && !interaction.guildId) {
47
+ return 'This command can only be used in a server.';
48
+ }
49
+ return null;
50
+ }
51
+ /**
52
+ * Check if the user has permission to use this command.
53
+ * Override this method to implement custom permission logic.
54
+ */
55
+ async hasPermission(interaction) {
56
+ // Default: everyone has permission
57
+ return true;
58
+ }
59
+ /**
60
+ * Execute the command with validation and error handling.
61
+ */
62
+ async execute(interaction, client) {
63
+ await this.safeExecute(this.name, interaction, client, async () => {
64
+ const error = this.validate(interaction);
65
+ if (error)
66
+ return await safeReply(interaction, error, true);
67
+ if (!(await this.hasPermission(interaction))) {
68
+ return await safeReply(interaction, 'You do not have permission to use this command.', true);
69
+ }
70
+ if (this.beforeExecute) {
71
+ const shouldContinue = await this.beforeExecute(interaction, client);
72
+ if (shouldContinue === false)
73
+ return;
74
+ }
75
+ try {
76
+ await this.run(interaction, client);
77
+ if (this.afterExecute) {
78
+ await this.afterExecute(interaction, client);
79
+ }
80
+ }
81
+ catch (err) {
82
+ if (this.onError) {
83
+ await this.onError(interaction, err, client);
84
+ }
85
+ throw err;
86
+ }
87
+ });
88
+ }
89
+ async safeExecute(commandName, interaction, client, fn) {
90
+ const scope = `${commandName}_EXECUTION`;
91
+ try {
92
+ await fn();
93
+ this.log(`${commandName} context menu command executed`, 'info', scope);
94
+ }
95
+ catch (err) {
96
+ this.log('An Error occurred: ' + err, 'error', scope, true);
97
+ if (this.errorReporter) {
98
+ await this.errorReporter.reportError(err, `Context Menu: ${commandName}`, {
99
+ user: interaction.user.tag,
100
+ userId: interaction.user.id,
101
+ targetUser: interaction.targetUser.tag,
102
+ targetUserId: interaction.targetUser.id,
103
+ guild: interaction.guild?.name,
104
+ guildId: interaction.guildId,
105
+ });
106
+ }
107
+ return await safeReply(interaction, 'An unexpected error occurred.');
108
+ }
109
+ }
110
+ /**
111
+ * Convert this command to Discord API JSON format.
112
+ */
113
+ toJSON() {
114
+ return new ContextMenuCommandBuilder()
115
+ .setName(this.name)
116
+ .setType(ApplicationCommandType.User)
117
+ .toJSON();
118
+ }
119
+ }
package/dist/index.d.ts CHANGED
@@ -3,21 +3,25 @@ export { SubcommandGroup } from './classes/SubcommandGroup.class.js';
3
3
  export { CommandManager } from './classes/CommandManager.class.js';
4
4
  export { DiscordHandler } from './classes/DiscordHandler.class.js';
5
5
  export { ModalManager } from './classes/ModalManager.class.js';
6
- export { PaginatedEmbed } from './utils/PaginatedEmbed.class.js';
6
+ export { UserContextMenuCommand } from './classes/UserContextMenuCommand.class.js';
7
+ export { MessageContextMenuCommand } from './classes/MessageContextMenuCommand.class.js';
7
8
  export type { PermissionLevel } from './types/permission.js';
8
9
  export type { Modal, ModalField } from './types/modal.js';
9
10
  export type { ButtonType } from './types/button.js';
10
11
  export type { ILogger } from './types/logger.js';
11
12
  export type { AnySelectMenuInteraction, ButtonHandler, SelectMenuHandler, ComponentConfig } from './types/component.js';
12
13
  export type { AutocompleteHandler } from './types/autocomplete.js';
14
+ export type { LoadCommandsOptions } from './types/loadCommands.js';
13
15
  export { getPermissionsForLevel } from './utils/permissions.js';
14
16
  export { embedBuilder, createButton, createButtonsRow, createPaginationButtons, } from './utils/embeds.js';
15
17
  export { stringOption, integerOption, booleanOption, userOption, channelOption, roleOption, } from './utils/slashCommandOptions.js';
16
18
  export { safeReply, safeEdit } from './utils/editAndReply.js';
17
19
  export { formatDuration, formatDateToString, formatDateToYYYYMMDDHHMMSS, formatDateToDDMMYYYY, getDaySuffix, capitalizeFirst, } from './utils/formatting.js';
20
+ export { loadCommands } from './utils/loadCommands.js';
18
21
  export { TIMES_MILISECONDS } from './utils/miliseconds.js';
19
22
  export { TToolboxLogger } from './utils/TToolboxLogger.class.js';
20
23
  export { ErrorReporter } from './utils/ErrorReporter.js';
21
24
  export { ComponentManager } from './utils/ComponentManager.class.js';
22
25
  export { AutocompleteManager } from './utils/AutocompleteManager.class.js';
26
+ export { PaginatedEmbed } from './utils/PaginatedEmbed.class.js';
23
27
  export { InteractionError } from './classes/InteractionError.class.js';
package/dist/index.js CHANGED
@@ -4,17 +4,20 @@ export { SubcommandGroup } from './classes/SubcommandGroup.class.js';
4
4
  export { CommandManager } from './classes/CommandManager.class.js';
5
5
  export { DiscordHandler } from './classes/DiscordHandler.class.js';
6
6
  export { ModalManager } from './classes/ModalManager.class.js';
7
- export { PaginatedEmbed } from './utils/PaginatedEmbed.class.js';
7
+ export { UserContextMenuCommand } from './classes/UserContextMenuCommand.class.js';
8
+ export { MessageContextMenuCommand } from './classes/MessageContextMenuCommand.class.js';
8
9
  // Utilities
9
10
  export { getPermissionsForLevel } from './utils/permissions.js';
10
11
  export { embedBuilder, createButton, createButtonsRow, createPaginationButtons, } from './utils/embeds.js';
11
12
  export { stringOption, integerOption, booleanOption, userOption, channelOption, roleOption, } from './utils/slashCommandOptions.js';
12
13
  export { safeReply, safeEdit } from './utils/editAndReply.js';
13
14
  export { formatDuration, formatDateToString, formatDateToYYYYMMDDHHMMSS, formatDateToDDMMYYYY, getDaySuffix, capitalizeFirst, } from './utils/formatting.js';
15
+ export { loadCommands } from './utils/loadCommands.js';
14
16
  export { TIMES_MILISECONDS } from './utils/miliseconds.js';
15
17
  export { TToolboxLogger } from './utils/TToolboxLogger.class.js';
16
18
  export { ErrorReporter } from './utils/ErrorReporter.js';
17
19
  export { ComponentManager } from './utils/ComponentManager.class.js';
18
20
  export { AutocompleteManager } from './utils/AutocompleteManager.class.js';
21
+ export { PaginatedEmbed } from './utils/PaginatedEmbed.class.js';
19
22
  // Errors
20
23
  export { InteractionError } from './classes/InteractionError.class.js';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Options for loading commands from a directory
3
+ */
4
+ export interface LoadCommandsOptions {
5
+ /**
6
+ * Whether to recursively search subdirectories (default: true)
7
+ */
8
+ recursive?: boolean;
9
+ /**
10
+ * Whether to log verbose output to console (default: false)
11
+ */
12
+ verbose?: boolean;
13
+ /**
14
+ * Directory names to skip (default: ['subcommands', 'utils', 'helpers', 'lib'])
15
+ * Case-insensitive partial matching
16
+ */
17
+ skipDirs?: string[];
18
+ /**
19
+ * File name patterns to skip (default: ['Helper', 'Util', '.test', '.spec'])
20
+ * Case-sensitive partial matching
21
+ */
22
+ skipFiles?: string[];
23
+ /**
24
+ * Custom filter function for fine-grained control (optional)
25
+ * Return true to include the file, false to skip
26
+ * Runs AFTER skipDirs and skipFiles checks
27
+ */
28
+ filter?: (filePath: string) => boolean;
29
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,5 @@
1
1
  import Stream from 'stream';
2
- import { ActionRowBuilder, APIAttachment, Attachment, AttachmentBuilder, AttachmentPayload, BufferResolvable, ButtonInteraction, ChannelSelectMenuInteraction, ChatInputCommandInteraction, EmbedBuilder, JSONEncodable, Message, ModalSubmitInteraction, StringSelectMenuInteraction } from 'discord.js';
2
+ import { ActionRowBuilder, APIAttachment, Attachment, AttachmentBuilder, AttachmentPayload, BufferResolvable, ButtonInteraction, ChannelSelectMenuInteraction, ChatInputCommandInteraction, ContextMenuCommandInteraction, EmbedBuilder, JSONEncodable, Message, ModalSubmitInteraction, StringSelectMenuInteraction } from 'discord.js';
3
3
  /**
4
4
  * Safely replies to an interaction, handling deferred/replied states.
5
5
  *
@@ -23,7 +23,7 @@ import { ActionRowBuilder, APIAttachment, Attachment, AttachmentBuilder, Attachm
23
23
  * }
24
24
  * ```
25
25
  */
26
- export declare function safeReply(interaction: ChatInputCommandInteraction | ButtonInteraction | ModalSubmitInteraction | ChannelSelectMenuInteraction | StringSelectMenuInteraction, content: string, ephemeral?: boolean, embeds?: EmbedBuilder[], components?: ActionRowBuilder<any>[], files?: (BufferResolvable | Stream | JSONEncodable<APIAttachment> | Attachment | AttachmentBuilder | AttachmentPayload)[]): Promise<Message>;
26
+ export declare function safeReply(interaction: ChatInputCommandInteraction | ButtonInteraction | ModalSubmitInteraction | ChannelSelectMenuInteraction | StringSelectMenuInteraction | ContextMenuCommandInteraction, content: string, ephemeral?: boolean, embeds?: EmbedBuilder[], components?: ActionRowBuilder<any>[], files?: (BufferResolvable | Stream | JSONEncodable<APIAttachment> | Attachment | AttachmentBuilder | AttachmentPayload)[]): Promise<Message>;
27
27
  /**
28
28
  * Safely edits an interaction reply.
29
29
  *
@@ -0,0 +1,27 @@
1
+ import { LoadCommandsOptions } from '../types/loadCommands';
2
+ /**
3
+ * @experimental
4
+ * Automatically discover and load all commands from a directory.
5
+ *
6
+ * Returns an array of command instances that can be registered with CommandManager.
7
+ *
8
+ * @param dirPath - Absolute path to the directory containing commands
9
+ * @param options - Optional configuration
10
+ * @returns Array of command instances
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { loadCommands } from '@julanzw/ttoolbox-discordjs-framework';
15
+ *
16
+ * // Load all commands
17
+ * const commands = await loadCommands('./src/commands', { verbose: true });
18
+ *
19
+ * // Register them
20
+ * commandManager.registerCommand(commands);
21
+ *
22
+ * // Or filter/process them first
23
+ * const adminCommands = commands.filter(cmd => cmd.name.startsWith('admin'));
24
+ * commandManager.registerCommand(adminCommands);
25
+ * ```
26
+ */
27
+ export declare function loadCommands(dirPath: string, options?: LoadCommandsOptions): Promise<any[]>;