diff --git a/src/patcher.ts b/src/patcher.ts index c25505a2..4f724cbb 100644 --- a/src/patcher.ts +++ b/src/patcher.ts @@ -23,6 +23,7 @@ import { dirname, join } from "path"; import { initIpc } from "./ipcMain"; import { installExt } from "./ipcMain/extensions"; import { readSettings } from "./ipcMain/index"; +import { onceDefined } from "./utils/onceDefined"; console.log("[Vencord] Starting up..."); @@ -74,15 +75,9 @@ require.cache[electronPath]!.exports = { }; // Patch appSettings to force enable devtools -Object.defineProperty(global, "appSettings", { - set: (v: typeof global.appSettings) => { - v.set("DANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOING", true); - // @ts-ignore - delete global.appSettings; - global.appSettings = v; - }, - configurable: true -}); +onceDefined(global, "appSettings", s => + s.set("DANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOING", true) +); process.env.DATA_DIR = join(app.getPath("userData"), "..", "Vencord"); diff --git a/src/utils/index.ts b/src/utils/index.ts index d818e886..22504ce2 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -24,4 +24,6 @@ export { default as IpcEvents } from "./IpcEvents"; export { default as Logger } from "./logger"; export * from "./misc"; export * as Modals from "./modal"; +export * from "./onceDefined"; export * from "./proxyLazy"; +export * from "./Queue"; diff --git a/src/utils/onceDefined.ts b/src/utils/onceDefined.ts new file mode 100644 index 00000000..4ee8fa65 --- /dev/null +++ b/src/utils/onceDefined.ts @@ -0,0 +1,47 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2022 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import type { LiteralUnion } from "type-fest"; + +/** + * Wait for a property to be defined on the target, then call the callback with + * the value + * @param target Object + * @param property Property to be defined + * @param callback Callback + * + * @example onceDefined(window, "webpackChunkdiscord_app", wpInstance => wpInstance.push(...)); + */ +export function onceDefined>( + target: T, property: P, callback: (v: P extends keyof T ? T[P] : any) => void +): void { + const propertyAsAny = property as any; + + if (property in target) + return void callback(target[propertyAsAny]); + + Object.defineProperty(target, property, { + set(v) { + delete target[propertyAsAny]; + target[propertyAsAny] = v; + callback(v); + }, + configurable: true, + enumerable: false + }); +} diff --git a/src/webpack/webpack.ts b/src/webpack/webpack.ts index ba2d5591..4f78f738 100644 --- a/src/webpack/webpack.ts +++ b/src/webpack/webpack.ts @@ -66,6 +66,14 @@ export function _initWebpack(instance: typeof window.webpackChunkdiscord_app) { instance.pop(); } +if (IS_DEV && !IS_WEB) { + var devToolsOpen = false; + // At this point in time, DiscordNative has not been exposed yet, so setImmediate is needed + setTimeout(() => { + DiscordNative/* just to make sure */?.window.setDevtoolsCallbacks(() => devToolsOpen = true, () => devToolsOpen = false); + }, 0); +} + export function find(filter: FilterFn, getDefault = true, isWaitFor = false) { if (typeof filter !== "function") throw new Error("Invalid filter. Expected a function got " + typeof filter); @@ -92,10 +100,12 @@ export function find(filter: FilterFn, getDefault = true, isWaitFor = false) { 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; + if (!devToolsOpen) + // Strict behaviour in DevBuilds to fail early and make sure the issue is found + throw err; + } else { + logger.warn(err); } - logger.warn(err); } return null; @@ -196,10 +206,12 @@ export function bulk(...filterFns: FilterFn[]) { if (found !== length) { const err = new Error(`Got ${length} filters, but only found ${found} modules!`); if (IS_DEV) { - // Strict behaviour in DevBuilds to fail early and make sure the issue is found - throw err; + if (!devToolsOpen) + // Strict behaviour in DevBuilds to fail early and make sure the issue is found + throw err; + } else { + logger.warn(err); } - logger.warn(err); } return results; @@ -219,10 +231,12 @@ export function findModuleId(code: string) { const err = new Error("Didn't find module with code:\n" + code); if (IS_DEV) { - // Strict behaviour in DevBuilds to fail early and make sure the issue is found - throw err; + if (!devToolsOpen) + // Strict behaviour in DevBuilds to fail early and make sure the issue is found + throw err; + } else { + logger.warn(err); } - logger.warn(err); return null; }