From 6cb3824d72c05939bb8f5ddd8c02fa602f668a6c Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Tue, 16 May 2023 14:17:20 +0800 Subject: [PATCH 1/6] [Commands] Init core commands --- src/def.d.ts | 1 + src/lib/commands/debug.ts | 42 +++++++++++++++++++ src/lib/commands/eval.ts | 47 ++++++++++++++++++++++ src/lib/{commands.ts => commands/index.ts} | 29 ++++++++----- src/lib/metro/common.ts | 1 + 5 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 src/lib/commands/debug.ts create mode 100644 src/lib/commands/eval.ts rename src/lib/{commands.ts => commands/index.ts} (58%) diff --git a/src/def.d.ts b/src/def.d.ts index 802715ab..07a9e36b 100644 --- a/src/def.d.ts +++ b/src/def.d.ts @@ -388,6 +388,7 @@ interface VendettaObject { invites: PropIntellisense<"acceptInviteAndTransitionToInviteChannel">; commands: PropIntellisense<"getBuiltInCommands">; navigation: PropIntellisense<"pushLazy">; + messageUtil: PropIntellisense<"sendBotMessage">; navigationStack: PropIntellisense<"createStackNavigator">; NavigationNative: PropIntellisense<"NavigationContainer">; // You may ask: "Why not just install Flux's types?" diff --git a/src/lib/commands/debug.ts b/src/lib/commands/debug.ts new file mode 100644 index 00000000..2d874a8e --- /dev/null +++ b/src/lib/commands/debug.ts @@ -0,0 +1,42 @@ +import { ApplicationCommand, ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType } from "@types"; +import { getDebugInfo } from "@lib/debug"; +import { findByProps } from "@metro/filters"; + +const messageUtil = findByProps("sendBotMessage"); + +export default { + name: "debug", + displayName: "debug", + description: "Send Vendetta debug info.", + displayDescription: "Send Vendetta debug info.", + options: [ + { + name: "ephemeral", + displayName: "ephemeral", + type: ApplicationCommandOptionType.BOOLEAN, + description: "Send debug info ephemerally.", + displayDescription: "Send debug info ephemerally.", + } + ], + applicationId: "-1", + inputType: ApplicationCommandInputType.BUILT_IN_TEXT, + type: ApplicationCommandType.CHAT, + execute([ephemeral], ctx) { + const info = getDebugInfo(); + const content = [ + "**__Vendetta Debug Info__**", + `> Vendetta: ${info.vendetta.version} (${info.vendetta.loader})`, + `> Discord: ${info.discord.version} (${info.discord.build})`, + `> React: ${info.react.version} (RN ${info.react.nativeVersion})`, + `> Hermes: ${info.hermes.version} (bcv${info.hermes.bytecodeVersion})`, + `> System: ${info.os.name} ${info.os.version} (SDK ${info.os.sdk})`, + `> Device: ${info.device.model} (${info.device.codename})`, + ].join("\n"); + + if (ephemeral?.value) { + messageUtil.sendBotMessage(ctx.channel.id, content); + } else { + return { content }; + } + } +} diff --git a/src/lib/commands/eval.ts b/src/lib/commands/eval.ts new file mode 100644 index 00000000..52e98082 --- /dev/null +++ b/src/lib/commands/eval.ts @@ -0,0 +1,47 @@ +import { findByProps } from "@metro/filters"; +import { messageUtil } from "@metro/common"; +import { ApplicationCommand, ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType } from "@types"; + +const util = findByProps("inspect"); +const AsyncFunction = (async () => void 0).constructor; + +function wrapInJSCodeblock(resString: string) { + return "```js\n" + resString + "\n```"; +} + +export default { + name: "eval", + displayName: "eval", + description: "Evaluate JavaScript code.", + displayDescription: "Evaluate JavaScript code.", + options: [ + { + name: "code", + displayName: "code", + type: ApplicationCommandOptionType.STRING, + description: "The code to evaluate.", + displayDescription: "The code to evaluate.", + required: true + }, + { + name: "async", + displayName: "async", + type: ApplicationCommandOptionType.BOOLEAN, + description: "Whether to support 'await' in code. Must explicitly return for result (default: false)", + displayDescription: "Whether to support 'await' in code. Must explicitly return for result (default: false)" + } + ], + applicationId: "-1", + inputType: ApplicationCommandInputType.BUILT_IN_TEXT, + type: ApplicationCommandType.CHAT, + async execute([code, async], ctx) { + try { + const res = util.inspect(async?.value ? await AsyncFunction(code.value)() : eval?.(code.value)); + const trimmedRes = res.length > 2000 ? res.slice(0, 2000) + "..." : res; + + messageUtil.sendBotMessage(ctx.channel.id, wrapInJSCodeblock(trimmedRes)); + } catch (err: any) { + messageUtil.sendBotMessage(ctx.channel.id, wrapInJSCodeblock(err?.stack ?? err)); + } + } +} diff --git a/src/lib/commands.ts b/src/lib/commands/index.ts similarity index 58% rename from src/lib/commands.ts rename to src/lib/commands/index.ts index 1fdcbfda..86721c5c 100644 --- a/src/lib/commands.ts +++ b/src/lib/commands/index.ts @@ -1,30 +1,37 @@ -import { ApplicationCommand } from "@types"; -import { commands as commandsModule } from "@metro/common"; import { after } from "@lib/patcher"; +import { commands as commandsModule } from "@metro/common"; +import { ApplicationCommand } from "@types"; + +import evalCommand from "@lib/commands/eval"; +import debugCommand from "@lib/commands/debug"; let commands: ApplicationCommand[] = []; export function patchCommands() { - const unpatch = after("getBuiltInCommands", commandsModule, (_, res) => res.concat(commands)); - return () => { - commands = []; - unpatch(); - } + const unpatch = after("getBuiltInCommands", commandsModule, (_, res) => res.concat(commands)); + + // Register core commands + [evalCommand, debugCommand].forEach(registerCommand); + + return () => { + commands = []; + unpatch(); + } } export function registerCommand(command: ApplicationCommand): () => void { // Get built in commands - const builtInCommands = commandsModule.getBuiltInCommands(1, true, false); - builtInCommands.sort(function (a: ApplicationCommand, b: ApplicationCommand) { return parseInt(b.id!) - parseInt(a.id!) }); + const builtInCommands = commandsModule.getBuiltInCommands(1, true, false) as ApplicationCommand[]; + builtInCommands.sort((a, b) => parseInt(b.id!) - parseInt(a.id!)); const lastCommand = builtInCommands[builtInCommands.length - 1]; // Override the new command's id to the last command id - 1 - command.id = (parseInt(lastCommand.id, 10) - 1).toString(); + command.id = (Number(lastCommand.id!) - 1).toString(); // Add it to the commands array commands.push(command); // Return command id so it can be unregistered return () => commands = commands.filter(({ id }) => id !== command.id); -} \ No newline at end of file +} diff --git a/src/lib/metro/common.ts b/src/lib/metro/common.ts index 689a8ded..afe43a6d 100644 --- a/src/lib/metro/common.ts +++ b/src/lib/metro/common.ts @@ -13,6 +13,7 @@ export const assets = findByProps("registerAsset"); export const invites = findByProps("acceptInviteAndTransitionToInviteChannel"); export const commands = findByProps("getBuiltInCommands"); export const navigation = findByProps("pushLazy"); +export const messageUtil = findByProps("sendBotMessage"); export const navigationStack = findByProps("createStackNavigator"); export const NavigationNative = findByProps("NavigationContainer"); From 29a433c2633b80d0369e44be67beb9a6d19b5c1b Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Tue, 16 May 2023 14:18:27 +0800 Subject: [PATCH 2/6] [Commands] Remove duplicate module find --- src/lib/commands/debug.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib/commands/debug.ts b/src/lib/commands/debug.ts index 2d874a8e..f29c875a 100644 --- a/src/lib/commands/debug.ts +++ b/src/lib/commands/debug.ts @@ -1,8 +1,6 @@ import { ApplicationCommand, ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType } from "@types"; import { getDebugInfo } from "@lib/debug"; -import { findByProps } from "@metro/filters"; - -const messageUtil = findByProps("sendBotMessage"); +import { messageUtil } from "@metro/common"; export default { name: "debug", From 781207492b4428639106079c9e36afa6b9c369fa Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Tue, 16 May 2023 14:34:22 +0800 Subject: [PATCH 3/6] [Commands] Append ZSWC when needed --- src/lib/commands/eval.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/commands/eval.ts b/src/lib/commands/eval.ts index 52e98082..2a0e27bc 100644 --- a/src/lib/commands/eval.ts +++ b/src/lib/commands/eval.ts @@ -5,8 +5,10 @@ import { ApplicationCommand, ApplicationCommandInputType, ApplicationCommandOpti const util = findByProps("inspect"); const AsyncFunction = (async () => void 0).constructor; +const ZERO_WIDTH_SPACE_CHARACTER = "\u200B"; + function wrapInJSCodeblock(resString: string) { - return "```js\n" + resString + "\n```"; + return "```js\n" + resString.replaceAll("`", "`" + ZERO_WIDTH_SPACE_CHARACTER) + "\n```"; } export default { From b0ac0b487f4232f7eddfabf378f9fbba45bbd437 Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Tue, 16 May 2023 20:29:18 +0800 Subject: [PATCH 4/6] [Commands] Add /plugins --- src/lib/commands/index.ts | 3 ++- src/lib/commands/plugins.ts | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/lib/commands/plugins.ts diff --git a/src/lib/commands/index.ts b/src/lib/commands/index.ts index 86721c5c..0db57abd 100644 --- a/src/lib/commands/index.ts +++ b/src/lib/commands/index.ts @@ -4,6 +4,7 @@ import { ApplicationCommand } from "@types"; import evalCommand from "@lib/commands/eval"; import debugCommand from "@lib/commands/debug"; +import pluginCommand from "@lib/commands/plugins"; let commands: ApplicationCommand[] = []; @@ -11,7 +12,7 @@ export function patchCommands() { const unpatch = after("getBuiltInCommands", commandsModule, (_, res) => res.concat(commands)); // Register core commands - [evalCommand, debugCommand].forEach(registerCommand); + [evalCommand, debugCommand, pluginCommand].forEach(registerCommand); return () => { commands = []; diff --git a/src/lib/commands/plugins.ts b/src/lib/commands/plugins.ts new file mode 100644 index 00000000..3ae32484 --- /dev/null +++ b/src/lib/commands/plugins.ts @@ -0,0 +1,42 @@ +import { ApplicationCommand, ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType, Plugin } from "@types"; +import { messageUtil } from "@metro/common"; +import { plugins as pluginStorage } from "../plugins"; + +export default { + name: "plugins", + displayName: "plugins", + description: "Send list of installed plugins.", + displayDescription: "Send list of installed plugins.", + options: [ + { + name: "ephemeral", + displayName: "ephemeral", + type: ApplicationCommandOptionType.BOOLEAN, + description: "Send plugins list ephemerally.", + displayDescription: "Send plugins list ephemerally.", + } + ], + applicationId: "-1", + inputType: ApplicationCommandInputType.BUILT_IN_TEXT, + type: ApplicationCommandType.CHAT, + execute([ephemeral], ctx) { + const plugins = Object.values(pluginStorage).sort((a, b) => a.manifest.name.localeCompare(b.manifest.name)); + + const enabled = plugins.filter(p => p.enabled).map(p => p.manifest.name); + const disabled = plugins.filter(p => !p.enabled).map(p => p.manifest.name); + + const content = [ + `**__Installed Plugins (${plugins.length})__**`, + `Enabled (${enabled.length}):`, + "> " + enabled.join(", "), + `Disabled (${disabled.length}):`, + "> " + disabled.join(", "), + ].join("\n"); + + if (ephemeral?.value) { + messageUtil.sendBotMessage(ctx.channel.id, content); + } else { + return { content }; + } + } +} From e8d78fe8a5eb1a62e978b7f498235ed59f241b5c Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Tue, 16 May 2023 20:43:12 +0800 Subject: [PATCH 5/6] [Commands] Check plugins length first --- src/lib/commands/plugins.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/lib/commands/plugins.ts b/src/lib/commands/plugins.ts index 3ae32484..d24bc70b 100644 --- a/src/lib/commands/plugins.ts +++ b/src/lib/commands/plugins.ts @@ -27,10 +27,14 @@ export default { const content = [ `**__Installed Plugins (${plugins.length})__**`, - `Enabled (${enabled.length}):`, - "> " + enabled.join(", "), - `Disabled (${disabled.length}):`, - "> " + disabled.join(", "), + ...(enabled.length > 0 ? [ + `Enabled (${enabled.length}):`, + "> " + enabled.join(", "), + ] : []), + ...(disabled.length > 0 ? [ + `Disabled (${disabled.length}):`, + "> " + disabled.join(", "), + ] : []), ].join("\n"); if (ephemeral?.value) { From 9b70e8e11a8b3b58a20eac6cff0615ece8c3229e Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Tue, 30 May 2023 15:44:02 +0800 Subject: [PATCH 6/6] Remove `applicationId` entry --- src/lib/commands/plugins.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/commands/plugins.ts b/src/lib/commands/plugins.ts index d24bc70b..523cd1d4 100644 --- a/src/lib/commands/plugins.ts +++ b/src/lib/commands/plugins.ts @@ -16,7 +16,6 @@ export default { displayDescription: "Send plugins list ephemerally.", } ], - applicationId: "-1", inputType: ApplicationCommandInputType.BUILT_IN_TEXT, type: ApplicationCommandType.CHAT, execute([ephemeral], ctx) {