@minesa-org/mini-interaction 0.2.6 → 0.2.8

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.
@@ -1126,14 +1126,15 @@ export class MiniInteraction {
1126
1126
  const interactionWithHelpers = createMessageComponentInteraction(interaction, {
1127
1127
  onAck: (response) => ackResolver?.(response),
1128
1128
  sendFollowUp,
1129
+ trackResponse: (id, token, state) => this.trackInteractionState(id, token, state),
1130
+ canRespond: (id) => this.canRespond(id),
1129
1131
  });
1130
1132
  // Wrap component handler with timeout and acknowledgment
1131
1133
  const timeoutWrapper = createTimeoutWrapper(async () => {
1132
1134
  const response = await handler(interactionWithHelpers);
1133
1135
  const resolvedResponse = response ?? interactionWithHelpers.getResponse();
1134
- if (!resolvedResponse) {
1135
- throw new Error(`Component "${customId}" did not return a response. ` +
1136
- "Return an APIInteractionResponse to acknowledge the interaction.");
1136
+ if (this.timeoutConfig.enableResponseDebugLogging) {
1137
+ console.log(`[MiniInteraction] Component handler finished: "${customId}"`);
1137
1138
  }
1138
1139
  return resolvedResponse;
1139
1140
  }, this.timeoutConfig.initialResponseTimeout, `Component "${customId}"`, this.timeoutConfig.enableTimeoutWarnings, ackPromise);
@@ -1191,14 +1192,15 @@ export class MiniInteraction {
1191
1192
  const interactionWithHelpers = createModalSubmitInteraction(interaction, {
1192
1193
  onAck: (response) => ackResolver?.(response),
1193
1194
  sendFollowUp,
1195
+ trackResponse: (id, token, state) => this.trackInteractionState(id, token, state),
1196
+ canRespond: (id) => this.canRespond(id),
1194
1197
  });
1195
1198
  // Wrap modal handler with timeout and acknowledgment
1196
1199
  const timeoutWrapper = createTimeoutWrapper(async () => {
1197
1200
  const response = await handler(interactionWithHelpers);
1198
1201
  const resolvedResponse = response ?? interactionWithHelpers.getResponse();
1199
- if (!resolvedResponse) {
1200
- throw new Error(`Modal "${customId}" did not return a response. ` +
1201
- "Return an APIInteractionResponse to acknowledge the interaction.");
1202
+ if (this.timeoutConfig.enableResponseDebugLogging) {
1203
+ console.log(`[MiniInteraction] Modal handler finished: "${customId}"`);
1202
1204
  }
1203
1205
  return resolvedResponse;
1204
1206
  }, this.timeoutConfig.initialResponseTimeout, `Modal "${customId}"`, this.timeoutConfig.enableTimeoutWarnings, ackPromise);
@@ -1273,9 +1275,9 @@ export class MiniInteraction {
1273
1275
  }
1274
1276
  else if (commandInteraction.data.type ===
1275
1277
  ApplicationCommandType.User) {
1276
- // User context menu command
1277
1278
  const interactionWithHelpers = createUserContextMenuInteraction(commandInteraction, {
1278
1279
  onAck: (response) => ackResolver?.(response),
1280
+ sendFollowUp,
1279
1281
  });
1280
1282
  response = await command.handler(interactionWithHelpers);
1281
1283
  resolvedResponse =
@@ -1285,6 +1287,7 @@ export class MiniInteraction {
1285
1287
  ApplicationCommandType.PrimaryEntryPoint) {
1286
1288
  const interactionWithHelpers = createAppCommandInteraction(commandInteraction, {
1287
1289
  onAck: (response) => ackResolver?.(response),
1290
+ sendFollowUp,
1288
1291
  });
1289
1292
  response = await command.handler(interactionWithHelpers);
1290
1293
  resolvedResponse =
@@ -1295,6 +1298,7 @@ export class MiniInteraction {
1295
1298
  // Message context menu command
1296
1299
  const interactionWithHelpers = createMessageContextMenuInteraction(commandInteraction, {
1297
1300
  onAck: (response) => ackResolver?.(response),
1301
+ sendFollowUp,
1298
1302
  });
1299
1303
  response = await command.handler(interactionWithHelpers);
1300
1304
  resolvedResponse =
@@ -1305,9 +1309,15 @@ export class MiniInteraction {
1305
1309
  response = await command.handler(commandInteraction);
1306
1310
  resolvedResponse = response ?? null;
1307
1311
  }
1312
+ if (this.timeoutConfig.enableResponseDebugLogging) {
1313
+ console.log(`[MiniInteraction] Command handler finished: "${commandName}"`);
1314
+ }
1308
1315
  return resolvedResponse;
1309
1316
  }, this.timeoutConfig.initialResponseTimeout, `Command "${commandName}"`, this.timeoutConfig.enableTimeoutWarnings, ackPromise);
1310
1317
  const finalResponse = await timeoutWrapper();
1318
+ if (this.timeoutConfig.enableResponseDebugLogging) {
1319
+ console.log(`[MiniInteraction] handleApplicationCommand: initial response determined (type=${finalResponse?.type})`);
1320
+ }
1311
1321
  if (!finalResponse) {
1312
1322
  console.error(`[MiniInteraction] Command "${commandName}" did not return a response. ` +
1313
1323
  "This indicates the handler completed but no response was generated. " +
@@ -1352,8 +1362,14 @@ export class MiniInteraction {
1352
1362
  const url = isEdit
1353
1363
  ? `${DISCORD_BASE_URL}/webhooks/${this.applicationId}/${token}/messages/${messageId}`
1354
1364
  : `${DISCORD_BASE_URL}/webhooks/${this.applicationId}/${token}`;
1365
+ if (this.timeoutConfig.enableResponseDebugLogging) {
1366
+ console.log(`[MiniInteraction] sendFollowUp: id=${messageId || 'new'}, edit=${isEdit}, url=${url}`);
1367
+ }
1355
1368
  // Only send follow-up if there is data to send
1356
1369
  if (!('data' in response) || !response.data) {
1370
+ if (this.timeoutConfig.enableResponseDebugLogging) {
1371
+ console.warn(`[MiniInteraction] sendFollowUp cancelled: no data in response object`);
1372
+ }
1357
1373
  return;
1358
1374
  }
1359
1375
  try {
@@ -1364,6 +1380,9 @@ export class MiniInteraction {
1364
1380
  },
1365
1381
  body: JSON.stringify(response.data),
1366
1382
  });
1383
+ if (this.timeoutConfig.enableResponseDebugLogging) {
1384
+ console.log(`[MiniInteraction] sendFollowUp response: [${fetchResponse.status}] ${fetchResponse.statusText}`);
1385
+ }
1367
1386
  if (!fetchResponse.ok) {
1368
1387
  const errorBody = await fetchResponse.text();
1369
1388
  console.error(`[MiniInteraction] Failed to send follow-up response: [${fetchResponse.status}] ${errorBody}`);
@@ -479,6 +479,7 @@ export function createCommandInteraction(interaction, helpers) {
479
479
  canRespond: helpers?.canRespond,
480
480
  trackResponse: helpers?.trackResponse,
481
481
  onAck: helpers?.onAck,
482
+ sendFollowUp: helpers?.sendFollowUp,
482
483
  };
483
484
  return commandInteraction;
484
485
  }
@@ -3,16 +3,17 @@ import { DeferReplyOptions, InteractionMessageData } from "./interactionMessageH
3
3
  /**
4
4
  * Base helper methods for context menu interactions.
5
5
  */
6
- type ContextMenuInteractionHelpers = {
6
+ export type ContextMenuInteractionHelpers = {
7
7
  getResponse: () => APIInteractionResponse | null;
8
8
  reply: (data: InteractionMessageData) => APIInteractionResponseChannelMessageWithSource;
9
- followUp: (data: InteractionMessageData) => APIInteractionResponseChannelMessageWithSource;
10
- editReply: (data?: InteractionMessageData) => APIInteractionResponseUpdateMessage;
9
+ followUp: (data: InteractionMessageData) => Promise<APIInteractionResponseChannelMessageWithSource>;
10
+ editReply: (data?: InteractionMessageData) => Promise<APIInteractionResponseUpdateMessage>;
11
11
  deferReply: (options?: DeferReplyOptions) => APIInteractionResponseDeferredChannelMessageWithSource;
12
12
  showModal: (data: APIModalInteractionResponseCallbackData | {
13
13
  toJSON(): APIModalInteractionResponseCallbackData;
14
14
  }) => APIModalInteractionResponse;
15
15
  onAck?: (response: APIInteractionResponse) => void;
16
+ sendFollowUp?: (token: string, response: APIInteractionResponse, messageId?: string) => Promise<void>;
16
17
  };
17
18
  /**
18
19
  * User context menu interaction with helper methods.
@@ -39,27 +40,32 @@ export declare const AppCommandInteraction: {};
39
40
  * Wraps a raw user context menu interaction with helper methods.
40
41
  *
41
42
  * @param interaction - The raw user context menu interaction payload from Discord.
43
+ * @param helpers - Optional callback helpers.
42
44
  * @returns A helper-augmented interaction object.
43
45
  */
44
46
  export declare function createUserContextMenuInteraction(interaction: APIUserApplicationCommandInteraction, helpers?: {
45
47
  onAck?: (response: APIInteractionResponse) => void;
48
+ sendFollowUp?: (token: string, response: APIInteractionResponse, messageId?: string) => Promise<void>;
46
49
  }): UserContextMenuInteraction;
47
50
  /**
48
51
  * Wraps a raw message context menu interaction with helper methods.
49
52
  *
50
53
  * @param interaction - The raw message context menu interaction payload from Discord.
54
+ * @param helpers - Optional callback helpers.
51
55
  * @returns A helper-augmented interaction object.
52
56
  */
53
57
  export declare function createMessageContextMenuInteraction(interaction: APIMessageApplicationCommandInteraction, helpers?: {
54
58
  onAck?: (response: APIInteractionResponse) => void;
59
+ sendFollowUp?: (token: string, response: APIInteractionResponse, messageId?: string) => Promise<void>;
55
60
  }): MessageContextMenuInteraction;
56
61
  /**
57
62
  * Wraps a raw primary entry point interaction with helper methods.
58
63
  *
59
64
  * @param interaction - The raw primary entry point interaction payload from Discord.
65
+ * @param helpers - Optional callback helpers.
60
66
  * @returns A helper-augmented interaction object.
61
67
  */
62
68
  export declare function createAppCommandInteraction(interaction: APIPrimaryEntryPointCommandInteraction, helpers?: {
63
69
  onAck?: (response: APIInteractionResponse) => void;
70
+ sendFollowUp?: (token: string, response: APIInteractionResponse, messageId?: string) => Promise<void>;
64
71
  }): AppCommandInteraction;
65
- export {};
@@ -3,8 +3,10 @@ import { normaliseInteractionMessageData, normaliseMessageFlags, } from "./inter
3
3
  export const UserContextMenuInteraction = {};
4
4
  export const MessageContextMenuInteraction = {};
5
5
  export const AppCommandInteraction = {};
6
- function createContextMenuInteractionHelpers(helpers) {
6
+ function createContextMenuInteractionHelpers(interaction, helpers) {
7
7
  let capturedResponse = null;
8
+ let isDeferred = false;
9
+ let hasResponded = false;
8
10
  const captureResponse = (response) => {
9
11
  capturedResponse = response;
10
12
  return response;
@@ -27,17 +29,32 @@ function createContextMenuInteractionHelpers(helpers) {
27
29
  }
28
30
  const reply = (data) => {
29
31
  const response = createMessageResponse(InteractionResponseType.ChannelMessageWithSource, data);
32
+ hasResponded = true;
30
33
  helpers?.onAck?.(response);
31
34
  return response;
32
35
  };
33
- const followUp = (data) => createMessageResponse(InteractionResponseType.ChannelMessageWithSource, data);
34
- const editReply = (data) => createMessageResponse(InteractionResponseType.UpdateMessage, data);
36
+ const followUp = async (data) => {
37
+ const response = createMessageResponse(InteractionResponseType.ChannelMessageWithSource, data);
38
+ if (helpers?.sendFollowUp) {
39
+ await helpers.sendFollowUp(interaction.token, response, '');
40
+ }
41
+ return response;
42
+ };
43
+ const editReply = async (data) => {
44
+ const response = createMessageResponse(InteractionResponseType.UpdateMessage, data);
45
+ if (helpers?.sendFollowUp && (isDeferred || hasResponded)) {
46
+ await helpers.sendFollowUp(interaction.token, response, '@original');
47
+ }
48
+ hasResponded = true;
49
+ return response;
50
+ };
35
51
  const deferReply = (options = {}) => {
36
52
  const flags = normaliseMessageFlags(options.flags);
37
53
  const response = captureResponse({
38
54
  type: InteractionResponseType.DeferredChannelMessageWithSource,
39
55
  data: flags ? { flags } : undefined,
40
56
  });
57
+ isDeferred = true;
41
58
  helpers?.onAck?.(response);
42
59
  return response;
43
60
  };
@@ -56,17 +73,18 @@ function createContextMenuInteractionHelpers(helpers) {
56
73
  editReply,
57
74
  deferReply,
58
75
  showModal,
59
- onAck: helpers?.onAck,
76
+ sendFollowUp: helpers?.sendFollowUp,
60
77
  };
61
78
  }
62
79
  /**
63
80
  * Wraps a raw user context menu interaction with helper methods.
64
81
  *
65
82
  * @param interaction - The raw user context menu interaction payload from Discord.
83
+ * @param helpers - Optional callback helpers.
66
84
  * @returns A helper-augmented interaction object.
67
85
  */
68
86
  export function createUserContextMenuInteraction(interaction, helpers) {
69
- return Object.assign(interaction, createContextMenuInteractionHelpers(helpers), {
87
+ return Object.assign(interaction, createContextMenuInteractionHelpers(interaction, helpers), {
70
88
  targetUser: resolveTargetUser(interaction),
71
89
  });
72
90
  }
@@ -74,10 +92,11 @@ export function createUserContextMenuInteraction(interaction, helpers) {
74
92
  * Wraps a raw message context menu interaction with helper methods.
75
93
  *
76
94
  * @param interaction - The raw message context menu interaction payload from Discord.
95
+ * @param helpers - Optional callback helpers.
77
96
  * @returns A helper-augmented interaction object.
78
97
  */
79
98
  export function createMessageContextMenuInteraction(interaction, helpers) {
80
- return Object.assign(interaction, createContextMenuInteractionHelpers(helpers), {
99
+ return Object.assign(interaction, createContextMenuInteractionHelpers(interaction, helpers), {
81
100
  targetMessage: resolveTargetMessage(interaction),
82
101
  });
83
102
  }
@@ -85,10 +104,11 @@ export function createMessageContextMenuInteraction(interaction, helpers) {
85
104
  * Wraps a raw primary entry point interaction with helper methods.
86
105
  *
87
106
  * @param interaction - The raw primary entry point interaction payload from Discord.
107
+ * @param helpers - Optional callback helpers.
88
108
  * @returns A helper-augmented interaction object.
89
109
  */
90
110
  export function createAppCommandInteraction(interaction, helpers) {
91
- return Object.assign(interaction, createContextMenuInteractionHelpers(helpers));
111
+ return Object.assign(interaction, createContextMenuInteractionHelpers(interaction, helpers));
92
112
  }
93
113
  function resolveTargetMessage(interaction) {
94
114
  const targetId = interaction.data?.target_id;
@@ -22,6 +22,8 @@ export type BaseComponentInteractionHelpers = {
22
22
  trackTiming?: (interactionId: string, operation: string, startTime: number, success: boolean) => void;
23
23
  onAck?: (response: APIInteractionResponse) => void;
24
24
  sendFollowUp?: (token: string, response: APIInteractionResponse, messageId?: string) => Promise<void>;
25
+ canRespond?: (interactionId: string) => boolean;
26
+ trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
25
27
  };
26
28
  /**
27
29
  * Button interaction with helper methods.
@@ -37,6 +39,8 @@ export interface ButtonInteraction extends Omit<APIMessageComponentInteraction,
37
39
  showModal: (data: APIModalInteractionResponseCallbackData | {
38
40
  toJSON(): APIModalInteractionResponseCallbackData;
39
41
  }) => APIModalInteractionResponse;
42
+ canRespond?: (interactionId: string) => boolean;
43
+ trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
40
44
  }
41
45
  export declare const ButtonInteraction: {};
42
46
  /**
@@ -54,6 +58,8 @@ export interface StringSelectInteraction extends Omit<APIMessageComponentInterac
54
58
  showModal: (data: APIModalInteractionResponseCallbackData | {
55
59
  toJSON(): APIModalInteractionResponseCallbackData;
56
60
  }) => APIModalInteractionResponse;
61
+ canRespond?: (interactionId: string) => boolean;
62
+ trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
57
63
  }
58
64
  export declare const StringSelectInteraction: {};
59
65
  /**
@@ -71,6 +77,8 @@ export interface RoleSelectInteraction extends Omit<APIMessageComponentInteracti
71
77
  showModal: (data: APIModalInteractionResponseCallbackData | {
72
78
  toJSON(): APIModalInteractionResponseCallbackData;
73
79
  }) => APIModalInteractionResponse;
80
+ canRespond?: (interactionId: string) => boolean;
81
+ trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
74
82
  }
75
83
  export declare const RoleSelectInteraction: {};
76
84
  /**
@@ -88,6 +96,8 @@ export interface UserSelectInteraction extends Omit<APIMessageComponentInteracti
88
96
  showModal: (data: APIModalInteractionResponseCallbackData | {
89
97
  toJSON(): APIModalInteractionResponseCallbackData;
90
98
  }) => APIModalInteractionResponse;
99
+ canRespond?: (interactionId: string) => boolean;
100
+ trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
91
101
  }
92
102
  export declare const UserSelectInteraction: {};
93
103
  /**
@@ -105,6 +115,8 @@ export interface ChannelSelectInteraction extends Omit<APIMessageComponentIntera
105
115
  showModal: (data: APIModalInteractionResponseCallbackData | {
106
116
  toJSON(): APIModalInteractionResponseCallbackData;
107
117
  }) => APIModalInteractionResponse;
118
+ canRespond?: (interactionId: string) => boolean;
119
+ trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
108
120
  }
109
121
  export declare const ChannelSelectInteraction: {};
110
122
  /**
@@ -122,6 +134,8 @@ export interface MentionableSelectInteraction extends Omit<APIMessageComponentIn
122
134
  showModal: (data: APIModalInteractionResponseCallbackData | {
123
135
  toJSON(): APIModalInteractionResponseCallbackData;
124
136
  }) => APIModalInteractionResponse;
137
+ canRespond?: (interactionId: string) => boolean;
138
+ trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
125
139
  }
126
140
  export declare const MentionableSelectInteraction: {};
127
141
  /**
@@ -144,6 +158,11 @@ export type MessageComponentInteraction = APIMessageComponentInteraction & {
144
158
  * This is automatically called by reply() and update() if the interaction is deferred.
145
159
  */
146
160
  sendFollowUp?: (token: string, response: APIInteractionResponse, messageId?: string) => Promise<void>;
161
+ /**
162
+ * Optional state management helpers.
163
+ */
164
+ canRespond?: (interactionId: string) => boolean;
165
+ trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
147
166
  /**
148
167
  * The selected values from a select menu interaction.
149
168
  * This property is only present for select menu interactions.
@@ -203,5 +203,7 @@ export function createMessageComponentInteraction(interaction, helpers) {
203
203
  getMentionables,
204
204
  onAck: helpers?.onAck,
205
205
  sendFollowUp: helpers?.sendFollowUp,
206
+ canRespond: helpers?.canRespond,
207
+ trackResponse: helpers?.trackResponse,
206
208
  });
207
209
  }
@@ -16,6 +16,11 @@ export type ModalSubmitInteraction = APIModalSubmitInteraction & {
16
16
  * This is automatically called by reply() if the interaction is deferred.
17
17
  */
18
18
  sendFollowUp?: (token: string, response: APIInteractionResponse, messageId?: string) => Promise<void>;
19
+ /**
20
+ * Optional state management helpers.
21
+ */
22
+ canRespond?: (interactionId: string) => boolean;
23
+ trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
19
24
  };
20
25
  export declare const ModalSubmitInteraction: {};
21
26
  /**
@@ -28,4 +33,6 @@ export declare const ModalSubmitInteraction: {};
28
33
  export declare function createModalSubmitInteraction(interaction: APIModalSubmitInteraction, helpers?: {
29
34
  onAck?: (response: APIInteractionResponse) => void;
30
35
  sendFollowUp?: (token: string, response: APIInteractionResponse, messageId?: string) => Promise<void>;
36
+ canRespond?: (interactionId: string) => boolean;
37
+ trackResponse?: (interactionId: string, token: string, state: 'responded' | 'deferred') => void;
31
38
  }): ModalSubmitInteraction;
@@ -67,5 +67,7 @@ export function createModalSubmitInteraction(interaction, helpers) {
67
67
  getResponse,
68
68
  getTextFieldValue,
69
69
  sendFollowUp: helpers?.sendFollowUp,
70
+ canRespond: helpers?.canRespond,
71
+ trackResponse: helpers?.trackResponse,
70
72
  });
71
73
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minesa-org/mini-interaction",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Mini interaction, connecting your app with Discord via HTTP-interaction (Vercel support).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",