aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Vencord.ts15
-rw-r--r--src/api/Commands/commandHelpers.ts2
-rw-r--r--src/components/PluginSettings/PluginModal.tsx2
-rw-r--r--src/components/PluginSettings/index.tsx2
-rw-r--r--src/plugins/experiments.tsx2
-rw-r--r--src/plugins/ignoreActivities.ts2
-rw-r--r--src/plugins/index.ts1
-rw-r--r--src/plugins/interactionKeybinds.ts2
-rw-r--r--src/plugins/petpet.ts6
-rw-r--r--src/plugins/pronoundb/components/PronounsChatComponent.tsx2
-rw-r--r--src/plugins/reverseImageSearch.tsx2
-rw-r--r--src/plugins/sendify.ts6
-rw-r--r--src/utils/logger.ts2
-rw-r--r--src/webpack/common.tsx2
-rw-r--r--src/webpack/patchWebpack.ts2
-rw-r--r--src/webpack/webpack.ts97
16 files changed, 91 insertions, 56 deletions
diff --git a/src/Vencord.ts b/src/Vencord.ts
index 4d18cb2..041335f 100644
--- a/src/Vencord.ts
+++ b/src/Vencord.ts
@@ -25,7 +25,7 @@ export * as Webpack from "./webpack";
import { popNotice, showNotice } from "./api/Notices";
import { PlainSettings, Settings } from "./api/settings";
-import { startAllPlugins } from "./plugins";
+import { patches, PMLogger, startAllPlugins } from "./plugins";
export { PlainSettings, Settings };
@@ -61,6 +61,19 @@ async function init() {
UpdateLogger.error("Failed to check for updates", err);
}
}
+
+ if (IS_DEV) {
+ const pendingPatches = patches.filter(p => !p.all && p.predicate?.() !== false);
+ if (pendingPatches.length)
+ PMLogger.warn(
+ "Webpack has finished initialising, but some patches haven't been applied yet.",
+ "This might be expected since some Modules are lazy loaded, but please verify",
+ "that all plugins are working as intended.",
+ "You are seeing this warning because this is a Development build of Vencord.",
+ "\nThe following patches have not been applied:",
+ "\n\n" + pendingPatches.map(p => `${p.plugin}: ${p.find}`).join("\n")
+ );
+ }
}
init();
diff --git a/src/api/Commands/commandHelpers.ts b/src/api/Commands/commandHelpers.ts
index 90b89ed..8986248 100644
--- a/src/api/Commands/commandHelpers.ts
+++ b/src/api/Commands/commandHelpers.ts
@@ -24,7 +24,7 @@ import { filters, waitFor } from "../../webpack";
import { Argument } from "./types";
const createBotMessage = lazyWebpack(filters.byCode('username:"Clyde"'));
-const MessageSender = lazyWebpack(filters.byProps(["receiveMessage"]));
+const MessageSender = lazyWebpack(filters.byProps("receiveMessage"));
let SnowflakeUtils: any;
waitFor("fromTimestamp", m => SnowflakeUtils = m);
diff --git a/src/components/PluginSettings/PluginModal.tsx b/src/components/PluginSettings/PluginModal.tsx
index 9a47c32..4c14d61 100644
--- a/src/components/PluginSettings/PluginModal.tsx
+++ b/src/components/PluginSettings/PluginModal.tsx
@@ -38,7 +38,7 @@ import {
} from "./components";
const UserSummaryItem = lazyWebpack(filters.byCode("defaultRenderUser", "showDefaultAvatarsForNullUsers"));
-const AvatarStyles = lazyWebpack(filters.byProps(["moreUsers", "emptyUser", "avatarContainer", "clickableAvatar"]));
+const AvatarStyles = lazyWebpack(filters.byProps("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar"));
const UserRecord: Constructor<Partial<User>> = proxyLazy(() => UserStore.getCurrentUser().constructor) as any;
interface PluginModalProps extends ModalProps {
diff --git a/src/components/PluginSettings/index.tsx b/src/components/PluginSettings/index.tsx
index 1a2e78f..9ab1396 100644
--- a/src/components/PluginSettings/index.tsx
+++ b/src/components/PluginSettings/index.tsx
@@ -36,7 +36,7 @@ import * as styles from "./styles";
const logger = new Logger("PluginSettings", "#a6d189");
const Select = lazyWebpack(filters.byCode("optionClassName", "popoutPosition", "autoFocus", "maxVisibleItems"));
-const InputStyles = lazyWebpack(filters.byProps(["inputDefault", "inputWrapper"]));
+const InputStyles = lazyWebpack(filters.byProps("inputDefault", "inputWrapper"));
const CogWheel = lazyWebpack(filters.byCode("18.564C15.797 19.099 14.932 19.498 14 19.738V22H10V19.738C9.069"));
const InfoIcon = lazyWebpack(filters.byCode("4.4408921e-16 C4.4771525,-1.77635684e-15 4.4408921e-16"));
diff --git a/src/plugins/experiments.tsx b/src/plugins/experiments.tsx
index c6303f3..eac5b48 100644
--- a/src/plugins/experiments.tsx
+++ b/src/plugins/experiments.tsx
@@ -23,7 +23,7 @@ import { Settings } from "../Vencord";
import { filters } from "../webpack";
import { Forms, React } from "../webpack/common";
-const KbdStyles = lazyWebpack(filters.byProps(["key", "removeBuildOverride"]));
+const KbdStyles = lazyWebpack(filters.byProps("key", "removeBuildOverride"));
export default definePlugin({
name: "Experiments",
diff --git a/src/plugins/ignoreActivities.ts b/src/plugins/ignoreActivities.ts
index a429136..5c1ddcc 100644
--- a/src/plugins/ignoreActivities.ts
+++ b/src/plugins/ignoreActivities.ts
@@ -28,7 +28,7 @@ interface MatchAndReplace {
}
/** Used to re-render the Registered Games tab to update how our button looks like */
-const RunningGameStoreModule = lazyWebpack(filters.byProps(["IgnoreActivities_reRenderGames"]));
+const RunningGameStoreModule = lazyWebpack(filters.byProps("IgnoreActivities_reRenderGames"));
let ignoredActivitiesCache: string[] = [];
diff --git a/src/plugins/index.ts b/src/plugins/index.ts
index be6fae3..86d44b4 100644
--- a/src/plugins/index.ts
+++ b/src/plugins/index.ts
@@ -25,6 +25,7 @@ import { Patch, Plugin } from "../utils/types";
const logger = new Logger("PluginManager", "#a6d189");
+export const PMLogger = logger;
export const plugins = Plugins;
export const patches = [] as Patch[];
diff --git a/src/plugins/interactionKeybinds.ts b/src/plugins/interactionKeybinds.ts
index 1d28847..76a25bb 100644
--- a/src/plugins/interactionKeybinds.ts
+++ b/src/plugins/interactionKeybinds.ts
@@ -24,7 +24,7 @@ import definePlugin from "../utils/types";
import { filters } from "../webpack";
import { ChannelStore, FluxDispatcher as Dispatcher, SelectedChannelStore, UserStore } from "../webpack/common";
-const MessageStore = lazyWebpack(filters.byProps(["getRawMessages"]));
+const MessageStore = lazyWebpack(filters.byProps("getRawMessages"));
const isMac = navigator.platform.includes("Mac"); // bruh
let replyIdx = -1;
diff --git a/src/plugins/petpet.ts b/src/plugins/petpet.ts
index 8f2462d..093acba 100644
--- a/src/plugins/petpet.ts
+++ b/src/plugins/petpet.ts
@@ -16,9 +16,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { ApplicationCommandInputType, ApplicationCommandOptionType, Argument, CommandContext,findOption } from "../api/Commands";
+import { ApplicationCommandInputType, ApplicationCommandOptionType, Argument, CommandContext, findOption } from "../api/Commands";
import { Devs } from "../utils/constants";
-import { lazyWebpack,makeLazy } from "../utils/misc";
+import { lazyWebpack, makeLazy } from "../utils/misc";
import definePlugin from "../utils/types";
import { filters } from "../webpack";
@@ -41,7 +41,7 @@ const getFrames = makeLazy(() => Promise.all(
const fetchUser = lazyWebpack(filters.byCode(".USER("));
const promptToUpload = lazyWebpack(filters.byCode("UPLOAD_FILE_LIMIT_ERROR"));
-const UploadStore = lazyWebpack(filters.byProps(["getUploads"]));
+const UploadStore = lazyWebpack(filters.byProps("getUploads"));
function loadImage(source: File | string) {
const isFile = source instanceof File;
diff --git a/src/plugins/pronoundb/components/PronounsChatComponent.tsx b/src/plugins/pronoundb/components/PronounsChatComponent.tsx
index ec4de98..2d20461 100644
--- a/src/plugins/pronoundb/components/PronounsChatComponent.tsx
+++ b/src/plugins/pronoundb/components/PronounsChatComponent.tsx
@@ -25,7 +25,7 @@ import { UserStore } from "../../../webpack/common";
import { PronounMapping } from "../types";
import { fetchPronouns, formatPronouns } from "../utils";
-const styles: Record<string, string> = lazyWebpack(filters.byProps(["timestampInline"]));
+const styles: Record<string, string> = lazyWebpack(filters.byProps("timestampInline"));
export default function PronounsChatComponent({ message }: { message: Message; }) {
// Don't bother fetching bot or system users
diff --git a/src/plugins/reverseImageSearch.tsx b/src/plugins/reverseImageSearch.tsx
index 9f618de..da7d844 100644
--- a/src/plugins/reverseImageSearch.tsx
+++ b/src/plugins/reverseImageSearch.tsx
@@ -29,7 +29,7 @@ const Engines = {
TinEye: "https://www.tineye.com/search?url="
};
-const Menu = lazyWebpack(filters.byProps(["MenuItem"]));
+const Menu = lazyWebpack(filters.byProps("MenuItem"));
export default definePlugin({
diff --git a/src/plugins/sendify.ts b/src/plugins/sendify.ts
index 436a928..40836ad 100644
--- a/src/plugins/sendify.ts
+++ b/src/plugins/sendify.ts
@@ -53,9 +53,9 @@ interface Track {
name: string;
}
-const Spotify = lazyWebpack(filters.byProps(["getPlayerState"]));
-const MessageCreator = lazyWebpack(filters.byProps(["getSendMessageOptionsForReply", "sendMessage"]));
-const PendingReplyStore = lazyWebpack(filters.byProps(["getPendingReply"]));
+const Spotify = lazyWebpack(filters.byProps("getPlayerState"));
+const MessageCreator = lazyWebpack(filters.byProps("getSendMessageOptionsForReply", "sendMessage"));
+const PendingReplyStore = lazyWebpack(filters.byProps("getPendingReply"));
function sendMessage(channelId, message) {
message = {
diff --git a/src/utils/logger.ts b/src/utils/logger.ts
index 24cd2c8..88ebb43 100644
--- a/src/utils/logger.ts
+++ b/src/utils/logger.ts
@@ -29,7 +29,7 @@ export default class Logger {
return ["%c %c %s ", "", `background: ${color}; color: black; font-weight: bold; border-radius: 5px;`, title];
}
- constructor(public name: string, public color: string) { }
+ constructor(public name: string, public color: string = "white") { }
private _log(level: "log" | "error" | "warn" | "info" | "debug", levelColor: string, args: any[], customFmt = "") {
console[level](
diff --git a/src/webpack/common.tsx b/src/webpack/common.tsx
index f5b2401..4c59102 100644
--- a/src/webpack/common.tsx
+++ b/src/webpack/common.tsx
@@ -23,7 +23,7 @@ import type Stores from "discord-types/stores";
import { lazyWebpack } from "../utils/misc";
import { _resolveReady, filters, mapMangledModuleLazy, waitFor } from "./webpack";
-export const Margins = lazyWebpack(filters.byProps(["marginTop20"]));
+export const Margins = lazyWebpack(filters.byProps("marginTop20"));
export let FluxDispatcher: Other.FluxDispatcher;
export let React: typeof import("react");
diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts
index 5596730..b3cfd70 100644
--- a/src/webpack/patchWebpack.ts
+++ b/src/webpack/patchWebpack.ts
@@ -102,7 +102,7 @@ function patchPush() {
callback(exports.default);
}
- for (const nested in exports) if (nested.length < 3) {
+ for (const nested in exports) if (nested.length <= 3) {
if (exports[nested] && filter(exports[nested])) {
subscriptions.delete(filter);
callback(exports[nested]);
diff --git a/src/webpack/webpack.ts b/src/webpack/webpack.ts
index 7604266..3db4dd2 100644
--- a/src/webpack/webpack.ts
+++ b/src/webpack/webpack.ts
@@ -18,6 +18,7 @@
import type { WebpackInstance } from "discord-types/other";
+import Logger from "../utils/logger";
import { proxyLazy } from "../utils/proxyLazy";
export let _resolveReady: () => void;
@@ -33,11 +34,13 @@ export let cache: WebpackInstance["c"];
export type FilterFn = (mod: any) => boolean;
export const filters = {
- byProps: (props: string[]): FilterFn =>
+ byProps: (...props: string[]): FilterFn =>
props.length === 1
? m => m[props[0]] !== void 0
: m => props.every(p => m[p] !== void 0),
+
byDisplayName: (deezNuts: string): FilterFn => m => m.default?.displayName === deezNuts,
+
byCode: (...code: string[]): FilterFn => m => {
if (typeof m !== "function") return false;
const s = Function.prototype.toString.call(m);
@@ -48,6 +51,7 @@ export const filters = {
},
};
+const logger = new Logger("Webpack");
export const subscriptions = new Map<FilterFn, CallbackFn>();
export const listeners = new Set<CallbackFn>();
@@ -56,12 +60,12 @@ export type CallbackFn = (mod: any) => void;
export function _initWebpack(instance: typeof window.webpackChunkdiscord_app) {
if (cache !== void 0) throw "no.";
- wreq = instance.push([[Symbol()], {}, r => r]);
+ wreq = instance.push([[Symbol("Vencord")], {}, r => r]);
cache = wreq.c;
instance.pop();
}
-export function find(filter: FilterFn, getDefault = true) {
+export function find(filter: FilterFn, getDefault = true, isWaitFor = false) {
if (typeof filter !== "function")
throw new Error("Invalid filter. Expected a function got " + typeof filter);
@@ -77,7 +81,6 @@ export function find(filter: FilterFn, getDefault = true) {
if (mod.exports.default && filter(mod.exports.default))
return getDefault ? mod.exports.default : mod.exports;
- // is 3 is the longest obfuscated export?
// the length check makes search about 20% faster
for (const nestedMod in mod.exports) if (nestedMod.length <= 3) {
const nested = mod.exports[nestedMod];
@@ -85,11 +88,21 @@ export function find(filter: FilterFn, getDefault = true) {
}
}
+ if (!isWaitFor) {
+ const err = new Error("Didn't find module matching this filter");
+ if (IS_DEV) {
+ // Strict behaviour in DevBuilds to fail early and make sure the issue is found
+ throw err;
+ }
+ logger.warn(err);
+ }
+
return null;
}
export function findAll(filter: FilterFn, getDefault = true) {
- if (typeof filter !== "function") throw new Error("Invalid filter. Expected a function got " + typeof filter);
+ if (typeof filter !== "function")
+ throw new Error("Invalid filter. Expected a function got " + typeof filter);
const ret = [] as any[];
for (const key in cache) {
@@ -113,17 +126,17 @@ export function findAll(filter: FilterFn, getDefault = true) {
}
/**
- * Finds a mangled module by the provided code "code" (must be unique and can be anywhere in the module)
- * then maps it into an easily usable module via the specified mappers
- * @param code Code snippet
- * @param mappers Mappers to create the non mangled exports
- * @returns Unmangled exports as specified in mappers
- *
- * @example mapMangledModule("headerIdIsManaged:", {
- * openModal: filters.byCode("headerIdIsManaged:"),
- * closeModal: filters.byCode("key==")
- * })
- */
+ * Finds a mangled module by the provided code "code" (must be unique and can be anywhere in the module)
+ * then maps it into an easily usable module via the specified mappers
+ * @param code Code snippet
+ * @param mappers Mappers to create the non mangled exports
+ * @returns Unmangled exports as specified in mappers
+ *
+ * @example mapMangledModule("headerIdIsManaged:", {
+ * openModal: filters.byCode("headerIdIsManaged:"),
+ * closeModal: filters.byCode("key==")
+ * })
+ */
export function mapMangledModule<S extends string>(code: string, mappers: Record<S, FilterFn>): Record<S, any> {
const exports = {} as Record<S, any>;
@@ -143,26 +156,31 @@ export function mapMangledModule<S extends string>(code: string, mappers: Record
}
}
}
- break;
+ return exports;
}
}
+ const err = new Error("Didn't find module matching this code:\n" + code);
+ if (IS_DEV)
+ throw err;
+
+ logger.warn(err);
return exports;
}
/**
- * Same as {@link mapMangledModule} but lazy
- */
+ * Same as {@link mapMangledModule} but lazy
+ */
export function mapMangledModuleLazy<S extends string>(code: string, mappers: Record<S, FilterFn>): Record<S, any> {
return proxyLazy(() => mapMangledModule(code, mappers));
}
export function findByProps(...props: string[]) {
- return find(filters.byProps(props));
+ return find(filters.byProps(...props));
}
export function findAllByProps(...props: string[]) {
- return findAll(filters.byProps(props));
+ return findAll(filters.byProps(...props));
}
export function findByDisplayName(deezNuts: string) {
@@ -170,11 +188,14 @@ export function findByDisplayName(deezNuts: string) {
}
export function waitFor(filter: string | string[] | FilterFn, callback: CallbackFn) {
- if (typeof filter === "string") filter = filters.byProps([filter]);
- else if (Array.isArray(filter)) filter = filters.byProps(filter);
- else if (typeof filter !== "function") throw new Error("filter must be a string, string[] or function, got " + typeof filter);
-
- const existing = find(filter!);
+ if (typeof filter === "string")
+ filter = filters.byProps(filter);
+ else if (Array.isArray(filter))
+ filter = filters.byProps(...filter);
+ else if (typeof filter !== "function")
+ throw new Error("filter must be a string, string[] or function, got " + typeof filter);
+
+ const existing = find(filter!, true, true);
if (existing) return void callback(existing);
subscriptions.set(filter, callback);
@@ -189,11 +210,11 @@ export function removeListener(callback: CallbackFn) {
}
/**
- * Search modules by keyword. This searches the factory methods,
- * meaning you can search all sorts of things, displayName, methodName, strings somewhere in the code, etc
- * @param filters One or more strings or regexes
- * @returns Mapping of found modules
- */
+ * Search modules by keyword. This searches the factory methods,
+ * meaning you can search all sorts of things, displayName, methodName, strings somewhere in the code, etc
+ * @param filters One or more strings or regexes
+ * @returns Mapping of found modules
+ */
export function search(...filters: Array<string | RegExp>) {
const results = {} as Record<number, Function>;
const factories = wreq.m;
@@ -212,13 +233,13 @@ export function search(...filters: Array<string | RegExp>) {
}
/**
- * Extract a specific module by id into its own Source File. This has no effect on
- * the code, it is only useful to be able to look at a specific module without having
- * to view a massive file. extract then returns the extracted module so you can jump to it.
- * As mentioned above, note that this extracted module is not actually used,
- * so putting breakpoints or similar will have no effect.
- * @param id The id of the module to extract
- */
+ * Extract a specific module by id into its own Source File. This has no effect on
+ * the code, it is only useful to be able to look at a specific module without having
+ * to view a massive file. extract then returns the extracted module so you can jump to it.
+ * As mentioned above, note that this extracted module is not actually used,
+ * so putting breakpoints or similar will have no effect.
+ * @param id The id of the module to extract
+ */
export function extract(id: number) {
const mod = wreq.m[id] as Function;
if (!mod) return null;