@helyx/bot 0.1.2 → 0.1.3
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/CHANGELOG.md +6 -0
- package/dist/interactions.d.ts +1 -0
- package/dist/interactions.js +85 -14
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.3 - 2026-07-23
|
|
4
|
+
|
|
5
|
+
- Acknowledge slow interactions safely, edit deferred responses, support
|
|
6
|
+
module-owned public message updates and log bounded interaction identifiers
|
|
7
|
+
when handling fails.
|
|
8
|
+
|
|
3
9
|
## 0.1.2 - 2026-07-23
|
|
4
10
|
|
|
5
11
|
- Identify the included Helyx Source Available Licence as `HSAL 1.0` and align public core dependencies.
|
package/dist/interactions.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export declare function sendToChannel(client: Client, channelId: string, respons
|
|
|
19
19
|
messageId: string;
|
|
20
20
|
}>;
|
|
21
21
|
export declare function deleteChannelMessage(client: Client, channelId: string, messageId: string): Promise<void>;
|
|
22
|
+
export declare function editChannelMessage(client: Client, channelId: string, messageId: string, response: MessageResponse): Promise<void>;
|
|
22
23
|
export declare function normalizeDiscordPermission(permission: string): string;
|
|
23
24
|
export declare function toReplyOptions(response: MessageResponse): InteractionReplyOptions;
|
|
24
25
|
export declare function toUpdateOptions(response: MessageResponse): InteractionUpdateOptions;
|
package/dist/interactions.js
CHANGED
|
@@ -102,9 +102,17 @@ export function installInteractions(client, modules, registration, logger, servi
|
|
|
102
102
|
}
|
|
103
103
|
else if (interaction.isButton()) {
|
|
104
104
|
const button = buttons.get(interaction.customId);
|
|
105
|
+
const context = button
|
|
106
|
+
? createContext(interaction, services)
|
|
107
|
+
: undefined;
|
|
108
|
+
if (context &&
|
|
109
|
+
button?.contribution.acknowledgement === "deferred-ephemeral") {
|
|
110
|
+
await context.deferReply?.(true);
|
|
111
|
+
}
|
|
105
112
|
if (button &&
|
|
113
|
+
context &&
|
|
106
114
|
(await authorizeComponent(interaction, button.moduleId, services))) {
|
|
107
|
-
await button.contribution.execute(
|
|
115
|
+
await button.contribution.execute(context);
|
|
108
116
|
}
|
|
109
117
|
}
|
|
110
118
|
else if (interaction.isModalSubmit()) {
|
|
@@ -125,7 +133,11 @@ export function installInteractions(client, modules, registration, logger, servi
|
|
|
125
133
|
}
|
|
126
134
|
}
|
|
127
135
|
catch (error) {
|
|
128
|
-
logger.error({
|
|
136
|
+
logger.error({
|
|
137
|
+
event: "interaction.failed",
|
|
138
|
+
...interactionLogContext(interaction),
|
|
139
|
+
error: safeError(error),
|
|
140
|
+
}, "Module interaction failed");
|
|
129
141
|
await sendFailure(interaction);
|
|
130
142
|
}
|
|
131
143
|
}
|
|
@@ -241,7 +253,14 @@ function createContext(interaction, services) {
|
|
|
241
253
|
...(interaction.channelId ? { channelId: interaction.channelId } : {}),
|
|
242
254
|
...(interaction.isButton() ? { messageId: interaction.message.id } : {}),
|
|
243
255
|
services,
|
|
244
|
-
|
|
256
|
+
deferReply: async (ephemeral = false) => {
|
|
257
|
+
if (interaction.deferred || interaction.replied)
|
|
258
|
+
return;
|
|
259
|
+
await interaction.deferReply({
|
|
260
|
+
...(ephemeral ? { flags: MessageFlags.Ephemeral } : {}),
|
|
261
|
+
});
|
|
262
|
+
},
|
|
263
|
+
reply: (response) => replyToInteraction(interaction, response),
|
|
245
264
|
...(interaction.isMessageComponent()
|
|
246
265
|
? {
|
|
247
266
|
updateResponse: async (response) => interaction.update(toUpdateOptions(response)).then(() => undefined),
|
|
@@ -250,6 +269,7 @@ function createContext(interaction, services) {
|
|
|
250
269
|
showModal: async (modal) => interaction.showModal(toModal(modal)).then(() => undefined),
|
|
251
270
|
sendToChannel: (channelId, response) => sendToChannel(interaction.client, channelId, response),
|
|
252
271
|
deleteChannelMessage: (channelId, messageId) => deleteChannelMessage(interaction.client, channelId, messageId),
|
|
272
|
+
editChannelMessage: (channelId, messageId, response) => editChannelMessage(interaction.client, channelId, messageId, response),
|
|
253
273
|
addChannelMessageReaction: (channelId, messageId, emojiIdentifier) => addChannelMessageReaction(interaction.client, channelId, messageId, emojiIdentifier),
|
|
254
274
|
};
|
|
255
275
|
}
|
|
@@ -292,7 +312,14 @@ function createModalContext(interaction, services) {
|
|
|
292
312
|
...(interaction.guildId ? { serverId: interaction.guildId } : {}),
|
|
293
313
|
...(interaction.channelId ? { channelId: interaction.channelId } : {}),
|
|
294
314
|
services,
|
|
295
|
-
|
|
315
|
+
deferReply: async (ephemeral = false) => {
|
|
316
|
+
if (interaction.deferred || interaction.replied)
|
|
317
|
+
return;
|
|
318
|
+
await interaction.deferReply({
|
|
319
|
+
...(ephemeral ? { flags: MessageFlags.Ephemeral } : {}),
|
|
320
|
+
});
|
|
321
|
+
},
|
|
322
|
+
reply: (response) => replyToInteraction(interaction, response),
|
|
296
323
|
...(updateResponse ? { updateResponse } : {}),
|
|
297
324
|
getField: (customId) => interaction.fields.getTextInputValue(customId),
|
|
298
325
|
getStringSelectValues: (customId) => interaction.fields.getStringSelectValues(customId),
|
|
@@ -315,6 +342,7 @@ function createModalContext(interaction, services) {
|
|
|
315
342
|
],
|
|
316
343
|
sendToChannel: (channelId, response) => sendToChannel(interaction.client, channelId, response),
|
|
317
344
|
deleteChannelMessage: (channelId, messageId) => deleteChannelMessage(interaction.client, channelId, messageId),
|
|
345
|
+
editChannelMessage: (channelId, messageId, response) => editChannelMessage(interaction.client, channelId, messageId, response),
|
|
318
346
|
addChannelMessageReaction: (channelId, messageId, emojiIdentifier) => addChannelMessageReaction(interaction.client, channelId, messageId, emojiIdentifier),
|
|
319
347
|
};
|
|
320
348
|
}
|
|
@@ -339,6 +367,21 @@ export async function deleteChannelMessage(client, channelId, messageId) {
|
|
|
339
367
|
}
|
|
340
368
|
await channel.messages.delete(messageId);
|
|
341
369
|
}
|
|
370
|
+
export async function editChannelMessage(client, channelId, messageId, response) {
|
|
371
|
+
const channel = await client.channels.fetch(channelId);
|
|
372
|
+
if (!channel?.isTextBased()) {
|
|
373
|
+
throw new Error("Configured channel cannot contain messages");
|
|
374
|
+
}
|
|
375
|
+
const message = await channel.messages.fetch(messageId);
|
|
376
|
+
await message.edit(toUpdateOptions(response));
|
|
377
|
+
}
|
|
378
|
+
async function replyToInteraction(interaction, response) {
|
|
379
|
+
if (interaction.deferred || interaction.replied) {
|
|
380
|
+
await interaction.editReply(toUpdateOptions(response));
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
await interaction.reply(toReplyOptions(response));
|
|
384
|
+
}
|
|
342
385
|
async function addChannelMessageReaction(client, channelId, messageId, emojiIdentifier) {
|
|
343
386
|
const channel = await client.channels.fetch(channelId);
|
|
344
387
|
if (!channel?.isTextBased()) {
|
|
@@ -354,12 +397,16 @@ async function authorizeComponent(interaction, moduleId, services) {
|
|
|
354
397
|
if (await installations.isModuleEnabled(interaction.guildId, moduleId)) {
|
|
355
398
|
return true;
|
|
356
399
|
}
|
|
357
|
-
await interaction.
|
|
358
|
-
content: "This module is disabled in this server. Ask a server administrator to enable it with `/helyx` or in the Helyx dashboard.",
|
|
359
|
-
flags: MessageFlags.Ephemeral,
|
|
360
|
-
});
|
|
400
|
+
await replyEphemeralText(interaction, "This module is disabled in this server. Ask a server administrator to enable it with `/helyx` or in the Helyx dashboard.");
|
|
361
401
|
return false;
|
|
362
402
|
}
|
|
403
|
+
async function replyEphemeralText(interaction, content) {
|
|
404
|
+
if (interaction.deferred || interaction.replied) {
|
|
405
|
+
await interaction.editReply({ content });
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
await interaction.reply({ content, flags: MessageFlags.Ephemeral });
|
|
409
|
+
}
|
|
363
410
|
async function authorizeCommand(interaction, moduleId, commandId, rateLimit, services) {
|
|
364
411
|
if (!interaction.guildId)
|
|
365
412
|
return true;
|
|
@@ -650,17 +697,41 @@ export function toModal(definition) {
|
|
|
650
697
|
return modal;
|
|
651
698
|
}
|
|
652
699
|
async function sendFailure(interaction) {
|
|
653
|
-
if (!interaction.isRepliable()
|
|
700
|
+
if (!interaction.isRepliable())
|
|
701
|
+
return;
|
|
702
|
+
const message = "Something went wrong while handling that interaction.";
|
|
703
|
+
if (interaction.replied || interaction.deferred) {
|
|
704
|
+
await interaction.editReply({ content: message }).catch(() => undefined);
|
|
654
705
|
return;
|
|
706
|
+
}
|
|
655
707
|
await interaction
|
|
656
|
-
.reply({
|
|
657
|
-
content: "Something went wrong while handling that interaction.",
|
|
658
|
-
flags: MessageFlags.Ephemeral,
|
|
659
|
-
})
|
|
708
|
+
.reply({ content: message, flags: MessageFlags.Ephemeral })
|
|
660
709
|
.catch(() => undefined);
|
|
661
710
|
}
|
|
662
711
|
function safeError(error) {
|
|
663
712
|
const value = error instanceof Error ? error : new Error(String(error));
|
|
664
|
-
return {
|
|
713
|
+
return {
|
|
714
|
+
name: value.name,
|
|
715
|
+
message: value.message,
|
|
716
|
+
...("code" in value &&
|
|
717
|
+
(typeof value.code === "string" || typeof value.code === "number")
|
|
718
|
+
? { code: value.code }
|
|
719
|
+
: {}),
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
function interactionLogContext(interaction) {
|
|
723
|
+
return {
|
|
724
|
+
interactionId: interaction.id,
|
|
725
|
+
interactionType: interaction.type,
|
|
726
|
+
...(interaction.guildId ? { guildId: interaction.guildId } : {}),
|
|
727
|
+
...(interaction.isChatInputCommand()
|
|
728
|
+
? {
|
|
729
|
+
commandName: interaction.commandName,
|
|
730
|
+
subcommandName: interaction.options.getSubcommand(false) ?? undefined,
|
|
731
|
+
}
|
|
732
|
+
: "customId" in interaction && typeof interaction.customId === "string"
|
|
733
|
+
? { customId: interaction.customId }
|
|
734
|
+
: {}),
|
|
735
|
+
};
|
|
665
736
|
}
|
|
666
737
|
//# sourceMappingURL=interactions.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helyx/bot",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Production Discord runtime for the modular Helyx platform.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"helyx",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@helyx/config": "0.1.2",
|
|
52
|
-
"@helyx/core": "0.1.
|
|
52
|
+
"@helyx/core": "0.1.2",
|
|
53
53
|
"@helyx/database": "0.1.1",
|
|
54
|
-
"@helyx/framework": "0.1.
|
|
54
|
+
"@helyx/framework": "0.1.2",
|
|
55
55
|
"@helyx/module-manifest": "0.1.1",
|
|
56
|
-
"@helyx/platform": "0.1.
|
|
57
|
-
"@helyx/sdk": "0.2.
|
|
56
|
+
"@helyx/platform": "0.1.2",
|
|
57
|
+
"@helyx/sdk": "0.2.2",
|
|
58
58
|
"discord.js": "14.27.0",
|
|
59
59
|
"fastify": "5.10.0",
|
|
60
60
|
"pino": "10.3.1",
|