Temporary Fix for commands

This commit is contained in:
kmmiio99o 2025-09-29 22:18:06 +02:00
parent 5084adb3a8
commit 5d1ac74115
8 changed files with 236 additions and 120 deletions

2
.gitignore vendored
View file

@ -1,6 +1,4 @@
.idea
node_modules/
dist/
pnpm-lock.yaml
yarn.lock
package-lock.json

View file

@ -1,5 +1,5 @@
import { storage } from "@vendetta/plugin";
import { sendMessage } from "../utils/messages";
import { sendMessage, validateChannelForCommand } from "../utils/messages";
import { catFact, dogFact, uselessFact } from "../utils/api";
// Helper function to format fact response
@ -20,8 +20,17 @@ export const catFactCommand = {
inputType: 1,
type: 1,
execute: async (args: any, ctx: any) => {
const fact = await catFact();
return sendMessage(ctx.channel.id, formatFactResponse(fact), ctx.message?.id, storage);
const channelValidation = validateChannelForCommand(ctx);
if (channelValidation) return channelValidation;
try {
const fact = await catFact();
return sendMessage(ctx.channel.id, formatFactResponse(fact), ctx.message?.id, storage);
} catch (error) {
console.error('[CatFact] Error:', error);
// Silent fail - no error message in chat
return { type: 4 };
}
},
};
@ -34,8 +43,17 @@ export const dogFactCommand = {
inputType: 1,
type: 1,
execute: async (args: any, ctx: any) => {
const fact = await dogFact();
return sendMessage(ctx.channel.id, formatFactResponse(fact), ctx.message?.id, storage);
const channelValidation = validateChannelForCommand(ctx);
if (channelValidation) return channelValidation;
try {
const fact = await dogFact();
return sendMessage(ctx.channel.id, formatFactResponse(fact), ctx.message?.id, storage);
} catch (error) {
console.error('[DogFact] Error:', error);
// Silent fail - no error message in chat
return { type: 4 };
}
},
};
@ -48,7 +66,16 @@ export const uselessFactCommand = {
inputType: 1,
type: 1,
execute: async (args: any, ctx: any) => {
const fact = await uselessFact();
return sendMessage(ctx.channel.id, formatFactResponse(fact), ctx.message?.id, storage);
const channelValidation = validateChannelForCommand(ctx);
if (channelValidation) return channelValidation;
try {
const fact = await uselessFact();
return sendMessage(ctx.channel.id, formatFactResponse(fact), ctx.message?.id, storage);
} catch (error) {
console.error('[UselessFact] Error:', error);
// Silent fail - no error message in chat
return { type: 4 };
}
},
};

View file

