@minesa-org/mini-interaction 0.1.12 → 0.2.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.
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import { ApplicationCommandType, InteractionResponseType, InteractionType, } from "discord-api-types/v10";
6
6
  import { verifyKey } from "discord-interactions";
7
+ import { resolveJSONEncodable } from "../builders/shared.js";
7
8
  import { DISCORD_BASE_URL } from "../utils/constants.js";
8
9
  import { createCommandInteraction } from "../utils/CommandInteractionOptions.js";
9
10
  import { createMessageComponentInteraction, } from "../utils/MessageComponentInteraction.js";
@@ -30,10 +31,12 @@ export class MiniInteraction {
30
31
  commandsDirectory;
31
32
  componentsDirectory;
32
33
  utilsDirectory;
34
+ timeoutConfig;
33
35
  commands = new Map();
34
36
  componentHandlers = new Map();
35
37
  modalHandlers = new Map();
36
38
  htmlTemplateCache = new Map();
39
+ interactionStates = new Map();
37
40
  commandsLoaded = false;
38
41
  loadCommandsPromise = null;
39
42
  componentsLoaded = false;
@@ -43,7 +46,7 @@ export class MiniInteraction {
43
46
  /**
44
47
  * Creates a new MiniInteraction client with optional command auto-loading and custom runtime hooks.
45
48
  */
46
- constructor({ applicationId, publicKey, commandsDirectory, componentsDirectory, utilsDirectory, fetchImplementation, verifyKeyImplementation, }) {
49
+ constructor({ applicationId, publicKey, commandsDirectory, componentsDirectory, utilsDirectory, fetchImplementation, verifyKeyImplementation, timeoutConfig, }) {
47
50
  if (!applicationId) {
48
51
  throw new Error("[MiniInteraction] applicationId is required");
49
52
  }
@@ -70,13 +73,135 @@ export class MiniInteraction {
70
73
  utilsDirectory === false
71
74
  ? null
72
75
  : this.resolveUtilsDirectory(utilsDirectory);
76
+ this.timeoutConfig = {
77
+ initialResponseTimeout: 2800, // Leave 200ms buffer before Discord's 3s limit
78
+ enableTimeoutWarnings: true,
79
+ autoDeferSlowOperations: true,
80
+ enableResponseDebugLogging: false,
81
+ responseAcknowledgmentTimeout: 500, // 500ms to wait for acknowledgment
82
+ responseAcknowledgmentRetries: 2,
83
+ responseAcknowledgmentRetryDelay: 100,
84
+ ...timeoutConfig,
85
+ };
86
+ }
87
+ /**
88
+ * Tracks the state of an interaction to prevent race conditions and double responses.
89
+ */
90
+ trackInteractionState(interactionId, token, state) {
91
+ const existing = this.interactionStates.get(interactionId);
92
+ const now = Date.now();
93
+ this.interactionStates.set(interactionId, {
94
+ state,
95
+ timestamp: now,
96
+ token,
97
+ responseCount: existing ? existing.responseCount + 1 : 1,
98
+ });
99
+ if (this.timeoutConfig.enableResponseDebugLogging) {
100
+ console.log(`[MiniInteraction:DEBUG] Interaction ${interactionId} state: ${state} (${existing ? existing.responseCount + 1 : 1} responses)`);
101
+ }
102
+ }
103
+ /**
104
+ * Checks if an interaction can still respond (not expired and not already responded).
105
+ */
106
+ canRespond(interactionId) {
107
+ const state = this.getInteractionState(interactionId);
108
+ if (!state)
109
+ return true; // New interaction
110
+ // Check if expired (15 minutes)
111
+ if (Date.now() - state.timestamp > 900000) {
112
+ this.trackInteractionState(interactionId, state.token, 'expired');
113
+ return false;
114
+ }
115
+ // Check if already responded
116
+ if (state.state === 'responded') {
117
+ return false;
118
+ }
119
+ return true;
120
+ }
121
+ /**
122
+ * Logs response timing and acknowledgment for debugging.
123
+ */
124
+ logResponseTiming(interactionId, operation, startTime, success) {
125
+ if (!this.timeoutConfig.enableResponseDebugLogging)
126
+ return;
127
+ const elapsed = Date.now() - startTime;
128
+ const status = success ? 'SUCCESS' : 'FAILED';
129
+ console.log(`[MiniInteraction:DEBUG] ${operation} for interaction ${interactionId}: ${status} (${elapsed}ms)`);
130
+ if (success && elapsed > 2000) {
131
+ console.warn(`[MiniInteraction:WARN] ${operation} took ${elapsed}ms - consider using deferReply() for slow operations`);
132
+ }
133
+ }
134
+ /**
135
+ * Simulates waiting for Discord acknowledgment to help debug timing issues.
136
+ * Note: This is a best-effort simulation since actual acknowledgment happens at the HTTP level.
137
+ */
138
+ async simulateAcknowledgmentWait(interactionId, operation) {
139
+ if (!this.timeoutConfig.enableResponseDebugLogging)
140
+ return;
141
+ const timeout = this.timeoutConfig.responseAcknowledgmentTimeout || 500;
142
+ const retries = this.timeoutConfig.responseAcknowledgmentRetries || 2;
143
+ const retryDelay = this.timeoutConfig.responseAcknowledgmentRetryDelay || 100;
144
+ console.log(`[MiniInteraction:DEBUG] Waiting for acknowledgment of ${operation} for interaction ${interactionId}...`);
145
+ for (let attempt = 0; attempt <= retries; attempt++) {
146
+ await new Promise(resolve => setTimeout(resolve, attempt === 0 ? timeout : retryDelay));
147
+ // In a real implementation, this would verify Discord actually received the response
148
+ // For now, we just simulate the wait time
149
+ const state = this.getInteractionState(interactionId);
150
+ if (state?.state === 'responded' || state?.state === 'deferred') {
151
+ console.log(`[MiniInteraction:DEBUG] Acknowledgment confirmed for ${operation} after ${attempt + 1} attempts`);
152
+ return;
153
+ }
154
+ }
155
+ console.warn(`[MiniInteraction:WARN] Acknowledgment timeout for ${operation} on interaction ${interactionId}`);
156
+ }
157
+ /**
158
+ * Enables or disables debug logging for interaction responses and timing.
159
+ * Useful for troubleshooting "didn't respond in time" errors.
160
+ *
161
+ * @param enabled - Whether to enable debug logging
162
+ */
163
+ setResponseDebugLogging(enabled) {
164
+ this.timeoutConfig.enableResponseDebugLogging = enabled;
165
+ console.log(`[MiniInteraction] Response debug logging ${enabled ? 'enabled' : 'disabled'}`);
166
+ }
167
+ /**
168
+ * Gets the current state of an interaction.
169
+ */
170
+ getInteractionState(interactionId) {
171
+ return this.interactionStates.get(interactionId);
172
+ }
173
+ /**
174
+ * Gets the current state of an interaction for debugging purposes.
175
+ *
176
+ * @param interactionId - The interaction ID to check
177
+ * @returns The current interaction state or null if not found
178
+ */
179
+ getInteractionStateInfo(interactionId) {
180
+ const state = this.interactionStates.get(interactionId);
181
+ return state ? { ...state } : null; // Return a copy to prevent external modification
182
+ }
183
+ /**
184
+ * Clears expired interaction states to prevent memory leaks.
185
+ * Call this periodically to clean up old interaction data.
186
+ */
187
+ cleanupExpiredInteractions() {
188
+ const now = Date.now();
189
+ let cleaned = 0;
190
+ for (const [id, state] of this.interactionStates.entries()) {
191
+ // Remove interactions older than 15 minutes
192
+ if (now - state.timestamp > 900000) {
193
+ this.interactionStates.delete(id);
194
+ cleaned++;
195
+ }
196
+ }
197
+ if (cleaned > 0) {
198
+ console.log(`[MiniInteraction] Cleaned up ${cleaned} expired interactions`);
199
+ }
200
+ return cleaned;
73
201
  }
74
202
  normalizeCommandData(data) {
75
203
  if (typeof data === "object" && data !== null) {
76
- const toJSON = data.toJSON;
77
- if (typeof toJSON === "function") {
78
- return toJSON.call(data);
79
- }
204
+ return resolveJSONEncodable(data);
80
205
  }
81
206
  return data;
82
207
  }
@@ -94,12 +219,14 @@ export class MiniInteraction {
94
219
  data: normalizedData,
95
220
  };
96
221
  this.commands.set(commandName, normalizedCommand);
97
- if (normalizedCommand.components && Array.isArray(normalizedCommand.components)) {
222
+ if (normalizedCommand.components &&
223
+ Array.isArray(normalizedCommand.components)) {
98
224
  for (const component of normalizedCommand.components) {
99
225
  this.useComponent(component);
100
226
  }
101
227
  }
102
- if (normalizedCommand.modals && Array.isArray(normalizedCommand.modals)) {
228
+ if (normalizedCommand.modals &&
229
+ Array.isArray(normalizedCommand.modals)) {
103
230
  for (const modal of normalizedCommand.modals) {
104
231
  this.useModal(modal);
105
232
  }
@@ -354,6 +481,7 @@ export class MiniInteraction {
354
481
  * @param request - The request payload containing headers and body data.
355
482
  */
356
483
  async handleRequest(request) {
484
+ const requestStartTime = Date.now();
357
485
  const { body, signature, timestamp } = request;
358
486
  if (!signature || !timestamp) {
359
487
  return {
@@ -390,14 +518,34 @@ export class MiniInteraction {
390
518
  };
391
519
  }
392
520
  if (interaction.type === InteractionType.ApplicationCommand) {
521
+ // Track interaction start
522
+ this.trackInteractionState(interaction.id, interaction.token, 'pending');
393
523
  return this.handleApplicationCommand(interaction);
394
524
  }
395
525
  if (interaction.type === InteractionType.MessageComponent) {
526
+ // Track interaction start
527
+ this.trackInteractionState(interaction.id, interaction.token, 'pending');
396
528
  return this.handleMessageComponent(interaction);
397
529
  }
398
530
  if (interaction.type === InteractionType.ModalSubmit) {
531
+ // Track interaction start
532
+ this.trackInteractionState(interaction.id, interaction.token, 'pending');
399
533
  return this.handleModalSubmit(interaction);
400
534
  }
535
+ // Check total processing time and log potential timeout issues
536
+ const totalProcessingTime = Date.now() - requestStartTime;
537
+ if (this.timeoutConfig.enableTimeoutWarnings &&
538
+ totalProcessingTime >
539
+ this.timeoutConfig.initialResponseTimeout * 0.9) {
540
+ console.warn(`[MiniInteraction] CRITICAL: Interaction processing took ${totalProcessingTime}ms ` +
541
+ `(${Math.round((totalProcessingTime / 3000) * 100)}% of Discord's 3-second limit). ` +
542
+ `This may cause "didn't respond in time" errors. ` +
543
+ `Consider optimizing or using deferReply() for slow operations.`);
544
+ }
545
+ // Log successful response timing for debugging
546
+ if (this.timeoutConfig.enableResponseDebugLogging) {
547
+ console.log(`[MiniInteraction:DEBUG] Request completed in ${totalProcessingTime}ms`);
548
+ }
401
549
  return {
402
550
  status: 400,
403
551
  body: {
@@ -511,8 +659,8 @@ export class MiniInteraction {
511
659
  * The following placeholders are available in the HTML file:
512
660
  * - `{{username}}`, `{{discriminator}}`, `{{user_id}}`, `{{user_tag}}`
513
661
  * - `{{access_token}}`, `{{refresh_token}}`, `{{token_type}}`, `{{scope}}`, `{{expires_at}}`
514
- * - `{{state}}`
515
- */
662
+ * - `{{state}}`
663
+ */
516
664
  connectedOAuthPage(filePath) {
517
665
  const template = this.loadHtmlTemplate(filePath);
518
666
  return ({ user, tokens, state }) => {
@@ -569,7 +717,7 @@ export class MiniInteraction {
569
717
  }
570
718
  /**
571
719
  * Replaces placeholder tokens in a template with escaped HTML values.
572
- */
720
+ */
573
721
  renderHtmlTemplate(template, values, options) {
574
722
  const rawKeys = options?.rawKeys instanceof Set
575
723
  ? options.rawKeys
@@ -666,7 +814,9 @@ export class MiniInteraction {
666
814
  const location = typeof options.successRedirect === "function"
667
815
  ? options.successRedirect(authorizeContext)
668
816
  : options.successRedirect;
669
- if (location && !response.headersSent && !response.writableEnded) {
817
+ if (location &&
818
+ !response.headersSent &&
819
+ !response.writableEnded) {
670
820
  response.statusCode = 302;
671
821
  response.setHeader("location", location);
672
822
  response.end();
@@ -1057,27 +1207,32 @@ export class MiniInteraction {
1057
1207
  }
1058
1208
  try {
1059
1209
  const interactionWithHelpers = createMessageComponentInteraction(interaction);
1060
- const response = await handler(interactionWithHelpers);
1061
- const resolvedResponse = response ?? interactionWithHelpers.getResponse();
1062
- if (!resolvedResponse) {
1063
- return {
1064
- status: 500,
1065
- body: {
1066
- error: `[MiniInteraction] Component "${customId}" did not return a response. ` +
1067
- "Return an APIInteractionResponse to acknowledge the interaction.",
1068
- },
1069
- };
1070
- }
1210
+ // Wrap component handler with timeout
1211
+ const timeoutWrapper = createTimeoutWrapper(async () => {
1212
+ const response = await handler(interactionWithHelpers);
1213
+ const resolvedResponse = response ?? interactionWithHelpers.getResponse();
1214
+ if (!resolvedResponse) {
1215
+ throw new Error(`Component "${customId}" did not return a response. ` +
1216
+ "Return an APIInteractionResponse to acknowledge the interaction.");
1217
+ }
1218
+ return resolvedResponse;
1219
+ }, this.timeoutConfig.initialResponseTimeout, `Component "${customId}"`, this.timeoutConfig.enableTimeoutWarnings);
1220
+ const resolvedResponse = await timeoutWrapper();
1071
1221
  return {
1072
1222
  status: 200,
1073
1223
  body: resolvedResponse,
1074
1224
  };
1075
1225
  }
1076
1226
  catch (error) {
1227
+ const errorMessage = error instanceof Error ? error.message : String(error);
1228
+ if (errorMessage.includes("Handler timeout")) {
1229
+ console.error(`[MiniInteraction] CRITICAL: Component "${customId}" timed out. ` +
1230
+ `This will result in "didn't respond in time" errors for users.`);
1231
+ }
1077
1232
  return {
1078
1233
  status: 500,
1079
1234
  body: {
1080
- error: `[MiniInteraction] Component "${customId}" failed: ${String(error)}`,
1235
+ error: `[MiniInteraction] Component "${customId}" failed: ${errorMessage}`,
1081
1236
  },
1082
1237
  };
1083
1238
  }
@@ -1107,27 +1262,32 @@ export class MiniInteraction {
1107
1262
  }
1108
1263
  try {
1109
1264
  const interactionWithHelpers = createModalSubmitInteraction(interaction);
1110
- const response = await handler(interactionWithHelpers);
1111
- const resolvedResponse = response ?? interactionWithHelpers.getResponse();
1112
- if (!resolvedResponse) {
1113
- return {
1114
- status: 500,
1115
- body: {
1116
- error: `[MiniInteraction] Modal "${customId}" did not return a response. ` +
1117
- "Return an APIInteractionResponse to acknowledge the interaction.",
1118
- },
1119
- };
1120
- }
1265
+ // Wrap modal handler with timeout
1266
+ const timeoutWrapper = createTimeoutWrapper(async () => {
1267
+ const response = await handler(interactionWithHelpers);
1268
+ const resolvedResponse = response ?? interactionWithHelpers.getResponse();
1269
+ if (!resolvedResponse) {
1270
+ throw new Error(`Modal "${customId}" did not return a response. ` +
1271
+ "Return an APIInteractionResponse to acknowledge the interaction.");
1272
+ }
1273
+ return resolvedResponse;
1274
+ }, this.timeoutConfig.initialResponseTimeout, `Modal "${customId}"`, this.timeoutConfig.enableTimeoutWarnings);
1275
+ const resolvedResponse = await timeoutWrapper();
1121
1276
  return {
1122
1277
  status: 200,
1123
1278
  body: resolvedResponse,
1124
1279
  };
1125
1280
  }
1126
1281
  catch (error) {
1282
+ const errorMessage = error instanceof Error ? error.message : String(error);
1283
+ if (errorMessage.includes("Handler timeout")) {
1284
+ console.error(`[MiniInteraction] CRITICAL: Modal "${customId}" timed out. ` +
1285
+ `This will result in "didn't respond in time" errors for users.`);
1286
+ }
1127
1287
  return {
1128
1288
  status: 500,
1129
1289
  body: {
1130
- error: `[MiniInteraction] Modal "${customId}" failed: ${String(error)}`,
1290
+ error: `[MiniInteraction] Modal "${customId}" failed: ${errorMessage}`,
1131
1291
  },
1132
1292
  };
1133
1293
  }
@@ -1159,41 +1319,54 @@ export class MiniInteraction {
1159
1319
  try {
1160
1320
  let response;
1161
1321
  let resolvedResponse = null;
1162
- // Check if it's a chat input (slash) command
1163
- if (commandInteraction.data.type ===
1164
- ApplicationCommandType.ChatInput) {
1165
- const interactionWithHelpers = createCommandInteraction(commandInteraction);
1166
- response = await command.handler(interactionWithHelpers);
1167
- resolvedResponse =
1168
- response ?? interactionWithHelpers.getResponse();
1169
- }
1170
- else if (commandInteraction.data.type === ApplicationCommandType.User) {
1171
- // User context menu command
1172
- const interactionWithHelpers = createUserContextMenuInteraction(commandInteraction);
1173
- response = await command.handler(interactionWithHelpers);
1174
- resolvedResponse =
1175
- response ?? interactionWithHelpers.getResponse();
1176
- }
1177
- else if (commandInteraction.data.type ===
1178
- ApplicationCommandType.PrimaryEntryPoint) {
1179
- const interactionWithHelpers = createAppCommandInteraction(commandInteraction);
1180
- response = await command.handler(interactionWithHelpers);
1181
- resolvedResponse =
1182
- response ?? interactionWithHelpers.getResponse();
1183
- }
1184
- else if (commandInteraction.data.type === ApplicationCommandType.Message) {
1185
- // Message context menu command
1186
- const interactionWithHelpers = createMessageContextMenuInteraction(commandInteraction);
1187
- response = await command.handler(interactionWithHelpers);
1188
- resolvedResponse =
1189
- response ?? interactionWithHelpers.getResponse();
1190
- }
1191
- else {
1192
- // Unknown command type
1193
- response = await command.handler(commandInteraction);
1194
- resolvedResponse = response ?? null;
1195
- }
1322
+ // Create a timeout wrapper for the command handler
1323
+ const timeoutWrapper = createTimeoutWrapper(async () => {
1324
+ // Check if it's a chat input (slash) command
1325
+ if (commandInteraction.data.type ===
1326
+ ApplicationCommandType.ChatInput) {
1327
+ const interactionWithHelpers = createCommandInteraction(commandInteraction, {
1328
+ canRespond: (id) => this.canRespond(id),
1329
+ trackResponse: (id, token, state) => this.trackInteractionState(id, token, state),
1330
+ logTiming: (id, op, start, success) => this.logResponseTiming(id, op, start, success),
1331
+ });
1332
+ response = await command.handler(interactionWithHelpers);
1333
+ resolvedResponse =
1334
+ response ?? interactionWithHelpers.getResponse();
1335
+ }
1336
+ else if (commandInteraction.data.type ===
1337
+ ApplicationCommandType.User) {
1338
+ // User context menu command
1339
+ const interactionWithHelpers = createUserContextMenuInteraction(commandInteraction);
1340
+ response = await command.handler(interactionWithHelpers);
1341
+ resolvedResponse =
1342
+ response ?? interactionWithHelpers.getResponse();
1343
+ }
1344
+ else if (commandInteraction.data.type ===
1345
+ ApplicationCommandType.PrimaryEntryPoint) {
1346
+ const interactionWithHelpers = createAppCommandInteraction(commandInteraction);
1347
+ response = await command.handler(interactionWithHelpers);
1348
+ resolvedResponse =
1349
+ response ?? interactionWithHelpers.getResponse();
1350
+ }
1351
+ else if (commandInteraction.data.type ===
1352
+ ApplicationCommandType.Message) {
1353
+ // Message context menu command
1354
+ const interactionWithHelpers = createMessageContextMenuInteraction(commandInteraction);
1355
+ response = await command.handler(interactionWithHelpers);
1356
+ resolvedResponse =
1357
+ response ?? interactionWithHelpers.getResponse();
1358
+ }
1359
+ else {
1360
+ // Unknown command type
1361
+ response = await command.handler(commandInteraction);
1362
+ resolvedResponse = response ?? null;
1363
+ }
1364
+ }, this.timeoutConfig.initialResponseTimeout, `Command "${commandName}"`, this.timeoutConfig.enableTimeoutWarnings);
1365
+ await timeoutWrapper();
1196
1366
  if (!resolvedResponse) {
1367
+ console.error(`[MiniInteraction] Command "${commandName}" did not return a response. ` +
1368
+ "This indicates the handler completed but no response was generated. " +
1369
+ "Check that deferReply(), reply(), showModal(), or a direct response is returned.");
1197
1370
  return {
1198
1371
  status: 500,
1199
1372
  body: {
@@ -1209,10 +1382,18 @@ export class MiniInteraction {
1209
1382
  };
1210
1383
  }
1211
1384
  catch (error) {
1385
+ const errorMessage = error instanceof Error ? error.message : String(error);
1386
+ // Check if this was a timeout error
1387
+ if (errorMessage.includes("Handler timeout")) {
1388
+ console.error(`[MiniInteraction] CRITICAL: Command "${commandName}" timed out before responding to Discord. ` +
1389
+ `This will result in "didn't respond in time" errors for users. ` +
1390
+ `Handler took longer than ${this.timeoutConfig.initialResponseTimeout}ms to complete. ` +
1391
+ `Consider using deferReply() for operations that take more than 3 seconds.`);
1392
+ }
1212
1393
  return {
1213
1394
  status: 500,
1214
1395
  body: {
1215
- error: `[MiniInteraction] Command "${commandName}" failed: ${String(error)}`,
1396
+ error: `[MiniInteraction] Command "${commandName}" failed: ${errorMessage}`,
1216
1397
  },
1217
1398
  };
1218
1399
  }
@@ -1382,3 +1563,45 @@ function resolveOAuthConfig(provided) {
1382
1563
  redirectUri,
1383
1564
  };
1384
1565
  }
1566
+ /**
1567
+ * Wraps a handler function with timeout detection and error handling.
1568
+ */
1569
+ function createTimeoutWrapper(handler, timeoutMs, handlerName, enableWarnings = true) {
1570
+ return async (...args) => {
1571
+ const startTime = Date.now();
1572
+ let timeoutId;
1573
+ const timeoutPromise = new Promise((_, reject) => {
1574
+ timeoutId = setTimeout(() => {
1575
+ const elapsed = Date.now() - startTime;
1576
+ console.error(`[MiniInteraction] ${handlerName} timed out after ${elapsed}ms (limit: ${timeoutMs}ms)`);
1577
+ reject(new Error(`Handler timeout: ${handlerName} exceeded ${timeoutMs}ms limit`));
1578
+ }, timeoutMs);
1579
+ });
1580
+ try {
1581
+ const result = await Promise.race([
1582
+ Promise.resolve(handler(...args)),
1583
+ timeoutPromise,
1584
+ ]);
1585
+ if (timeoutId) {
1586
+ clearTimeout(timeoutId);
1587
+ }
1588
+ const elapsed = Date.now() - startTime;
1589
+ if (enableWarnings && elapsed > timeoutMs * 0.8) {
1590
+ console.warn(`[MiniInteraction] ${handlerName} completed in ${elapsed}ms (${Math.round((elapsed / timeoutMs) * 100)}% of timeout limit)`);
1591
+ }
1592
+ return result;
1593
+ }
1594
+ catch (error) {
1595
+ if (timeoutId) {
1596
+ clearTimeout(timeoutId);
1597
+ }
1598
+ // Re-throw the error with additional context
1599
+ if (error instanceof Error &&
1600
+ error.message.includes("Handler timeout")) {
1601
+ throw error;
1602
+ }
1603
+ console.error(`[MiniInteraction] ${handlerName} failed:`, error);
1604
+ throw error;
1605
+ }
1606
+ };
1607
+ }
package/dist/index.d.ts CHANGED
@@ -5,21 +5,21 @@ export { CommandBuilder, CommandContext, IntegrationType, } from "./commands/Com
5
5
  export { UserCommandBuilder, MessageCommandBuilder, AppCommandBuilder, } from "./commands/ContextMenuCommandBuilder.js";
6
6
  export type { AttachmentOptionBuilder, ChannelOptionBuilder, MentionableOptionBuilder, NumberOptionBuilder, RoleOptionBuilder, StringOptionBuilder, SubcommandBuilder, SubcommandGroupBuilder, UserOptionBuilder, } from "./commands/CommandBuilder.js";
7
7
  export { CommandInteractionOptionResolver, createCommandInteraction, } from "./utils/CommandInteractionOptions.js";
8
- export type { CommandInteraction, MentionableOption, ResolvedUserOption, } from "./utils/CommandInteractionOptions.js";
9
- export type { UserContextMenuInteraction, MessageContextMenuInteraction, AppCommandInteraction, } from "./utils/ContextMenuInteraction.js";
10
- export type { MiniInteractionFetchHandler, MiniInteractionNodeHandler, MiniInteractionHandlerResult, MiniInteractionRequest, MiniInteractionOptions, DiscordOAuthAuthorizeContext, DiscordOAuthCallbackOptions, DiscordOAuthCallbackTemplates, DiscordOAuthErrorTemplateContext, DiscordOAuthServerErrorTemplateContext, DiscordOAuthStateTemplateContext, DiscordOAuthSuccessTemplateContext, DiscordOAuthVerificationPageOptions, } from "./clients/MiniInteraction.js";
11
- export type { MiniInteractionCommand, SlashCommandHandler, UserCommandHandler, MessageCommandHandler, AppCommandHandler, CommandHandler, } from "./types/Commands.js";
12
- export type { MiniInteractionComponent, MiniInteractionButtonHandler, MiniInteractionStringSelectHandler, MiniInteractionRoleSelectHandler, MiniInteractionUserSelectHandler, MiniInteractionChannelSelectHandler, MiniInteractionMentionableSelectHandler, MiniInteractionComponentHandler, MiniInteractionModal, MiniInteractionModalHandler, MiniInteractionHandler, } from "./clients/MiniInteraction.js";
13
- export type { MessageComponentInteraction, ButtonInteraction, StringSelectInteraction, RoleSelectInteraction, UserSelectInteraction, ChannelSelectInteraction, MentionableSelectInteraction, ResolvedUserOption as ComponentResolvedUserOption, ResolvedMentionableOption as ComponentResolvedMentionableOption, } from "./utils/MessageComponentInteraction.js";
14
- export type { ModalSubmitInteraction } from "./utils/ModalSubmitInteraction.js";
8
+ export { CommandInteraction, MentionableOption, ResolvedUserOption, } from "./utils/CommandInteractionOptions.js";
9
+ export { UserContextMenuInteraction, MessageContextMenuInteraction, AppCommandInteraction, } from "./utils/ContextMenuInteraction.js";
10
+ export type { InteractionFetchHandler, InteractionNodeHandler, InteractionHandlerResult, InteractionRequest, InteractionClientOptions, DiscordOAuthAuthorizeContext, DiscordOAuthCallbackOptions, DiscordOAuthCallbackTemplates, DiscordOAuthErrorTemplateContext, DiscordOAuthServerErrorTemplateContext, DiscordOAuthStateTemplateContext, DiscordOAuthSuccessTemplateContext, DiscordOAuthVerificationPageOptions, } from "./clients/MiniInteraction.js";
11
+ export type { InteractionCommand, SlashCommandHandler, UserCommandHandler, MessageCommandHandler, AppCommandHandler, CommandHandler, } from "./types/Commands.js";
12
+ export type { ComponentCommand, ButtonComponentHandler, StringSelectComponentHandler, RoleSelectComponentHandler, UserSelectComponentHandler, ChannelSelectComponentHandler, MentionableSelectComponentHandler, ComponentHandler, ModalCommand, ModalHandler, InteractionHandler, } from "./clients/MiniInteraction.js";
13
+ export { MessageComponentInteraction, ButtonInteraction, StringSelectInteraction, RoleSelectInteraction, UserSelectInteraction, ChannelSelectInteraction, MentionableSelectInteraction, ResolvedUserOption as ComponentResolvedUserOption, ResolvedMentionableOption as ComponentResolvedMentionableOption, } from "./utils/MessageComponentInteraction.js";
14
+ export { ModalSubmitInteraction } from "./utils/ModalSubmitInteraction.js";
15
15
  export { RoleConnectionMetadataTypes } from "./types/RoleConnectionMetadataTypes.js";
16
16
  export { ChannelType } from "./types/ChannelType.js";
17
- export { InteractionFollowUpFlags, InteractionReplyFlags, } from "./types/InteractionFlags.js";
17
+ export { InteractionFollowUpFlags, InteractionReplyFlags, InteractionFlags, } from "./types/InteractionFlags.js";
18
18
  export { ButtonStyle } from "./types/ButtonStyle.js";
19
19
  export { SeparatorSpacingSize } from "./types/SeparatorSpacingSize.js";
20
20
  export { TextInputStyle } from "discord-api-types/v10";
21
21
  export { MiniPermFlags } from "./types/PermissionFlags.js";
22
- export type { MiniComponentActionRow, MiniComponentMessageActionRow, } from "./types/ComponentTypes.js";
22
+ export type { ActionRowComponent, MessageActionRowComponent, } from "./types/ComponentTypes.js";
23
23
  export * from "./builders/index.js";
24
24
  export { MiniDataBuilder } from "./database/MiniDataBuilder.js";
25
25
  export type { DataField } from "./database/MiniDataBuilder.js";
package/dist/index.js CHANGED
@@ -3,9 +3,13 @@ export { MiniInteraction } from "./clients/MiniInteraction.js";
3
3
  export { CommandBuilder, CommandContext, IntegrationType, } from "./commands/CommandBuilder.js";
4
4
  export { UserCommandBuilder, MessageCommandBuilder, AppCommandBuilder, } from "./commands/ContextMenuCommandBuilder.js";
5
5
  export { CommandInteractionOptionResolver, createCommandInteraction, } from "./utils/CommandInteractionOptions.js";
6
+ export { CommandInteraction, MentionableOption, ResolvedUserOption, } from "./utils/CommandInteractionOptions.js";
7
+ export { UserContextMenuInteraction, MessageContextMenuInteraction, AppCommandInteraction, } from "./utils/ContextMenuInteraction.js";
8
+ export { MessageComponentInteraction, ButtonInteraction, StringSelectInteraction, RoleSelectInteraction, UserSelectInteraction, ChannelSelectInteraction, MentionableSelectInteraction, ResolvedUserOption as ComponentResolvedUserOption, ResolvedMentionableOption as ComponentResolvedMentionableOption, } from "./utils/MessageComponentInteraction.js";
9
+ export { ModalSubmitInteraction } from "./utils/ModalSubmitInteraction.js";
6
10
  export { RoleConnectionMetadataTypes } from "./types/RoleConnectionMetadataTypes.js";
7
11
  export { ChannelType } from "./types/ChannelType.js";
8
- export { InteractionFollowUpFlags, InteractionReplyFlags, } from "./types/InteractionFlags.js";
12
+ export { InteractionFollowUpFlags, InteractionReplyFlags, InteractionFlags, } from "./types/InteractionFlags.js";
9
13
  export { ButtonStyle } from "./types/ButtonStyle.js";
10
14
  export { SeparatorSpacingSize } from "./types/SeparatorSpacingSize.js";
11
15
  export { TextInputStyle } from "discord-api-types/v10";
@@ -1,7 +1,8 @@
1
1
  import type { APIInteractionResponse, RESTPostAPIChatInputApplicationCommandsJSONBody, RESTPostAPIContextMenuApplicationCommandsJSONBody, RESTPostAPIPrimaryEntryPointApplicationCommandJSONBody } from "discord-api-types/v10";
2
2
  import type { CommandInteraction } from "../utils/CommandInteractionOptions.js";
3
3
  import type { UserContextMenuInteraction, MessageContextMenuInteraction, AppCommandInteraction } from "../utils/ContextMenuInteraction.js";
4
- import type { MiniInteractionComponent, MiniInteractionModal } from "../clients/MiniInteraction.js";
4
+ import type { JSONEncodable } from "../builders/shared.js";
5
+ import type { ComponentCommand, ModalCommand } from "../clients/MiniInteraction.js";
5
6
  import type { CommandBuilder } from "../commands/CommandBuilder.js";
6
7
  import type { MessageCommandBuilder, UserCommandBuilder, AppCommandBuilder } from "../commands/ContextMenuCommandBuilder.js";
7
8
  /** Handler signature for slash command executions within MiniInteraction. */
@@ -15,19 +16,19 @@ export type AppCommandHandler = (interaction: AppCommandInteraction) => Promise<
15
16
  /** Union of all command handler types. */
16
17
  export type CommandHandler = SlashCommandHandler | UserCommandHandler | MessageCommandHandler | AppCommandHandler;
17
18
  /** Structure representing a slash command definition and its runtime handler. */
18
- export type MiniInteractionCommand = {
19
- data: RESTPostAPIChatInputApplicationCommandsJSONBody | RESTPostAPIContextMenuApplicationCommandsJSONBody | RESTPostAPIPrimaryEntryPointApplicationCommandJSONBody | CommandBuilder | UserCommandBuilder | MessageCommandBuilder | AppCommandBuilder;
19
+ export type InteractionCommand = {
20
+ data: RESTPostAPIChatInputApplicationCommandsJSONBody | RESTPostAPIContextMenuApplicationCommandsJSONBody | RESTPostAPIPrimaryEntryPointApplicationCommandJSONBody | CommandBuilder | UserCommandBuilder | MessageCommandBuilder | AppCommandBuilder | JSONEncodable<RESTPostAPIChatInputApplicationCommandsJSONBody | RESTPostAPIContextMenuApplicationCommandsJSONBody | RESTPostAPIPrimaryEntryPointApplicationCommandJSONBody>;
20
21
  handler: CommandHandler;
21
22
  /**
22
23
  * Optional array of component handlers related to this command.
23
24
  * These will be automatically registered when the command is loaded.
24
25
  */
25
- components?: MiniInteractionComponent[];
26
+ components?: ComponentCommand[];
26
27
  /**
27
28
  * Optional array of modal handlers related to this command.
28
29
  * These will be automatically registered when the command is loaded.
29
30
  */
30
- modals?: MiniInteractionModal[];
31
+ modals?: ModalCommand[];
31
32
  };
32
33
  /** Map of command names to their registered MiniInteraction command definitions. */
33
- export type MiniInteractionCommandsMap = Map<string, MiniInteractionCommand>;
34
+ export type InteractionCommandsMap = Map<string, InteractionCommand>;
@@ -1,5 +1,5 @@
1
1
  import type { APIComponentInActionRow, APIComponentInMessageActionRow } from "discord-api-types/v10";
2
- /** * Components that can appear inside a Discord action row container. */
3
- export type MiniComponentMessageActionRow = APIComponentInMessageActionRow;
4
- /** Components that are valid inside message action rows. */
5
- export type MiniComponentActionRow = APIComponentInActionRow;
2
+ /** Defines a component structure for use in ActionRow builders. */
3
+ export type ActionRowComponent = APIComponentInActionRow;
4
+ /** Defines a message component structure for use in message builders. */
5
+ export type MessageActionRowComponent = APIComponentInMessageActionRow;
@@ -1,10 +1,9 @@
1
- /** Flags available when responding directly to an interaction. */
2
- export declare enum InteractionReplyFlags {
3
- Ephemeral = 64,
4
- IsComponentsV2 = 32768
5
- }
6
- /** Flags available when sending a follow-up message for an interaction. */
7
- export declare enum InteractionFollowUpFlags {
1
+ /** Flags available for interaction responses. */
2
+ export declare enum InteractionFlags {
8
3
  Ephemeral = 64,
9
4
  IsComponentsV2 = 32768
10
5
  }
6
+ /** @deprecated Use InteractionFlags instead. */
7
+ export { InteractionFlags as InteractionReplyFlags };
8
+ /** @deprecated Use InteractionFlags instead. */
9
+ export { InteractionFlags as InteractionFollowUpFlags };
@@ -1,12 +1,10 @@
1
- /** Flags available when responding directly to an interaction. */
2
- export var InteractionReplyFlags;
3
- (function (InteractionReplyFlags) {
4
- InteractionReplyFlags[InteractionReplyFlags["Ephemeral"] = 64] = "Ephemeral";
5
- InteractionReplyFlags[InteractionReplyFlags["IsComponentsV2"] = 32768] = "IsComponentsV2";
6
- })(InteractionReplyFlags || (InteractionReplyFlags = {}));
7
- /** Flags available when sending a follow-up message for an interaction. */
8
- export var InteractionFollowUpFlags;
9
- (function (InteractionFollowUpFlags) {
10
- InteractionFollowUpFlags[InteractionFollowUpFlags["Ephemeral"] = 64] = "Ephemeral";
11
- InteractionFollowUpFlags[InteractionFollowUpFlags["IsComponentsV2"] = 32768] = "IsComponentsV2";
12
- })(InteractionFollowUpFlags || (InteractionFollowUpFlags = {}));
1
+ /** Flags available for interaction responses. */
2
+ export var InteractionFlags;
3
+ (function (InteractionFlags) {
4
+ InteractionFlags[InteractionFlags["Ephemeral"] = 64] = "Ephemeral";
5
+ InteractionFlags[InteractionFlags["IsComponentsV2"] = 32768] = "IsComponentsV2";
6
+ })(InteractionFlags || (InteractionFlags = {}));
7
+ /** @deprecated Use InteractionFlags instead. */
8
+ export { InteractionFlags as InteractionReplyFlags };
9
+ /** @deprecated Use InteractionFlags instead. */
10
+ export { InteractionFlags as InteractionFollowUpFlags };