feat: add runtime patch for ModalSubmitInteraction to prevent crashes during member resolution

This commit is contained in:
2025-10-03 23:52:15 -05:00
parent 1a9eabb7af
commit 2d28e63a4f
2 changed files with 105 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
// filepath: src/core/patches/discordModalPatch.ts
/*
Runtime patch for discord.js 15.0.0-dev to avoid crashes when ModalSubmitInteraction
tries to cache members from resolved.members lacking the `user` field.
Source of truth: node_modules/discord.js/src/structures/ModalSubmitInteraction.js
*/
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { Collection } = require('@discordjs/collection');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const ModalModule = require('../../../node_modules/discord.js/src/structures/ModalSubmitInteraction.js');
export function applyModalSubmitInteractionPatch() {
const ModalSubmitInteraction = ModalModule?.ModalSubmitInteraction;
if (!ModalSubmitInteraction || typeof ModalSubmitInteraction !== 'function') {
return; // Nothing to patch
}
const original = ModalSubmitInteraction.prototype.transformComponent;
// Override with a safer version
// eslint-disable-next-line func-names
ModalSubmitInteraction.prototype.transformComponent = function (rawComponent: any, resolved: any) {
if ('components' in rawComponent) {
return {
type: rawComponent.type,
id: rawComponent.id,
components: rawComponent.components.map((component: any) => this.transformComponent(component, resolved)),
};
}
if ('component' in rawComponent) {
return {
type: rawComponent.type,
id: rawComponent.id,
component: this.transformComponent(rawComponent.component, resolved),
};
}
const data: any = {
type: rawComponent.type,
id: rawComponent.id,
};
if ('custom_id' in rawComponent) data.customId = rawComponent.custom_id;
if ('value' in rawComponent) data.value = rawComponent.value;
if (rawComponent.values) {
data.values = rawComponent.values;
if (resolved) {
const collect = (resolvedData: any, resolver: (val: any, id: string) => any) => {
const collection = new Collection();
for (const value of data.values as string[]) {
if (resolvedData?.[value]) {
const resolvedVal = resolver(resolvedData[value], value);
if (resolvedVal) collection.set(value, resolvedVal);
}
}
return collection.size ? collection : null;
};
const users = collect(resolved.users, (user: any) => this.client.users._add(user));
if (users) data.users = users;
const channels = collect(
resolved.channels,
(channel: any) => this.client.channels._add(channel, this.guild) ?? channel,
);
if (channels) data.channels = channels;
// SAFE members resolution: ensure member.user exists or skip _add fallbacking to raw
const members = collect(resolved.members, (member: any, id: string) => {
try {
if (!member?.user && resolved.users?.[id]) {
member.user = resolved.users[id];
}
// If still no user, don't call _add which would crash; return raw member
if (!member?.user) return member;
return this.guild?.members._add(member) ?? member;
} catch {
return member;
}
});
if (members) data.members = members;
const roles = collect(resolved.roles, (role: any) => this.guild?.roles._add(role) ?? role);
if (roles) data.roles = roles;
}
}
return data;
};
// Keep a reference in case we need to restore
(ModalSubmitInteraction.prototype as any).__originalTransformComponent = original;
}

View File

@@ -9,6 +9,7 @@ import {memoryOptimizer} from "./core/memory/memoryOptimizer";
import { startReminderPoller } from "./core/api/reminders";
import { ensureRemindersSchema } from "./core/api/remindersSchema";
import logger from "./core/lib/logger";
import { applyModalSubmitInteractionPatch } from "./core/patches/discordModalPatch";
// Activar monitor de memoria si se define la variable
const __memInt = parseInt(process.env.MEMORY_LOG_INTERVAL_SECONDS || '0', 10);
@@ -21,6 +22,13 @@ if (process.env.ENABLE_MEMORY_OPTIMIZER === 'true') {
memoryOptimizer.start();
}
// Apply safety patch for ModalSubmitInteraction members resolution before anything else
try {
applyModalSubmitInteractionPatch();
} catch (e) {
logger.warn({ err: e }, 'No se pudo aplicar el patch de ModalSubmitInteraction');
}
export const bot = new Amayo();
// Listeners de robustez del cliente Discord