@minesa-org/mini-interaction 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clients/MiniInteraction.d.ts +0 -40
- package/dist/clients/MiniInteraction.js +47 -91
- package/dist/database/MiniDatabase.js +0 -5
- package/dist/utils/CommandInteractionOptions.d.ts +2 -1
- package/dist/utils/CommandInteractionOptions.js +5 -4
- package/dist/utils/ContextMenuInteraction.d.ts +10 -3
- package/dist/utils/ContextMenuInteraction.js +16 -9
- package/dist/utils/MessageComponentInteraction.d.ts +4 -1
- package/dist/utils/MessageComponentInteraction.js +8 -3
- package/dist/utils/ModalSubmitInteraction.d.ts +4 -1
- package/dist/utils/ModalSubmitInteraction.js +8 -3
- package/package.json +1 -1
|
@@ -49,15 +49,6 @@ export type InteractionTimeoutConfig = {
|
|
|
49
49
|
/** Whether to enable debug logging for interaction responses (default: false) */
|
|
50
50
|
enableResponseDebugLogging?: boolean;
|
|
51
51
|
};
|
|
52
|
-
/** Enhanced timeout configuration with response acknowledgment settings. */
|
|
53
|
-
export type InteractionTimeoutConfigV2 = InteractionTimeoutConfig & {
|
|
54
|
-
/** Time to wait for Discord acknowledgment after sending response (default: 500ms) */
|
|
55
|
-
responseAcknowledgmentTimeout?: number;
|
|
56
|
-
/** Maximum retries for response acknowledgment (default: 2) */
|
|
57
|
-
responseAcknowledgmentRetries?: number;
|
|
58
|
-
/** Delay between acknowledgment retries (default: 100ms) */
|
|
59
|
-
responseAcknowledgmentRetryDelay?: number;
|
|
60
|
-
};
|
|
61
52
|
/** Handler signature invoked for Discord button interactions. */
|
|
62
53
|
export type ButtonComponentHandler = (interaction: ButtonInteraction) => Promise<APIInteractionResponse | void> | APIInteractionResponse | void;
|
|
63
54
|
/** Handler signature invoked for Discord string select menu interactions. */
|
|
@@ -184,46 +175,15 @@ export declare class MiniInteraction {
|
|
|
184
175
|
* Creates a new MiniInteraction client with optional command auto-loading and custom runtime hooks.
|
|
185
176
|
*/
|
|
186
177
|
constructor({ applicationId, publicKey, commandsDirectory, componentsDirectory, utilsDirectory, fetchImplementation, verifyKeyImplementation, timeoutConfig, }: InteractionClientOptions);
|
|
187
|
-
/**
|
|
188
|
-
* Tracks the state of an interaction to prevent race conditions and double responses.
|
|
189
|
-
*/
|
|
190
178
|
private trackInteractionState;
|
|
191
179
|
/**
|
|
192
180
|
* Checks if an interaction can still respond (not expired and not already responded).
|
|
193
181
|
*/
|
|
194
182
|
private canRespond;
|
|
195
|
-
/**
|
|
196
|
-
* Logs response timing and acknowledgment for debugging.
|
|
197
|
-
*/
|
|
198
|
-
private logResponseTiming;
|
|
199
|
-
/**
|
|
200
|
-
* Simulates waiting for Discord acknowledgment to help debug timing issues.
|
|
201
|
-
* Note: This is a best-effort simulation since actual acknowledgment happens at the HTTP level.
|
|
202
|
-
*/
|
|
203
|
-
private simulateAcknowledgmentWait;
|
|
204
|
-
/**
|
|
205
|
-
* Enables or disables debug logging for interaction responses and timing.
|
|
206
|
-
* Useful for troubleshooting "didn't respond in time" errors.
|
|
207
|
-
*
|
|
208
|
-
* @param enabled - Whether to enable debug logging
|
|
209
|
-
*/
|
|
210
|
-
setResponseDebugLogging(enabled: boolean): void;
|
|
211
183
|
/**
|
|
212
184
|
* Gets the current state of an interaction.
|
|
213
185
|
*/
|
|
214
186
|
private getInteractionState;
|
|
215
|
-
/**
|
|
216
|
-
* Gets the current state of an interaction for debugging purposes.
|
|
217
|
-
*
|
|
218
|
-
* @param interactionId - The interaction ID to check
|
|
219
|
-
* @returns The current interaction state or null if not found
|
|
220
|
-
*/
|
|
221
|
-
getInteractionStateInfo(interactionId: string): {
|
|
222
|
-
state: "pending" | "deferred" | "responded" | "expired";
|
|
223
|
-
timestamp: number;
|
|
224
|
-
token: string;
|
|
225
|
-
responseCount: number;
|
|
226
|
-
} | null;
|
|
227
187
|
/**
|
|
228
188
|
* Clears expired interaction states to prevent memory leaks.
|
|
229
189
|
* Call this periodically to clean up old interaction data.
|
|
@@ -78,27 +78,16 @@ export class MiniInteraction {
|
|
|
78
78
|
enableTimeoutWarnings: true,
|
|
79
79
|
autoDeferSlowOperations: true,
|
|
80
80
|
enableResponseDebugLogging: false,
|
|
81
|
-
responseAcknowledgmentTimeout: 500, // 500ms to wait for acknowledgment
|
|
82
|
-
responseAcknowledgmentRetries: 2,
|
|
83
|
-
responseAcknowledgmentRetryDelay: 100,
|
|
84
81
|
...timeoutConfig,
|
|
85
82
|
};
|
|
86
83
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Tracks the state of an interaction to prevent race conditions and double responses.
|
|
89
|
-
*/
|
|
90
84
|
trackInteractionState(interactionId, token, state) {
|
|
91
|
-
const existing = this.interactionStates.get(interactionId);
|
|
92
85
|
const now = Date.now();
|
|
93
86
|
this.interactionStates.set(interactionId, {
|
|
94
87
|
state,
|
|
95
88
|
timestamp: now,
|
|
96
89
|
token,
|
|
97
|
-
responseCount: existing ? existing.responseCount + 1 : 1,
|
|
98
90
|
});
|
|
99
|
-
if (this.timeoutConfig.enableResponseDebugLogging) {
|
|
100
|
-
console.log(`[MiniInteraction:DEBUG] Interaction ${interactionId} state: ${state} (${existing ? existing.responseCount + 1 : 1} responses)`);
|
|
101
|
-
}
|
|
102
91
|
}
|
|
103
92
|
/**
|
|
104
93
|
* Checks if an interaction can still respond (not expired and not already responded).
|
|
@@ -118,68 +107,12 @@ export class MiniInteraction {
|
|
|
118
107
|
}
|
|
119
108
|
return true;
|
|
120
109
|
}
|
|
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
110
|
/**
|
|
168
111
|
* Gets the current state of an interaction.
|
|
169
112
|
*/
|
|
170
113
|
getInteractionState(interactionId) {
|
|
171
114
|
return this.interactionStates.get(interactionId);
|
|
172
115
|
}
|
|
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
116
|
/**
|
|
184
117
|
* Clears expired interaction states to prevent memory leaks.
|
|
185
118
|
* Call this periodically to clean up old interaction data.
|
|
@@ -194,9 +127,6 @@ export class MiniInteraction {
|
|
|
194
127
|
cleaned++;
|
|
195
128
|
}
|
|
196
129
|
}
|
|
197
|
-
if (cleaned > 0) {
|
|
198
|
-
console.log(`[MiniInteraction] Cleaned up ${cleaned} expired interactions`);
|
|
199
|
-
}
|
|
200
130
|
return cleaned;
|
|
201
131
|
}
|
|
202
132
|
normalizeCommandData(data) {
|
|
@@ -530,10 +460,6 @@ export class MiniInteraction {
|
|
|
530
460
|
`This may cause "didn't respond in time" errors. ` +
|
|
531
461
|
`Consider optimizing or using deferReply() for slow operations.`);
|
|
532
462
|
}
|
|
533
|
-
// Log successful response timing for debugging
|
|
534
|
-
if (this.timeoutConfig.enableResponseDebugLogging) {
|
|
535
|
-
console.log(`[MiniInteraction:DEBUG] Request completed in ${totalProcessingTime}ms`);
|
|
536
|
-
}
|
|
537
463
|
return {
|
|
538
464
|
status: 400,
|
|
539
465
|
body: {
|
|
@@ -1194,8 +1120,15 @@ export class MiniInteraction {
|
|
|
1194
1120
|
};
|
|
1195
1121
|
}
|
|
1196
1122
|
try {
|
|
1197
|
-
|
|
1198
|
-
|
|
1123
|
+
// Create an acknowledgment promise that resolves when the handler calls reply() or deferReply()
|
|
1124
|
+
let ackResolver = null;
|
|
1125
|
+
const ackPromise = new Promise((resolve) => {
|
|
1126
|
+
ackResolver = resolve;
|
|
1127
|
+
});
|
|
1128
|
+
const interactionWithHelpers = createMessageComponentInteraction(interaction, {
|
|
1129
|
+
onAck: (response) => ackResolver?.(response),
|
|
1130
|
+
});
|
|
1131
|
+
// Wrap component handler with timeout and acknowledgment
|
|
1199
1132
|
const timeoutWrapper = createTimeoutWrapper(async () => {
|
|
1200
1133
|
const response = await handler(interactionWithHelpers);
|
|
1201
1134
|
const resolvedResponse = response ?? interactionWithHelpers.getResponse();
|
|
@@ -1204,7 +1137,7 @@ export class MiniInteraction {
|
|
|
1204
1137
|
"Return an APIInteractionResponse to acknowledge the interaction.");
|
|
1205
1138
|
}
|
|
1206
1139
|
return resolvedResponse;
|
|
1207
|
-
}, this.timeoutConfig.initialResponseTimeout, `Component "${customId}"`, this.timeoutConfig.enableTimeoutWarnings);
|
|
1140
|
+
}, this.timeoutConfig.initialResponseTimeout, `Component "${customId}"`, this.timeoutConfig.enableTimeoutWarnings, ackPromise);
|
|
1208
1141
|
const resolvedResponse = await timeoutWrapper();
|
|
1209
1142
|
return {
|
|
1210
1143
|
status: 200,
|
|
@@ -1249,8 +1182,15 @@ export class MiniInteraction {
|
|
|
1249
1182
|
};
|
|
1250
1183
|
}
|
|
1251
1184
|
try {
|
|
1252
|
-
|
|
1253
|
-
|
|
1185
|
+
// Create an acknowledgment promise for modals
|
|
1186
|
+
let ackResolver = null;
|
|
1187
|
+
const ackPromise = new Promise((resolve) => {
|
|
1188
|
+
ackResolver = resolve;
|
|
1189
|
+
});
|
|
1190
|
+
const interactionWithHelpers = createModalSubmitInteraction(interaction, {
|
|
1191
|
+
onAck: (response) => ackResolver?.(response),
|
|
1192
|
+
});
|
|
1193
|
+
// Wrap modal handler with timeout and acknowledgment
|
|
1254
1194
|
const timeoutWrapper = createTimeoutWrapper(async () => {
|
|
1255
1195
|
const response = await handler(interactionWithHelpers);
|
|
1256
1196
|
const resolvedResponse = response ?? interactionWithHelpers.getResponse();
|
|
@@ -1259,7 +1199,7 @@ export class MiniInteraction {
|
|
|
1259
1199
|
"Return an APIInteractionResponse to acknowledge the interaction.");
|
|
1260
1200
|
}
|
|
1261
1201
|
return resolvedResponse;
|
|
1262
|
-
}, this.timeoutConfig.initialResponseTimeout, `Modal "${customId}"`, this.timeoutConfig.enableTimeoutWarnings);
|
|
1202
|
+
}, this.timeoutConfig.initialResponseTimeout, `Modal "${customId}"`, this.timeoutConfig.enableTimeoutWarnings, ackPromise);
|
|
1263
1203
|
const resolvedResponse = await timeoutWrapper();
|
|
1264
1204
|
return {
|
|
1265
1205
|
status: 200,
|
|
@@ -1307,6 +1247,11 @@ export class MiniInteraction {
|
|
|
1307
1247
|
try {
|
|
1308
1248
|
let response;
|
|
1309
1249
|
let resolvedResponse = null;
|
|
1250
|
+
// Create an acknowledgment promise for application commands
|
|
1251
|
+
let ackResolver = null;
|
|
1252
|
+
const ackPromise = new Promise((resolve) => {
|
|
1253
|
+
ackResolver = resolve;
|
|
1254
|
+
});
|
|
1310
1255
|
// Create a timeout wrapper for the command handler
|
|
1311
1256
|
const timeoutWrapper = createTimeoutWrapper(async () => {
|
|
1312
1257
|
// Check if it's a chat input (slash) command
|
|
@@ -1315,7 +1260,7 @@ export class MiniInteraction {
|
|
|
1315
1260
|
const interactionWithHelpers = createCommandInteraction(commandInteraction, {
|
|
1316
1261
|
canRespond: (id) => this.canRespond(id),
|
|
1317
1262
|
trackResponse: (id, token, state) => this.trackInteractionState(id, token, state),
|
|
1318
|
-
|
|
1263
|
+
onAck: (response) => ackResolver?.(response),
|
|
1319
1264
|
});
|
|
1320
1265
|
response = await command.handler(interactionWithHelpers);
|
|
1321
1266
|
resolvedResponse =
|
|
@@ -1324,14 +1269,18 @@ export class MiniInteraction {
|
|
|
1324
1269
|
else if (commandInteraction.data.type ===
|
|
1325
1270
|
ApplicationCommandType.User) {
|
|
1326
1271
|
// User context menu command
|
|
1327
|
-
const interactionWithHelpers = createUserContextMenuInteraction(commandInteraction
|
|
1272
|
+
const interactionWithHelpers = createUserContextMenuInteraction(commandInteraction, {
|
|
1273
|
+
onAck: (response) => ackResolver?.(response),
|
|
1274
|
+
});
|
|
1328
1275
|
response = await command.handler(interactionWithHelpers);
|
|
1329
1276
|
resolvedResponse =
|
|
1330
1277
|
response ?? interactionWithHelpers.getResponse();
|
|
1331
1278
|
}
|
|
1332
1279
|
else if (commandInteraction.data.type ===
|
|
1333
1280
|
ApplicationCommandType.PrimaryEntryPoint) {
|
|
1334
|
-
const interactionWithHelpers = createAppCommandInteraction(commandInteraction
|
|
1281
|
+
const interactionWithHelpers = createAppCommandInteraction(commandInteraction, {
|
|
1282
|
+
onAck: (response) => ackResolver?.(response),
|
|
1283
|
+
});
|
|
1335
1284
|
response = await command.handler(interactionWithHelpers);
|
|
1336
1285
|
resolvedResponse =
|
|
1337
1286
|
response ?? interactionWithHelpers.getResponse();
|
|
@@ -1339,7 +1288,9 @@ export class MiniInteraction {
|
|
|
1339
1288
|
else if (commandInteraction.data.type ===
|
|
1340
1289
|
ApplicationCommandType.Message) {
|
|
1341
1290
|
// Message context menu command
|
|
1342
|
-
const interactionWithHelpers = createMessageContextMenuInteraction(commandInteraction
|
|
1291
|
+
const interactionWithHelpers = createMessageContextMenuInteraction(commandInteraction, {
|
|
1292
|
+
onAck: (response) => ackResolver?.(response),
|
|
1293
|
+
});
|
|
1343
1294
|
response = await command.handler(interactionWithHelpers);
|
|
1344
1295
|
resolvedResponse =
|
|
1345
1296
|
response ?? interactionWithHelpers.getResponse();
|
|
@@ -1349,9 +1300,10 @@ export class MiniInteraction {
|
|
|
1349
1300
|
response = await command.handler(commandInteraction);
|
|
1350
1301
|
resolvedResponse = response ?? null;
|
|
1351
1302
|
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1303
|
+
return resolvedResponse;
|
|
1304
|
+
}, this.timeoutConfig.initialResponseTimeout, `Command "${commandName}"`, this.timeoutConfig.enableTimeoutWarnings, ackPromise);
|
|
1305
|
+
const finalResponse = await timeoutWrapper();
|
|
1306
|
+
if (!finalResponse) {
|
|
1355
1307
|
console.error(`[MiniInteraction] Command "${commandName}" did not return a response. ` +
|
|
1356
1308
|
"This indicates the handler completed but no response was generated. " +
|
|
1357
1309
|
"Check that deferReply(), reply(), showModal(), or a direct response is returned.");
|
|
@@ -1366,7 +1318,7 @@ export class MiniInteraction {
|
|
|
1366
1318
|
}
|
|
1367
1319
|
return {
|
|
1368
1320
|
status: 200,
|
|
1369
|
-
body:
|
|
1321
|
+
body: finalResponse,
|
|
1370
1322
|
};
|
|
1371
1323
|
}
|
|
1372
1324
|
catch (error) {
|
|
@@ -1554,7 +1506,7 @@ function resolveOAuthConfig(provided) {
|
|
|
1554
1506
|
/**
|
|
1555
1507
|
* Wraps a handler function with timeout detection and error handling.
|
|
1556
1508
|
*/
|
|
1557
|
-
function createTimeoutWrapper(handler, timeoutMs, handlerName, enableWarnings = true) {
|
|
1509
|
+
function createTimeoutWrapper(handler, timeoutMs, handlerName, enableWarnings = true, ackPromise) {
|
|
1558
1510
|
return async (...args) => {
|
|
1559
1511
|
const startTime = Date.now();
|
|
1560
1512
|
let timeoutId;
|
|
@@ -1566,10 +1518,14 @@ function createTimeoutWrapper(handler, timeoutMs, handlerName, enableWarnings =
|
|
|
1566
1518
|
}, timeoutMs);
|
|
1567
1519
|
});
|
|
1568
1520
|
try {
|
|
1569
|
-
const
|
|
1521
|
+
const promises = [
|
|
1570
1522
|
Promise.resolve(handler(...args)),
|
|
1571
1523
|
timeoutPromise,
|
|
1572
|
-
]
|
|
1524
|
+
];
|
|
1525
|
+
if (ackPromise) {
|
|
1526
|
+
promises.push(ackPromise);
|
|
1527
|
+
}
|
|
1528
|
+
const result = await Promise.race(promises);
|
|
1573
1529
|
if (timeoutId) {
|
|
1574
1530
|
clearTimeout(timeoutId);
|
|
1575
1531
|
}
|
|
@@ -77,7 +77,6 @@ export class MiniDatabase {
|
|
|
77
77
|
await this.mongoClient.connect();
|
|
78
78
|
this.mongoDb = this.mongoClient.db(this.config.dbName || "minidb");
|
|
79
79
|
this.mongoCollection = this.mongoDb.collection(this.config.collectionName || "data");
|
|
80
|
-
console.log("✅ [MiniDatabase] Connected to MongoDB");
|
|
81
80
|
}
|
|
82
81
|
catch (err) {
|
|
83
82
|
console.error("❌ [MiniDatabase] Failed to connect to MongoDB:", err);
|
|
@@ -136,7 +135,6 @@ export class MiniDatabase {
|
|
|
136
135
|
createdAt: new Date(),
|
|
137
136
|
},
|
|
138
137
|
}, { upsert: true });
|
|
139
|
-
console.log(`✅ [MiniDatabase] Saved data for key "${key}"`);
|
|
140
138
|
return true;
|
|
141
139
|
}
|
|
142
140
|
catch (err) {
|
|
@@ -175,7 +173,6 @@ export class MiniDatabase {
|
|
|
175
173
|
createdAt: new Date(),
|
|
176
174
|
},
|
|
177
175
|
}, { upsert: true });
|
|
178
|
-
console.log(`✅ [MiniDatabase] Updated data for key "${key}"`);
|
|
179
176
|
return true;
|
|
180
177
|
}
|
|
181
178
|
catch (err) {
|
|
@@ -194,7 +191,6 @@ export class MiniDatabase {
|
|
|
194
191
|
throw new Error("MongoDB collection is not initialized");
|
|
195
192
|
}
|
|
196
193
|
await collection.deleteOne({ _id: key });
|
|
197
|
-
console.log(`✅ [MiniDatabase] Deleted data for key "${key}"`);
|
|
198
194
|
return true;
|
|
199
195
|
}
|
|
200
196
|
catch (err) {
|
|
@@ -208,7 +204,6 @@ export class MiniDatabase {
|
|
|
208
204
|
async close() {
|
|
209
205
|
if (this.mongoClient) {
|
|
210
206
|
await this.mongoClient.close();
|
|
211
|
-
console.log("✅ [MiniDatabase] MongoDB connection closed");
|
|
212
207
|
}
|
|
213
208
|
}
|
|
214
209
|
}
|
|
@@ -154,7 +154,7 @@ export interface CommandInteraction extends Omit<APIChatInputApplicationCommandI
|
|
|
154
154
|
withTimeoutProtection<T>(operation: () => Promise<T>, deferOptions?: DeferReplyOptions): Promise<T>;
|
|
155
155
|
canRespond?(interactionId: string): boolean;
|
|
156
156
|
trackResponse?(interactionId: string, token: string, state: 'responded' | 'deferred'): void;
|
|
157
|
-
|
|
157
|
+
onAck?(response: APIInteractionResponse): void;
|
|
158
158
|
}
|
|
159
159
|
export declare const CommandInteraction: {};
|
|
160
160
|
/**
|
|
@@ -168,4 +168,5 @@ export declare function createCommandInteraction(interaction: APIChatInputApplic
|
|
|
168
168
|
canRespond?: (interactionId: string) => boolean;
|
|
169
169
|
trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
|
|
170
170
|
logTiming?: (interactionId: string, operation: string, startTime: number, success: boolean) => void;
|
|
171
|
+
onAck?: (response: APIInteractionResponse) => void;
|
|
171
172
|
}): CommandInteraction;
|
|
@@ -383,8 +383,9 @@ export function createCommandInteraction(interaction, helpers) {
|
|
|
383
383
|
const response = createMessageResponse(InteractionResponseType.ChannelMessageWithSource, data);
|
|
384
384
|
// Track response
|
|
385
385
|
this.trackResponse?.(this.id, this.token, 'responded');
|
|
386
|
+
// Notify acknowledgment
|
|
387
|
+
this.onAck?.(response);
|
|
386
388
|
// Log timing if debug enabled
|
|
387
|
-
this.logTiming?.(this.id, 'reply', startTime, true);
|
|
388
389
|
return response;
|
|
389
390
|
},
|
|
390
391
|
followUp(data) {
|
|
@@ -403,7 +404,6 @@ export function createCommandInteraction(interaction, helpers) {
|
|
|
403
404
|
// Track response
|
|
404
405
|
this.trackResponse?.(this.id, this.token, 'responded');
|
|
405
406
|
// Log timing if debug enabled
|
|
406
|
-
this.logTiming?.(this.id, 'editReply', startTime, true);
|
|
407
407
|
return response;
|
|
408
408
|
},
|
|
409
409
|
deferReply(options) {
|
|
@@ -417,8 +417,9 @@ export function createCommandInteraction(interaction, helpers) {
|
|
|
417
417
|
: undefined);
|
|
418
418
|
// Track deferred state
|
|
419
419
|
this.trackResponse?.(this.id, this.token, 'deferred');
|
|
420
|
+
// Notify acknowledgment
|
|
421
|
+
this.onAck?.(response);
|
|
420
422
|
// Log timing if debug enabled
|
|
421
|
-
this.logTiming?.(this.id, 'deferReply', startTime, true);
|
|
422
423
|
return response;
|
|
423
424
|
},
|
|
424
425
|
showModal(data) {
|
|
@@ -469,7 +470,7 @@ export function createCommandInteraction(interaction, helpers) {
|
|
|
469
470
|
// Helper methods for state management
|
|
470
471
|
canRespond: helpers?.canRespond,
|
|
471
472
|
trackResponse: helpers?.trackResponse,
|
|
472
|
-
|
|
473
|
+
onAck: helpers?.onAck,
|
|
473
474
|
};
|
|
474
475
|
return commandInteraction;
|
|
475
476
|
}
|
|
@@ -12,6 +12,7 @@ type ContextMenuInteractionHelpers = {
|
|
|
12
12
|
showModal: (data: APIModalInteractionResponseCallbackData | {
|
|
13
13
|
toJSON(): APIModalInteractionResponseCallbackData;
|
|
14
14
|
}) => APIModalInteractionResponse;
|
|
15
|
+
onAck?: (response: APIInteractionResponse) => void;
|
|
15
16
|
};
|
|
16
17
|
/**
|
|
17
18
|
* User context menu interaction with helper methods.
|
|
@@ -40,19 +41,25 @@ export declare const AppCommandInteraction: {};
|
|
|
40
41
|
* @param interaction - The raw user context menu interaction payload from Discord.
|
|
41
42
|
* @returns A helper-augmented interaction object.
|
|
42
43
|
*/
|
|
43
|
-
export declare function createUserContextMenuInteraction(interaction: APIUserApplicationCommandInteraction
|
|
44
|
+
export declare function createUserContextMenuInteraction(interaction: APIUserApplicationCommandInteraction, helpers?: {
|
|
45
|
+
onAck?: (response: APIInteractionResponse) => void;
|
|
46
|
+
}): UserContextMenuInteraction;
|
|
44
47
|
/**
|
|
45
48
|
* Wraps a raw message context menu interaction with helper methods.
|
|
46
49
|
*
|
|
47
50
|
* @param interaction - The raw message context menu interaction payload from Discord.
|
|
48
51
|
* @returns A helper-augmented interaction object.
|
|
49
52
|
*/
|
|
50
|
-
export declare function createMessageContextMenuInteraction(interaction: APIMessageApplicationCommandInteraction
|
|
53
|
+
export declare function createMessageContextMenuInteraction(interaction: APIMessageApplicationCommandInteraction, helpers?: {
|
|
54
|
+
onAck?: (response: APIInteractionResponse) => void;
|
|
55
|
+
}): MessageContextMenuInteraction;
|
|
51
56
|
/**
|
|
52
57
|
* Wraps a raw primary entry point interaction with helper methods.
|
|
53
58
|
*
|
|
54
59
|
* @param interaction - The raw primary entry point interaction payload from Discord.
|
|
55
60
|
* @returns A helper-augmented interaction object.
|
|
56
61
|
*/
|
|
57
|
-
export declare function createAppCommandInteraction(interaction: APIPrimaryEntryPointCommandInteraction
|
|
62
|
+
export declare function createAppCommandInteraction(interaction: APIPrimaryEntryPointCommandInteraction, helpers?: {
|
|
63
|
+
onAck?: (response: APIInteractionResponse) => void;
|
|
64
|
+
}): AppCommandInteraction;
|
|
58
65
|
export {};
|
|
@@ -3,7 +3,7 @@ import { normaliseInteractionMessageData, normaliseMessageFlags, } from "./inter
|
|
|
3
3
|
export const UserContextMenuInteraction = {};
|
|
4
4
|
export const MessageContextMenuInteraction = {};
|
|
5
5
|
export const AppCommandInteraction = {};
|
|
6
|
-
function createContextMenuInteractionHelpers() {
|
|
6
|
+
function createContextMenuInteractionHelpers(helpers) {
|
|
7
7
|
let capturedResponse = null;
|
|
8
8
|
const captureResponse = (response) => {
|
|
9
9
|
capturedResponse = response;
|
|
@@ -25,15 +25,21 @@ function createContextMenuInteractionHelpers() {
|
|
|
25
25
|
}
|
|
26
26
|
return captureResponse({ type });
|
|
27
27
|
}
|
|
28
|
-
const reply = (data) =>
|
|
28
|
+
const reply = (data) => {
|
|
29
|
+
const response = createMessageResponse(InteractionResponseType.ChannelMessageWithSource, data);
|
|
30
|
+
helpers?.onAck?.(response);
|
|
31
|
+
return response;
|
|
32
|
+
};
|
|
29
33
|
const followUp = (data) => createMessageResponse(InteractionResponseType.ChannelMessageWithSource, data);
|
|
30
34
|
const editReply = (data) => createMessageResponse(InteractionResponseType.UpdateMessage, data);
|
|
31
35
|
const deferReply = (options = {}) => {
|
|
32
36
|
const flags = normaliseMessageFlags(options.flags);
|
|
33
|
-
|
|
37
|
+
const response = captureResponse({
|
|
34
38
|
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
|
35
39
|
data: flags ? { flags } : undefined,
|
|
36
40
|
});
|
|
41
|
+
helpers?.onAck?.(response);
|
|
42
|
+
return response;
|
|
37
43
|
};
|
|
38
44
|
const showModal = (data) => {
|
|
39
45
|
const modalData = typeof data === "object" && "toJSON" in data ? data.toJSON() : data;
|
|
@@ -50,6 +56,7 @@ function createContextMenuInteractionHelpers() {
|
|
|
50
56
|
editReply,
|
|
51
57
|
deferReply,
|
|
52
58
|
showModal,
|
|
59
|
+
onAck: helpers?.onAck,
|
|
53
60
|
};
|
|
54
61
|
}
|
|
55
62
|
/**
|
|
@@ -58,8 +65,8 @@ function createContextMenuInteractionHelpers() {
|
|
|
58
65
|
* @param interaction - The raw user context menu interaction payload from Discord.
|
|
59
66
|
* @returns A helper-augmented interaction object.
|
|
60
67
|
*/
|
|
61
|
-
export function createUserContextMenuInteraction(interaction) {
|
|
62
|
-
return Object.assign(interaction, createContextMenuInteractionHelpers(), {
|
|
68
|
+
export function createUserContextMenuInteraction(interaction, helpers) {
|
|
69
|
+
return Object.assign(interaction, createContextMenuInteractionHelpers(helpers), {
|
|
63
70
|
targetUser: resolveTargetUser(interaction),
|
|
64
71
|
});
|
|
65
72
|
}
|
|
@@ -69,8 +76,8 @@ export function createUserContextMenuInteraction(interaction) {
|
|
|
69
76
|
* @param interaction - The raw message context menu interaction payload from Discord.
|
|
70
77
|
* @returns A helper-augmented interaction object.
|
|
71
78
|
*/
|
|
72
|
-
export function createMessageContextMenuInteraction(interaction) {
|
|
73
|
-
return Object.assign(interaction, createContextMenuInteractionHelpers(), {
|
|
79
|
+
export function createMessageContextMenuInteraction(interaction, helpers) {
|
|
80
|
+
return Object.assign(interaction, createContextMenuInteractionHelpers(helpers), {
|
|
74
81
|
targetMessage: resolveTargetMessage(interaction),
|
|
75
82
|
});
|
|
76
83
|
}
|
|
@@ -80,8 +87,8 @@ export function createMessageContextMenuInteraction(interaction) {
|
|
|
80
87
|
* @param interaction - The raw primary entry point interaction payload from Discord.
|
|
81
88
|
* @returns A helper-augmented interaction object.
|
|
82
89
|
*/
|
|
83
|
-
export function createAppCommandInteraction(interaction) {
|
|
84
|
-
return Object.assign(interaction, createContextMenuInteractionHelpers());
|
|
90
|
+
export function createAppCommandInteraction(interaction, helpers) {
|
|
91
|
+
return Object.assign(interaction, createContextMenuInteractionHelpers(helpers));
|
|
85
92
|
}
|
|
86
93
|
function resolveTargetMessage(interaction) {
|
|
87
94
|
const targetId = interaction.data?.target_id;
|
|
@@ -27,6 +27,7 @@ type BaseComponentInteractionHelpers = {
|
|
|
27
27
|
showModal: (data: APIModalInteractionResponseCallbackData | {
|
|
28
28
|
toJSON(): APIModalInteractionResponseCallbackData;
|
|
29
29
|
}) => APIModalInteractionResponse;
|
|
30
|
+
onAck?: (response: APIInteractionResponse) => void;
|
|
30
31
|
};
|
|
31
32
|
/**
|
|
32
33
|
* Button interaction with helper methods.
|
|
@@ -135,5 +136,7 @@ export declare const MessageComponentInteraction: {};
|
|
|
135
136
|
* @param interaction - The raw interaction payload from Discord.
|
|
136
137
|
* @returns A helper-augmented interaction object.
|
|
137
138
|
*/
|
|
138
|
-
export declare function createMessageComponentInteraction(interaction: APIMessageComponentInteraction
|
|
139
|
+
export declare function createMessageComponentInteraction(interaction: APIMessageComponentInteraction, helpers?: {
|
|
140
|
+
onAck?: (response: APIInteractionResponse) => void;
|
|
141
|
+
}): MessageComponentInteraction;
|
|
139
142
|
export {};
|
|
@@ -15,7 +15,7 @@ export const MessageComponentInteraction = {};
|
|
|
15
15
|
* @param interaction - The raw interaction payload from Discord.
|
|
16
16
|
* @returns A helper-augmented interaction object.
|
|
17
17
|
*/
|
|
18
|
-
export function createMessageComponentInteraction(interaction) {
|
|
18
|
+
export function createMessageComponentInteraction(interaction, helpers) {
|
|
19
19
|
let capturedResponse = null;
|
|
20
20
|
const captureResponse = (response) => {
|
|
21
21
|
capturedResponse = response;
|
|
@@ -26,10 +26,12 @@ export function createMessageComponentInteraction(interaction) {
|
|
|
26
26
|
if (!normalisedData) {
|
|
27
27
|
throw new Error("[MiniInteraction] Component replies require response data to be provided.");
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
const response = captureResponse({
|
|
30
30
|
type: InteractionResponseType.ChannelMessageWithSource,
|
|
31
31
|
data: normalisedData,
|
|
32
32
|
});
|
|
33
|
+
helpers?.onAck?.(response);
|
|
34
|
+
return response;
|
|
33
35
|
};
|
|
34
36
|
const deferReply = (options) => {
|
|
35
37
|
const flags = normaliseMessageFlags(options?.flags);
|
|
@@ -41,7 +43,9 @@ export function createMessageComponentInteraction(interaction) {
|
|
|
41
43
|
: {
|
|
42
44
|
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
|
43
45
|
};
|
|
44
|
-
|
|
46
|
+
captureResponse(response);
|
|
47
|
+
helpers?.onAck?.(response);
|
|
48
|
+
return response;
|
|
45
49
|
};
|
|
46
50
|
const update = (data) => {
|
|
47
51
|
const normalisedData = normaliseInteractionMessageData(data);
|
|
@@ -178,5 +182,6 @@ export function createMessageComponentInteraction(interaction) {
|
|
|
178
182
|
getChannels,
|
|
179
183
|
getUsers,
|
|
180
184
|
getMentionables,
|
|
185
|
+
onAck: helpers?.onAck,
|
|
181
186
|
});
|
|
182
187
|
}
|
|
@@ -7,6 +7,7 @@ export type ModalSubmitInteraction = APIModalSubmitInteraction & {
|
|
|
7
7
|
getResponse: () => APIInteractionResponse | null;
|
|
8
8
|
reply: (data: InteractionMessageData) => APIInteractionResponseChannelMessageWithSource;
|
|
9
9
|
deferReply: (options?: DeferReplyOptions) => APIInteractionResponseDeferredChannelMessageWithSource;
|
|
10
|
+
onAck?: (response: APIInteractionResponse) => void;
|
|
10
11
|
/**
|
|
11
12
|
* Helper method to get the value of a text input component by custom_id.
|
|
12
13
|
* @param customId - The custom_id of the text input component
|
|
@@ -32,4 +33,6 @@ export declare const ModalSubmitInteraction: {};
|
|
|
32
33
|
* @param interaction - The raw interaction payload from Discord.
|
|
33
34
|
* @returns A helper-augmented interaction object.
|
|
34
35
|
*/
|
|
35
|
-
export declare function createModalSubmitInteraction(interaction: APIModalSubmitInteraction
|
|
36
|
+
export declare function createModalSubmitInteraction(interaction: APIModalSubmitInteraction, helpers?: {
|
|
37
|
+
onAck?: (response: APIInteractionResponse) => void;
|
|
38
|
+
}): ModalSubmitInteraction;
|
|
@@ -7,7 +7,7 @@ export const ModalSubmitInteraction = {};
|
|
|
7
7
|
* @param interaction - The raw interaction payload from Discord.
|
|
8
8
|
* @returns A helper-augmented interaction object.
|
|
9
9
|
*/
|
|
10
|
-
export function createModalSubmitInteraction(interaction) {
|
|
10
|
+
export function createModalSubmitInteraction(interaction, helpers) {
|
|
11
11
|
let capturedResponse = null;
|
|
12
12
|
const captureResponse = (response) => {
|
|
13
13
|
capturedResponse = response;
|
|
@@ -18,10 +18,12 @@ export function createModalSubmitInteraction(interaction) {
|
|
|
18
18
|
if (!normalisedData) {
|
|
19
19
|
throw new Error("[MiniInteraction] Modal submit replies require response data to be provided.");
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
const response = captureResponse({
|
|
22
22
|
type: InteractionResponseType.ChannelMessageWithSource,
|
|
23
23
|
data: normalisedData,
|
|
24
24
|
});
|
|
25
|
+
helpers?.onAck?.(response);
|
|
26
|
+
return response;
|
|
25
27
|
};
|
|
26
28
|
const deferReply = (options) => {
|
|
27
29
|
const flags = normaliseMessageFlags(options?.flags);
|
|
@@ -33,7 +35,9 @@ export function createModalSubmitInteraction(interaction) {
|
|
|
33
35
|
: {
|
|
34
36
|
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
|
35
37
|
};
|
|
36
|
-
|
|
38
|
+
captureResponse(response);
|
|
39
|
+
helpers?.onAck?.(response);
|
|
40
|
+
return response;
|
|
37
41
|
};
|
|
38
42
|
const getResponse = () => capturedResponse;
|
|
39
43
|
// Helper to extract text input values from modal components
|
|
@@ -95,5 +99,6 @@ export function createModalSubmitInteraction(interaction) {
|
|
|
95
99
|
getTextInputValue,
|
|
96
100
|
getTextInputValues,
|
|
97
101
|
getSelectMenuValues: (customId) => selectMenuValues.get(customId),
|
|
102
|
+
onAck: helpers?.onAck,
|
|
98
103
|
});
|
|
99
104
|
}
|
package/package.json
CHANGED