@ -1,10 +1,16 @@
import { findByProps } from "@vendetta/metro";
import { url } from "@vendetta/metro/common";
import { validateChannelForCommand } from "../utils/messages";
const APIUtils = findByProps("getAPIBaseURL", "get");
const MessageActions = findByProps("sendMessage");
const messageUtil = findByProps("sendBotMessage", "sendMessage", "receiveMessage");
// Generate consistent nonce
const generateNonce = () => {
return (BigInt(Date.now()) * BigInt(4194304) + BigInt(Math.floor(Math.random() * 4194304))).toString();
};
// Helper functions for fetching messages
const getFirstGuildMessage = async (
guildId: string,
@ -65,6 +71,20 @@ export const firstMessageCommand = {
},
],
execute: async (args: any, ctx: any) => {
// Special handling for threads/forum channels
if (ctx.channel.type >= 10 && ctx.channel.type <= 15) {
return {
type: 4,
data: {
content: "FirstMessage command doesn't work in thread or forum channels.",
flags: 64
}
};
}
const channelValidation = validateChannelForCommand(ctx);
if (channelValidation) return channelValidation;
try {
const options = new Map(args.map((option: any) => [option.name, option]));
const user = options.get("user")?.value;
@ -96,7 +116,7 @@ export const firstMessageCommand = {
}
} else if (channel) {
if (isDM) {
messageUtil.sendBotMessage(channelId, "This combination cannot be used in DMs!");
// Silent fail for invalid combination
return { type: 4 };
}
message = await getFirstGuildMessage(guildId, null, channel);
@ -104,7 +124,7 @@ export const firstMessageCommand = {
} else {
// both user and channel specified
if (isDM) {
messageUtil.sendBotMessage(channelId, "This combination cannot be used in DMs!");
// Silent fail for invalid combination
return { type: 4 };
}
message = await getFirstGuildMessage(guildId, user, channel);
@ -112,12 +132,12 @@ export const firstMessageCommand = {
}
if (send) {
const fixNonce = Date.now().toString();
const nonce = generateNonce();
MessageActions.sendMessage(
ctx.channel.id,
{ content: result },
void 0,
{ nonce: fixNonce }
{ nonce }
);
return { type: 4 };
} else {
@ -126,7 +146,7 @@ export const firstMessageCommand = {
}
} catch (error) {
console.error("[FirstMessage] Error:", error);
messageUtil.sendBotMessage(ctx.channel.id, "Failed to fetch the first message. Please try again.");
// Silent fail - no error message in chat
return { type: 4 };
}
},

View file

@ -1,5 +1,6 @@
import { findByProps } from "@vendetta/metro";
import { alerts } from "@vendetta/ui";
import { validateChannelForCommand } from "../utils/messages";
const MessageActions = findByProps("sendMessage");
const messageUtil = findByProps(
@ -27,6 +28,7 @@ const fetchImage = async (isNSFW: boolean): Promise<string | null> => {
if (!Array.isArray(data) || data.length === 0) {
return null;
}
return data[0].file_url;
} catch (error) {
console.error("[KonoChan Randomizer] Error fetching image:", error);
@ -45,6 +47,11 @@ const showNSFWWarning = () => {
});
};
// Generate consistent nonce
const generateNonce = () => {
return (BigInt(Date.now()) * BigInt(4194304) + BigInt(Math.floor(Math.random() * 4194304))).toString();
};
// Common options for both commands
const nsfwOption = {
name: "nsfw",
@ -62,30 +69,36 @@ export const konoSelfCommand = {
displayDescription: "Fetch a random image from KonoChan for yourself.",
options: [nsfwOption],
execute: async (args: any, ctx: any) => {
const options = new Map(args.map((option: any) => [option.name, option]));
const isNSFW = options.get("nsfw")?.value || false;
const channelValidation = validateChannelForCommand(ctx);
if (channelValidation) return channelValidation;
// Check if channel is NSFW for NSFW content
if (isNSFW && !ctx.channel.nsfw) {
showNSFWWarning();
return { type: 4 };
}
try {
const options = new Map(args.map((option: any) => [option.name, option]));
const isNSFW = options.get("nsfw")?.value || false;
const imageUrl = await fetchImage(isNSFW);
// Check if channel is NSFW for NSFW content
if (isNSFW && !ctx.channel.nsfw) {
showNSFWWarning();
return { type: 4 };
}
const imageUrl = await fetchImage(isNSFW);
if (!imageUrl) {
// Silent fail - no error message
return { type: 4 };
}
if (!imageUrl) {
messageUtil.sendBotMessage(
ctx.channel.id,
"No image found. Try again later.",
`Here's your random image: ${imageUrl}`,
);
return { type: 4 };
} catch (error) {
console.error('[KonoSelf] Error:', error);
// Silent fail - no error message in chat
return { type: 4 };
}
messageUtil.sendBotMessage(
ctx.channel.id,
`Here's your random image: ${imageUrl}`,
);
return { type: 4 };
},
applicationId: "-1",
inputType: 1,
@ -100,33 +113,36 @@ export const konoSendCommand = {
"Fetch a random image from KonoChan and send it to the channel.",
options: [nsfwOption],
execute: async (args: any, ctx: any) => {
const options = new Map(args.map((option: any) => [option.name, option]));
const isNSFW = options.get("nsfw")?.value || false;
const channelValidation = validateChannelForCommand(ctx);
if (channelValidation) return channelValidation;
// Check if channel is NSFW for NSFW content
if (isNSFW && !ctx.channel.nsfw) {
showNSFWWarning();
try {
const options = new Map(args.map((option: any) => [option.name, option]));
const isNSFW = options.get("nsfw")?.value || false;
// Check if channel is NSFW for NSFW content
if (isNSFW && !ctx.channel.nsfw) {
showNSFWWarning();
return { type: 4 };
}
const imageUrl = await fetchImage(isNSFW);
if (!imageUrl) {
// Silent fail - no error message
return { type: 4 };
}
const nonce = generateNonce();
MessageActions.sendMessage(ctx.channel.id, { content: imageUrl }, void 0, {
nonce,
});
return { type: 4 };
} catch (error) {
console.error('[KonoSend] Error:', error);
// Silent fail - no error message in chat
return { type: 4 };
}
const imageUrl = await fetchImage(isNSFW);
if (!imageUrl) {
const fixNonce = Date.now().toString();
MessageActions.sendMessage(
ctx.channel.id,
{ content: "No image found. Try again later." },
void 0,
{ nonce: fixNonce },
);
return { type: 4 };
}
const fixNonce = Date.now().toString();
MessageActions.sendMessage(ctx.channel.id, { content: imageUrl }, void 0, {
nonce: fixNonce,
});
return { type: 4 };
},
applicationId: "-1",
inputType: 1,

View file

@ -1,63 +1,56 @@
import { findByProps } from "@vendetta/metro";
import { themes } from "@vendetta/themes";
import { plugins } from "@vendetta/plugins";
import { plugins, themes } from "@vendetta";
import { storage } from "@vendetta/plugin";
import { alerts } from "@vendetta/ui";
import { sendMessage } from "../utils/messages";
import { openURL } from "@vendetta/metro/common";
import { sendMessage, validateChannelForCommand } from "../utils/messages";
const SPLIT_LARGE_MESSAGES_PLUGIN =
"https://vd-plugins.github.io/proxy/actuallythesun.github.io/vendetta-plugins/SplitLargeMessages/";
const SPLIT_LARGE_MESSAGES_PLUGIN = "github.com/fres621/vendetta-plugins";
const STATUS = {
ENABLED: "🟢",
DISABLED: "🔴",
SELECTED: "🔶",
NOT_SELECTED: "🔷",
} as const;
ENABLED: "✅",
DISABLED: "❌",
SELECTED: "✅",
NOT_SELECTED: "❌",
};
// Helper Functions
const addonAuthors = (authors: Array<{ name: string }>) =>
authors.map((author) => author.name).join(", ");
// Helper functions
const addonAuthors = (authors: any[]) => {
if (!authors || authors.length === 0) return "Unknown";
return authors.map((author) => author.name).join(", ");
};
const formatList = (list: string[]) => list.join("\n").trimEnd();
const formatList = (list: string[]) => list.join("\n");
const getListLength = (list: string[]) => formatList(list).length;
const isSLMPluginInstalled = () =>
Object.keys(plugins).includes(SPLIT_LARGE_MESSAGES_PLUGIN);
const isSLMPluginInstalled = () => {
return Object.values(plugins).some((plugin) => plugin.id === SPLIT_LARGE_MESSAGES_PLUGIN);
};
const isSLMPluginEnabled = () =>
Object.values(plugins).find((p) => p.id === SPLIT_LARGE_MESSAGES_PLUGIN)
?.enabled ?? false;
const isSLMPluginEnabled = () => {
const slmPlugin = Object.values(plugins).find((p) => p.id === SPLIT_LARGE_MESSAGES_PLUGIN);
return slmPlugin?.enabled ?? false;
};
const showSplitPluginDialog = () => {
return alerts.showConfirmationAlert({
title: "Large Message Warning",
content:
"This list is too long to send! Would you like to install the Split Large Messages plugin?",
confirmText: "Install Plugin",
title: "Install Split Large Messages Plugin",
content: "This list is over 2000 characters. Install the Split Large Messages plugin to send it.",
confirmText: "Install",
cancelText: "Cancel",
confirmColor: "brand",
onConfirm: () => {
openURL(SPLIT_LARGE_MESSAGES_PLUGIN);
// Implementation to install plugin would go here
},
});
};
const showEnablePluginDialog = () => {
return alerts.showConfirmationAlert({
title: "Plugin Disabled",
content:
"The Split Large Messages plugin is installed but disabled. Would you like to enable it now?",
confirmText: "Enable Plugin",
title: "Enable Split Large Messages Plugin",
content: "This list is over 2000 characters. Enable the Split Large Messages plugin to send it.",
confirmText: "Enable",
cancelText: "Cancel",
confirmColor: "brand",
onConfirm: () => {
// Enable the plugin
const slmPlugin = Object.values(plugins).find(
(p) => p.id === SPLIT_LARGE_MESSAGES_PLUGIN,
);
const slmPlugin = Object.values(plugins).find((p) => p.id === SPLIT_LARGE_MESSAGES_PLUGIN);
if (slmPlugin) {
slmPlugin.enabled = true;
}
@ -67,8 +60,7 @@ const showEnablePluginDialog = () => {
// Command handlers
async function handlePluginList(detailed: boolean, ctx: any) {
const alwaysDetailed =
storage.listSettings?.pluginListAlwaysDetailed ?? false;
const alwaysDetailed = storage.listSettings?.pluginListAlwaysDetailed ?? false;
const pluginList = [
`**My Plugin List | ${Object.keys(plugins).length} Plugins**`,
"",
@ -182,9 +174,17 @@ export const pluginListCommand = {
},
],
execute: async (args: any, ctx: any) => {
const detailed =
args.find((arg: any) => arg.name === "detailed")?.value ?? false;
return handlePluginList(detailed, ctx);
const channelValidation = validateChannelForCommand(ctx);
if (channelValidation) return channelValidation;
try {
const detailed = args.find((arg: any) => arg.name === "detailed")?.value ?? false;
return handlePluginList(detailed, ctx);
} catch (error) {
console.error('[PluginList] Error:', error);
// Silent fail - no error message in chat
return { type: 4 };
}
},
applicationId: "-1",
inputType: 1,
@ -207,9 +207,17 @@ export const themeListCommand = {
},
],
execute: async (args: any, ctx: any) => {
const detailed =
args.find((arg: any) => arg.name === "detailed")?.value ?? false;
return handleThemeList(detailed, ctx);
const channelValidation = validateChannelForCommand(ctx);
if (channelValidation) return channelValidation;
try {
const detailed = args.find((arg: any) => arg.name === "detailed")?.value ?? false;
return handleThemeList(detailed, ctx);
} catch (error) {
console.error('[ThemeList] Error:', error);
// Silent fail - no error message in chat
return { type: 4 };
}
},
applicationId: "-1",
inputType: 1,

View file

@ -1,5 +1,5 @@
import { findByStoreName } from "@vendetta/metro";
import { sendMessage } from "../utils/messages";
import { sendMessage, validateChannelForCommand } from "../utils/messages";
import { getPetPetData } from "../utils/api";
const UserStore = findByStoreName("UserStore");
@ -20,10 +20,19 @@ export const petPetCommand = {
},
],
execute: async (args: any, ctx: any) => {
const user = await UserStore.getUser(args[0].value);
const image = user.getAvatarURL(512);
const data = await getPetPetData(image);
return sendMessage(ctx.channel.id, data.url, ctx.message?.id);
const channelValidation = validateChannelForCommand(ctx);
if (channelValidation) return channelValidation;
try {
const user = await UserStore.getUser(args[0].value);
const image = user.getAvatarURL(512);
const data = await getPetPetData(image);
return sendMessage(ctx.channel.id, data.url, ctx.message?.id);
} catch (error) {
console.error('[PetPet] Error:', error);
// Silent fail - no error message in chat
return { type: 4 };
}
},
applicationId: "-1",
inputType: 1,

View file

@ -2,6 +2,7 @@ import { findByProps } from "@vendetta/metro";
import { getDebugInfo } from "@vendetta/debug";
import { ReactNative } from "@vendetta/metro/common";
import { storage } from "@vendetta/plugin";
import { validateChannelForCommand } from "../utils/messages";
const MessageActions = findByProps("sendMessage");
const messageUtil = findByProps("sendBotMessage", "sendMessage", "receiveMessage");
@ -145,8 +146,16 @@ for (const cat of categories) {
if (storage[cat] === undefined) storage[cat] = true;
}
// Command execution function
function sysinfoCommand(args: any[], ctx: any) {
// Generate consistent nonce
const generateNonce = () => {
return (BigInt(Date.now()) * BigInt(4194304) + BigInt(Math.floor(Math.random() * 4194304))).toString();
};
// Command execution function (renamed to avoid conflict)
function executeSysinfoCommand(args: any[], ctx: any) {
const channelValidation = validateChannelForCommand(ctx);
if (channelValidation) return channelValidation;
try {
let output = ["__System Information__\n"];
const data = generateSystemInfo();
@ -171,18 +180,18 @@ function sysinfoCommand(args: any[], ctx: any) {
messageUtil.sendBotMessage(ctx.channel.id, output.join("\n"));
return { type: 4 };
} else {
const fixNonce = Date.now().toString();
const nonce = generateNonce();
MessageActions.sendMessage(
ctx.channel.id,
{ content: output.join("\n") },
void 0,
{ nonce: fixNonce }
{ nonce }
);
return { type: 4 };
}
} catch (e) {
console.error("[Sysinfo] Error:", e);
messageUtil.sendBotMessage(ctx.channel.id, "Failed to generate system information. Please try again.");
// Silent fail - no chat message
return { type: 4 };
}
}
@ -210,7 +219,7 @@ export const sysinfoCommand = {
required: false,
})),
],
execute: sysinfoCommand,
execute: executeSysinfoCommand,
applicationId: "-1",
inputType: 1,
type: 1,

View file

@ -2,6 +2,14 @@ import { findByProps } from "@vendetta/metro";
const MessageActions = findByProps("sendMessage");
// Channel type validation
const isValidChannel = (channelType: number) => {
// Allow: Text (0), DM (1), Voice (2), Group DM (3), News (5)
// Block: Threads (10,11,12), Forum (15), Stage (13), Category (4)
const unsupportedTypes = [4, 10, 11, 12, 13, 15];
return !unsupportedTypes.includes(channelType);
};
export const sendMessage = (
channelId: string,
content: string,
@ -23,17 +31,38 @@ export const sendMessage = (
};
}
// For normal messages, send through MessageActions
const message = {
content,
...(replyToId && storage?.factSettings?.sendAsReply
? { messageReference: { messageId: replyToId } }
: {}),
};
try {
// For normal messages, send through MessageActions
const message = {
content,
...(replyToId && storage?.factSettings?.sendAsReply
? { messageReference: { messageId: replyToId } }
: {}),
};
MessageActions.sendMessage(channelId, message, void 0, {
nonce: (Date.now() * 4194304).toString(),
});
// Use consistent, collision-resistant nonce generation
const nonce = (BigInt(Date.now()) * BigInt(4194304) + BigInt(Math.floor(Math.random() * 4194304))).toString();
return { type: 4 }; // Acknowledge the command
MessageActions.sendMessage(channelId, message, void 0, { nonce });
return { type: 4 }; // Acknowledge the command
} catch (error) {
console.error('[Commands] Message send failed:', error);
// Silent fail - no error message in chat
return { type: 4 };
}
};
// Helper function to validate channel types in commands
export const validateChannelForCommand = (ctx: any) => {
if (!isValidChannel(ctx.channel.type)) {
return {
type: 4,
data: {
content: "This command cannot be used in threads, forum channels, or voice channels.",
flags: 64 // Ephemeral
}
};
}
return null;
};