fix: interaction callback

This commit is contained in:
CyberL1
2025-10-19 16:31:35 +02:00
committed by Rory&
parent d0ae4d06bc
commit bbd0617d53
8 changed files with 98 additions and 22 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ export const NO_AUTHORIZATION_ROUTES = [
"GET /invites/",
// Routes with a seperate auth system
/^(POST|HEAD|GET|PATCH|DELETE) \/webhooks\/\d+\/\w+\/?/, // no token requires auth
// /^POST \/interactions\/\d+\/\w+\/callback/, // This is marked as Unauthoricated route on https://discord.food. But when it is then not all requests have req.user_id?
/^POST \/interactions\/\d+\/[A-Za-z0-9_-]+\/callback/,
// Public information endpoints
"GET /ping",
"GET /gateway",
@@ -55,13 +55,13 @@ router.post("/", route({}), async (req: Request, res: Response) => {
// TODO
break;
case InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE: {
const message = Message.create({
const message = await Message.createWithDefaults({
type: MessageType.APPLICATION_COMMAND,
timestamp: new Date(),
application_id: req.user_id,
application_id: interaction.applicationId,
guild_id: interaction.guildId,
channel_id: interaction.channelId,
author_id: req.user_id,
author_id: interaction.applicationId,
content: body.data.content,
tts: body.data.tts,
embeds: body.data.embeds || [],
@@ -69,7 +69,7 @@ router.post("/", route({}), async (req: Request, res: Response) => {
poll: body.data.poll,
flags: body.data.flags,
reactions: [],
// webhook_id: req.user_id, // This one requires a webhook to be created first
// webhook_id: interaction.applicationId, // This one requires a webhook to be created first
interaction: {
id: interactionId,
name: interaction.commandName,
@@ -98,9 +98,9 @@ router.post("/", route({}), async (req: Request, res: Response) => {
event: "MESSAGE_CREATE",
channel_id: interaction.channelId,
data: {
application_id: message.application_id,
application_id: interaction.applicationId,
attachments: message.attachments,
author: (await User.findOneOrFail({ where: { id: message.author_id } })).toPublicUser(),
author: message.author?.toPublicUser(),
channel_id: message.channel_id,
channel_type: 0,
components: message.components,
@@ -131,7 +131,7 @@ router.post("/", route({}), async (req: Request, res: Response) => {
timestamp: message.timestamp,
tss: message.tts,
type: message.type,
webhook_id: req.user_id,
webhook_id: interaction.applicationId,
} as MessageCreateSchema,
} as MessageCreateEvent);
break;
+51 -11
View File
@@ -20,8 +20,9 @@ import { randomBytes } from "crypto";
import { InteractionSchema } from "@spacebar/schemas";
import { route } from "@spacebar/api";
import { Request, Response, Router } from "express";
import { emitEvent, InteractionCreateEvent, InteractionFailureEvent, Snowflake } from "@spacebar/util";
import { pendingInteractions } from "../../../util/imports/Interactions";
import { emitEvent, Guild, InteractionCreateEvent, InteractionFailureEvent, InteractionType, Member, Message, Snowflake, User } from "@spacebar/util";
import { pendingInteractions } from "@spacebar/util/imports/Interactions";
import { InteractionCreateSchema } from "@spacebar/schemas/api/bots/InteractionCreateSchema";
const router = Router({ mergeParams: true });
@@ -40,18 +41,56 @@ router.post("/", route({}), async (req: Request, res: Response) => {
},
} as InteractionCreateEvent);
const user = await User.findOneOrFail({ where: { id: req.user_id } });
const interactionData: Partial<InteractionCreateSchema> = {
id: interactionId,
application_id: body.application_id,
channel_id: body.channel_id,
type: body.type,
token: interactionToken,
version: 1,
app_permissions: "0", // TODO: add this later
entitlements: [],
authorizing_integration_owners: { "0": req.user_id },
context: 0, // TODO: add this later
attachment_size_limit: 0, // TODO: add this later
};
if (body.type === InteractionType.ApplicationCommand || body.data.type === InteractionType.MessageComponent || body.data.type === InteractionType.ModalSubmit) {
interactionData.data = body.data;
}
if (body.type != InteractionType.Ping) {
interactionData.locale = user?.settings?.locale;
}
if (body.guild_id) {
interactionData.guild_id = body.guild_id;
const guild = await Guild.findOneOrFail({ where: { id: body.guild_id } });
const member = await Member.findOneOrFail({ where: { guild_id: body.guild_id, id: req.user_id }, relations: ["user"] });
interactionData.guild = {
id: guild.id,
features: guild.features,
locale: guild.preferred_locale!,
};
interactionData.guild_locale = guild.preferred_locale;
interactionData.member = member.toPublicMember();
} else {
interactionData.user = user.toPublicUser();
}
if (body.type === InteractionType.MessageComponent || body.data.type === InteractionType.ModalSubmit) {
interactionData.message = await Message.findOneOrFail({ where: { id: body.message_id } });
}
emitEvent({
event: "INTERACTION_CREATE",
user_id: body.application_id,
data: {
channel_id: body.channel_id,
guild_id: body.guild_id,
id: interactionId,
member_id: req.user_id,
token: interactionToken,
type: body.type,
nonce: body.nonce,
},
data: interactionData,
} as InteractionCreateEvent);
const interactionTimeout = setTimeout(() => {
@@ -69,6 +108,7 @@ router.post("/", route({}), async (req: Request, res: Response) => {
pendingInteractions.set(interactionId, {
timeout: interactionTimeout,
nonce: body.nonce,
applicationId: body.application_id,
userId: req.user_id,
guildId: body.guild_id,
channelId: body.channel_id,