From 987506822860a945ae89605b480bd7cd21260580 Mon Sep 17 00:00:00 2001 From: Strencher <46447572+Strencher@users.noreply.github.com> Date: Thu, 29 Dec 2022 23:27:52 +0100 Subject: [PATCH 01/14] Add webpack aliases. --- renderer/src/modules/api/webpack.js | 106 ++++++++++++++++++++++++- renderer/src/modules/webpackmodules.js | 39 ++++++++- 2 files changed, 143 insertions(+), 2 deletions(-) diff --git a/renderer/src/modules/api/webpack.js b/renderer/src/modules/api/webpack.js index 6abf86f1..cc553f30 100644 --- a/renderer/src/modules/api/webpack.js +++ b/renderer/src/modules/api/webpack.js @@ -9,6 +9,10 @@ import WebpackModules, {Filters} from "../webpackmodules"; * @name Webpack */ const Webpack = { + /** + * A Proxy that returns the module source by ID. + */ + modules: WebpackModules.modules, /** * Series of {@link Filters} to be used for finding webpack modules. @@ -60,6 +64,22 @@ const Webpack = { combine(...filters) {return Filters.combine(...filters);}, }, + /** + * Searches for a module by value, returns module & matched key. Useful in combination with the Patcher. + * @param {(value: any, index: number, array: any[]) => boolean} filter A function to use to filter the module + * @param {object} [options] Set of options to customize the search + * @param {any} [options.target=null] Optional module target to look inside. + * @param {Boolean} [options.defaultExport=true] Whether to return default export when matching the default export + * @param {Boolean} [options.searchExports=false] Whether to execute the filter on webpack export getters. + * @return {[Any, string]} + */ + getMangled(filter, options = {}) { + if (("first" in options)) return Logger.error("BdApi.Webpack~getModule", "Unsupported option first."); + if (("defaultExport" in options) && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected."); + if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); + return WebpackModules.getMangled(filter, options); + }, + /** * Finds a module using a filter function. * @memberof Webpack @@ -105,9 +125,93 @@ const Webpack = { if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); return WebpackModules.getLazy(filter, options); }, + + /** + * Finds all modules matching a filter function. + * @param {Function} filter A function to use to filter modules + */ + getModules(filter) {return WebpackModules.getModule(filter, {first: false});}, + + /** + * Finds a module using its code. + * @param {RegEx} regex A regular expression to use to filter modules + * @param {object} [options] Options to configure the search + * @param {Boolean} [options.defaultExport=true] Whether to return default export when matching the default export + * @param {Boolean} [options.searchExports=false] Whether to execute the filter on webpack exports + * @return {Any} + */ + getByRegex(regex, options = {}) { + return WebpackModules.getModule(Filters.byRegex(regex), options); + }, + + /** + * Finds akk modules using its code. + * @param {RegEx} regex A regular expression to use to filter modules + * @param {object} [options] Options to configure the search + * @param {Boolean} [options.defaultExport=true] Whether to return default export when matching the default export + * @param {Boolean} [options.searchExports=false] Whether to execute the filter on webpack exports + * @return {Any[]} + */ + getAllByRegex(regex, options = {}) { + return WebpackModules.getModule(Filters.byRegex(regex), options); + }, + + /** + * Finds a single module using properties on its prototype. + * @param {...string} prototypes Properties to use to filter modules + * @return {Any} + */ + getByPrototypes(...prototypes) { + return WebpackModules.getModule(Filters.byPrototypeFields(prototypes)); + }, + + /** + * Finds all modules with a set of properties of its prototype. + * @param {...string} prototypes Properties to use to filter modules + * @return {Any[]} + */ + getAllByPrototypes(...prototypes) { + return WebpackModules.getModule(Filters.byPrototypeFields(prototypes), {first: false}); + }, + + /** + * Finds a single module using its own properties. + * @param {...string} props Properties to use to filter modules + * @return {Any} + */ + getByProps(...props) { + return WebpackModules.getModule(Filters.byProps(props)); + }, + + /** + * Finds all modules with a set of properties. + * @param {...string} props Properties to use to filter modules + * @return {Any[]} + */ + getAllByProps(...props) { + return WebpackModules.getModule(Filters.byProps(props), {first: false}); + }, + + /** + * Finds a single module using a set of strings. + * @param {...String} props Strings to use to filter modules + * @return {Any} + */ + getByString(...strings) { + return WebpackModules.getModule(Filters.byStrings(...strings)); + }, + + /** + * Finds all modules with a set of strings. + * @param {...String} strings Strings to use to filter modules + * @return {Any[]} + */ + getAllByString(...strings) { + return WebpackModules.getModule(Filters.byStrings(...strings), {first: false}); + }, }; Object.freeze(Webpack); Object.freeze(Webpack.Filters); -export default Webpack; \ No newline at end of file +export default Webpack; diff --git a/renderer/src/modules/webpackmodules.js b/renderer/src/modules/webpackmodules.js index 96be30b6..b656aa56 100644 --- a/renderer/src/modules/webpackmodules.js +++ b/renderer/src/modules/webpackmodules.js @@ -140,6 +140,25 @@ export default class WebpackModules { static findByUniqueProperties(props, first = true) {return first ? this.getByProps(...props) : this.getAllByProps(...props);} static findByDisplayName(name) {return this.getByDisplayName(name);} + /** + * A Proxy that returns the module source by ID. + */ + static modules = new Proxy({}, { + ownKeys() {return Object.keys(WebpackModules.require.m);}, + getOwnPropertyDescriptor() { + return { + enumerable: true, + configurable: true, // Not actually + }; + }, + get(_, k) { + return WebpackModules.require.m[k]; + }, + set() { + throw new Error("[WebpackModules~modules] Setting modules is not allowed."); + } + }); + /** * Finds a module using a filter function. * @param {function} filter A function to use to filter modules @@ -247,6 +266,24 @@ export default class WebpackModules { return returnedModules; } + /** + * Searches for a module by value, returns module & matched key. Useful in combination with the Patcher. + * @param {(value: any, index: number, array: any[]) => boolean} filter A function to use to filter the module + * @param {object} [options] Set of options to customize the search + * @param {any} [options.target=null] Optional module target to look inside. + * @param {Boolean} [options.defaultExport=true] Whether to return default export when matching the default export + * @param {Boolean} [options.searchExports=false] Whether to execute the filter on webpack export getters. + * @return {[Any, string]} + */ + static *getMangled(filter, {target = null, ...rest} = {}) { + yield target ??= this.getModule(exports => + Object.values(exports).some(filter), + rest + ); + + yield target && Object.keys(target).find(k => filter(target[k])); + } + /** * Finds all modules matching a filter function. * @param {Function} filter A function to use to filter modules @@ -481,4 +518,4 @@ export default class WebpackModules { } } -WebpackModules.initialize(); \ No newline at end of file +WebpackModules.initialize(); From 97138afb7de7e08fa4d9bb7bcb2ee21b1facb93d Mon Sep 17 00:00:00 2001 From: Strencher <46447572+Strencher@users.noreply.github.com> Date: Sat, 31 Dec 2022 17:44:01 +0100 Subject: [PATCH 02/14] Fix typo & options --- renderer/src/modules/api/webpack.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/renderer/src/modules/api/webpack.js b/renderer/src/modules/api/webpack.js index cc553f30..7d651cb0 100644 --- a/renderer/src/modules/api/webpack.js +++ b/renderer/src/modules/api/webpack.js @@ -145,7 +145,7 @@ const Webpack = { }, /** - * Finds akk modules using its code. + * Finds all modules using its code. * @param {RegEx} regex A regular expression to use to filter modules * @param {object} [options] Options to configure the search * @param {Boolean} [options.defaultExport=true] Whether to return default export when matching the default export @@ -153,7 +153,7 @@ const Webpack = { * @return {Any[]} */ getAllByRegex(regex, options = {}) { - return WebpackModules.getModule(Filters.byRegex(regex), options); + return WebpackModules.getModule(Filters.byRegex(regex), Object.assign({}, options, {first: true})); }, /** From 68c6b81ed717b7859bdde2cf184d6b8f3aa20663 Mon Sep 17 00:00:00 2001 From: Strencher <46447572+Strencher@users.noreply.github.com> Date: Thu, 26 Jan 2023 00:00:16 +0100 Subject: [PATCH 03/14] Implement options for - getByProps() methods - getByPrototypes() methods - getByString() methods --- renderer/src/modules/api/webpack.js | 36 ++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/renderer/src/modules/api/webpack.js b/renderer/src/modules/api/webpack.js index 7d651cb0..81bbdb57 100644 --- a/renderer/src/modules/api/webpack.js +++ b/renderer/src/modules/api/webpack.js @@ -1,6 +1,18 @@ import Logger from "common/logger"; import WebpackModules, {Filters} from "../webpackmodules"; +const getOptions = (args, defaultOptions = {}) => { + if (args.length > 1 && + typeof(args[args.length - 1]) === "object" && + !Array.isArray(args[args.length - 1]) && + args[args.length - 1] !== null + ) { + Object.assign(defaultOptions, args.pop()); + } + + return defaultOptions; +}; + /** * `Webpack` is a utility class for getting internal webpack modules. Instance is accessible through the {@link BdApi}. * This is extremely useful for interacting with the internals of Discord. @@ -162,7 +174,9 @@ const Webpack = { * @return {Any} */ getByPrototypes(...prototypes) { - return WebpackModules.getModule(Filters.byPrototypeFields(prototypes)); + const options = getOptions(prototypes); + + return WebpackModules.getModule(Filters.byPrototypeFields(prototypes), options); }, /** @@ -171,7 +185,9 @@ const Webpack = { * @return {Any[]} */ getAllByPrototypes(...prototypes) { - return WebpackModules.getModule(Filters.byPrototypeFields(prototypes), {first: false}); + const options = getOptions(prototypes, {first: false}); + + return WebpackModules.getModule(Filters.byPrototypeFields(prototypes), options); }, /** @@ -180,7 +196,9 @@ const Webpack = { * @return {Any} */ getByProps(...props) { - return WebpackModules.getModule(Filters.byProps(props)); + const options = getOptions(props); + + return this.getModule(Filters.byProps(props), options); }, /** @@ -189,7 +207,9 @@ const Webpack = { * @return {Any[]} */ getAllByProps(...props) { - return WebpackModules.getModule(Filters.byProps(props), {first: false}); + const options = getOptions(props, {first: false}); + + return WebpackModules.getModule(Filters.byProps(props), options); }, /** @@ -198,7 +218,9 @@ const Webpack = { * @return {Any} */ getByString(...strings) { - return WebpackModules.getModule(Filters.byStrings(...strings)); + const options = getOptions(strings); + + return WebpackModules.getModule(Filters.byStrings(...strings), options); }, /** @@ -207,7 +229,9 @@ const Webpack = { * @return {Any[]} */ getAllByString(...strings) { - return WebpackModules.getModule(Filters.byStrings(...strings), {first: false}); + const options = getOptions(strings, {first: false}); + + return WebpackModules.getModule(Filters.byStrings(...strings), options); }, }; From 1f48d22e53ddb82ac9e3e5db021c2f7755489bef Mon Sep 17 00:00:00 2001 From: Strencher <46447572+Strencher@users.noreply.github.com> Date: Wed, 12 Apr 2023 23:20:20 +0200 Subject: [PATCH 04/14] fetch api & apply fix current https --- preload/src/api/fetch.js | 88 +++++++++++++++++++++++++++++++ preload/src/api/https.js | 10 +++- preload/src/api/index.js | 1 + renderer/src/modules/api/fetch.js | 63 ++++++++++++++++++++++ renderer/src/modules/api/index.js | 4 ++ 5 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 preload/src/api/fetch.js create mode 100644 renderer/src/modules/api/fetch.js diff --git a/preload/src/api/fetch.js b/preload/src/api/fetch.js new file mode 100644 index 00000000..f423b1df --- /dev/null +++ b/preload/src/api/fetch.js @@ -0,0 +1,88 @@ +import * as https from "https"; +import * as http from "http"; + +const redirectCodes = new Set([301, 302, 307, 308]); + +export function nativeFetch(url, options) { + let state = "PENDING"; + const data = {content: [], headers: null, statusCode: null, url: url, statusText: "", redirected: false}; + const listeners = new Set(); + const errors = new Set(); + + /** * @param {URL} url */ + const execute = (url, options, redirect = false) => { + const Module = url.protocol === "http" ? http : https; + + const req = Module.request(url.href, { + headers: options.headers ?? {}, + method: options.method ?? "GET" + }, res => { + if (redirectCodes.has(res.statusCode) && res.headers.location && options.redirect !== "manual") { + const final = new URL(res.headers.location); + + for (const [key, value] of new URL(url).searchParams.entries()) { + final.searchParams.set(key, value); + } + + return execute(final, options, true); + } + + res.on("data", chunk => data.content.push(chunk)); + res.on("end", () => { + data.content = Buffer.concat(data.content); + data.headers = res.headers; + data.statusCode = res.statusCode; + data.url = url.toString(); + data.statusText = res.statusMessage; + data.redirected = redirect; + state = "DONE"; + + listeners.forEach(listener => listener()); + }); + res.on("error", error => { + state = "ABORTED"; + errors.forEach(e => e(error)); + }); + }); + + if (options.body) { + try {req.write(options.body)} + catch (error) { + state = "ABORTED"; + errors.forEach(e => e(error)); + } finally { + req.end(); + } + } else { + req.end(); + } + + if (options.signal) { + options.signal.addEventListener("abort", () => { + req.end(); + state = "ABORTED"; + }); + } + }; + + execute(new URL(url), options); + + return { + onComplete(listener) { + listeners.add(listener); + }, + onError(listener) { + errors.add(listener); + }, + readData() { + switch (state) { + case "PENDING": + throw new Error("Cannot read data before request is done!"); + case "ABORTED": + throw new Error("Request was aborted."); + case "DONE": + return data; + } + } + }; +} diff --git a/preload/src/api/https.js b/preload/src/api/https.js index dae2ac0f..a65ede15 100644 --- a/preload/src/api/https.js +++ b/preload/src/api/https.js @@ -34,7 +34,15 @@ const makeRequest = (url, options, callback, setReq) => { req.end(); }); }); - req.end(); + + if (options.formData) { + // Make sure to close the socket. + try {req.write(options.formData);} + finally {req.end();} + } else { + req.end(); + } + }; const request = function (url, options, callback) { diff --git a/preload/src/api/index.js b/preload/src/api/index.js index 2d097c76..7907775f 100644 --- a/preload/src/api/index.js +++ b/preload/src/api/index.js @@ -3,6 +3,7 @@ export {default as https} from "./https"; export * as electron from "./electron"; export * as crypto from "./crypto"; export * as vm from "./vm"; +export * from "./fetch"; // We can expose that without any issues. export * as path from "path"; diff --git a/renderer/src/modules/api/fetch.js b/renderer/src/modules/api/fetch.js new file mode 100644 index 00000000..e9a3efb5 --- /dev/null +++ b/renderer/src/modules/api/fetch.js @@ -0,0 +1,63 @@ +import Remote from "../../polyfill/remote"; + +class FetchResponse extends Response { + constructor(options) { + super(options.content, { + headers: new Headers(options.headers), + method: options.method ?? "GET", + body: options.content, + ...options + }); + + this._options = options; + } + + get url() {return this._options.url;} + get redirected() {return this._options.redirected;} +} + +const convertSignal = signal => { + const listeners = new Set(); + + signal.addEventListener("abort", () => { + listeners.forEach(l => l()); + }); + + return { + addEventListener(_, listener) { + listeners.add(listener); + } + }; +}; + +export function fetch(url, options = {}) { + return new Promise((resolve, reject) => { + const ctx = Remote.nativeFetch(url, { + ...(options.headers && {headers: options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers}), + ...(options.body && {body: options.body}), + ...(options.method && {method: options.method}), + ...(options.signal && {signal: convertSignal(options.signal)}) + }); + + ctx.onError(error => { + reject(error); + }); + + ctx.onComplete(() => { + try { + const data = ctx.readData(); + + const req = new FetchResponse({ + method: options.method ?? "GET", + status: data.statusCode, + ...options, + ...data + }); + + resolve(req); + } catch (error) { + reject(error); + } + }); + }); +} diff --git a/renderer/src/modules/api/index.js b/renderer/src/modules/api/index.js index 7f56b7c6..cab1f18f 100644 --- a/renderer/src/modules/api/index.js +++ b/renderer/src/modules/api/index.js @@ -12,6 +12,7 @@ import Utils from "./utils"; import Webpack from "./webpack"; import * as Legacy from "./legacy"; import ContextMenu from "./contextmenu"; +import {fetch} from "./fetch"; import {DiscordModules} from "modules"; const bounded = new Map(); @@ -57,6 +58,7 @@ export default class BdApi { Components = { get Tooltip() {return DiscordModules.Tooltip;} } + fetch = fetch; } // Add legacy functions @@ -126,6 +128,8 @@ BdApi.Components = { get Tooltip() {return DiscordModules.Tooltip;} }; +BdApi.fetch = fetch; + Object.freeze(BdApi); Object.freeze(BdApi.prototype); Object.freeze(BdApi.Components); From bc6a0632de88a3ec90be465dce164f6e21c816bc Mon Sep 17 00:00:00 2001 From: Strencher <46447572+Strencher@users.noreply.github.com> Date: Mon, 1 May 2023 21:36:56 +0200 Subject: [PATCH 05/14] Code cleanup, deprecation notice, add maxRedirects --- preload/src/api/fetch.js | 56 +++++++++++++++++++++++++++---- renderer/src/modules/api/fetch.js | 36 ++++++++++++++++---- renderer/src/modules/api/index.js | 7 ++-- renderer/src/polyfill/index.js | 12 ++++++- 4 files changed, 93 insertions(+), 18 deletions(-) diff --git a/preload/src/api/fetch.js b/preload/src/api/fetch.js index f423b1df..b9f105f6 100644 --- a/preload/src/api/fetch.js +++ b/preload/src/api/fetch.js @@ -1,8 +1,23 @@ import * as https from "https"; import * as http from "http"; +const MAX_DEFAULT_REDIRECTS = 20; const redirectCodes = new Set([301, 302, 307, 308]); +/** + * @typedef {Object} FetchOptions + * @property {"GET" | "PUT" | "POST" | "DELETE"} [method] - Request method. + * @property {Record} [headers] - Request headers. + * @property {"manual" | "follow"} [redirect] - Whether to follow redirects. + * @property {number} [maxRedirects] - Maximum amount of redirects to be followed. + * @property {AbortSignal} [signal] - Signal to abruptly cancel the request + * @property {Uint8Array | string} [body] - Defines a request body. Data must be serializable. + */ + +/** + * @param {string} url + * @param {FetchOptions} options + */ export function nativeFetch(url, options) { let state = "PENDING"; const data = {content: [], headers: null, statusCode: null, url: url, statusText: "", redirected: false}; @@ -10,7 +25,7 @@ export function nativeFetch(url, options) { const errors = new Set(); /** * @param {URL} url */ - const execute = (url, options, redirect = false) => { + const execute = (url, options, redirectCount = 0) => { const Module = url.protocol === "http" ? http : https; const req = Module.request(url.href, { @@ -18,13 +33,31 @@ export function nativeFetch(url, options) { method: options.method ?? "GET" }, res => { if (redirectCodes.has(res.statusCode) && res.headers.location && options.redirect !== "manual") { - const final = new URL(res.headers.location); + redirectCount++; + + if (redirectCount >= (options.maxRedirects ?? MAX_DEFAULT_REDIRECTS)) { + state = "ABORTED"; + const error = new Error(`Maximum amount of redirects reached (${options.maxRedirects ?? MAX_DEFAULT_REDIRECTS})`); + errors.forEach(e => e(error)); + + return; + } + + let final; + try { + final = new URL(res.headers.location); + } + catch (error) { + state = "ABORTED"; + errors.forEach(e => e(error)); + return; + } for (const [key, value] of new URL(url).searchParams.entries()) { final.searchParams.set(key, value); } - return execute(final, options, true); + return execute(final, options, redirectCount); } res.on("data", chunk => data.content.push(chunk)); @@ -34,7 +67,7 @@ export function nativeFetch(url, options) { data.statusCode = res.statusCode; data.url = url.toString(); data.statusText = res.statusMessage; - data.redirected = redirect; + data.redirected = redirectCount > 0; state = "DONE"; listeners.forEach(listener => listener()); @@ -50,10 +83,12 @@ export function nativeFetch(url, options) { catch (error) { state = "ABORTED"; errors.forEach(e => e(error)); - } finally { + } + finally { req.end(); } - } else { + } + else { req.end(); } @@ -65,7 +100,14 @@ export function nativeFetch(url, options) { } }; - execute(new URL(url), options); + try { + const parsed = new URL(url); + execute(parsed, options); + } + catch (error) { + state = "ABORTED"; + errors.forEach(e => e(error)); + } return { onComplete(listener) { diff --git a/renderer/src/modules/api/fetch.js b/renderer/src/modules/api/fetch.js index e9a3efb5..1d541395 100644 --- a/renderer/src/modules/api/fetch.js +++ b/renderer/src/modules/api/fetch.js @@ -1,5 +1,7 @@ import Remote from "../../polyfill/remote"; +const methods = new Set(["GET" | "PUT" | "POST" | "DELETE"]); + class FetchResponse extends Response { constructor(options) { super(options.content, { @@ -30,14 +32,34 @@ const convertSignal = signal => { }; }; -export function fetch(url, options = {}) { +/** + * @typedef {Object} FetchOptions + * @property {"GET" | "PUT" | "POST" | "DELETE"} [method] - Request method. + * @property {Record} [headers] - Request headers. + * @property {"manual" | "follow"} [redirect] - Whether to follow redirects. + * @property {number} [maxRedirects] - Maximum amount of redirects to be followed. + * @property {AbortSignal} [signal] - Signal to abruptly cancel the request + * @property {Uint8Array | string} [body] - Defines a request body. Data must be serializable. + */ + +/** + * @param {string} url + * @param {FetchOptions} options + * @returns {Promise} + */ +export default function fetch(url, options = {}) { return new Promise((resolve, reject) => { - const ctx = Remote.nativeFetch(url, { - ...(options.headers && {headers: options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers}), - ...(options.body && {body: options.body}), - ...(options.method && {method: options.method}), - ...(options.signal && {signal: convertSignal(options.signal)}) - }); + const data = {}; + + if (typeof options.headers === "object") { + data.headers = options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers; + } + + if (typeof options.body === "string" || options.body instanceof Uint8Array) data.body = options.body; + if (typeof options.method === "string" && methods.has(options.method)) data.method = options.method; + if (options.signal instanceof AbortSignal) data.signal = convertSignal(options.signal); + + const ctx = Remote.nativeFetch(url, data); ctx.onError(error => { reject(error); diff --git a/renderer/src/modules/api/index.js b/renderer/src/modules/api/index.js index cab1f18f..a30dba41 100644 --- a/renderer/src/modules/api/index.js +++ b/renderer/src/modules/api/index.js @@ -12,7 +12,7 @@ import Utils from "./utils"; import Webpack from "./webpack"; import * as Legacy from "./legacy"; import ContextMenu from "./contextmenu"; -import {fetch} from "./fetch"; +import fetch from "./fetch"; import {DiscordModules} from "modules"; const bounded = new Map(); @@ -58,7 +58,7 @@ export default class BdApi { Components = { get Tooltip() {return DiscordModules.Tooltip;} } - fetch = fetch; + Net = {fetch}; } // Add legacy functions @@ -128,8 +128,9 @@ BdApi.Components = { get Tooltip() {return DiscordModules.Tooltip;} }; -BdApi.fetch = fetch; +BdApi.Net = {fetch}; Object.freeze(BdApi); +Object.freeze(BdApi.Net); Object.freeze(BdApi.prototype); Object.freeze(BdApi.Components); diff --git a/renderer/src/polyfill/index.js b/renderer/src/polyfill/index.js index 72434088..0c375dd2 100644 --- a/renderer/src/polyfill/index.js +++ b/renderer/src/polyfill/index.js @@ -7,6 +7,12 @@ import * as https from "./https"; import Buffer from "./buffer"; import crypto from "./crypto"; import Remote from "./remote"; +import Logger from "common/logger"; + +const deprecated = new Map([ + ["request", "Use BdApi.Net.fetch instead."], + ["https", "Use BdApi.Net.fetch instead."], +]); const originalFs = Object.assign({}, fs); originalFs.writeFileSync = (path, data, options) => fs.writeFileSync(path, data, Object.assign({}, options, {originalFs: true})); @@ -14,6 +20,10 @@ originalFs.writeFile = (path, data, options) => fs.writeFile(path, data, Object. export const createRequire = function (path) { return mod => { + if (deprecated.has(mod)) { + Logger.warn("Remote~Require", `The "${mod}" module is marked as deprecated. ${deprecated.get(mod)}`); + } + switch (mod) { case "request": return request; case "https": return https; @@ -42,4 +52,4 @@ require.resolve = (path) => { } }; -export default require; \ No newline at end of file +export default require; From 8386da0722d08a6fd184a11def5083134f4c1e03 Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Wed, 24 May 2023 14:08:26 -0400 Subject: [PATCH 06/14] Fix fetch methods --- renderer/src/modules/api/fetch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/src/modules/api/fetch.js b/renderer/src/modules/api/fetch.js index 1d541395..7138a15f 100644 --- a/renderer/src/modules/api/fetch.js +++ b/renderer/src/modules/api/fetch.js @@ -1,6 +1,6 @@ import Remote from "../../polyfill/remote"; -const methods = new Set(["GET" | "PUT" | "POST" | "DELETE"]); +const methods = new Set(["GET", "PUT", "POST", "DELETE"]); class FetchResponse extends Response { constructor(options) { From f629f0a851ac9bda0bfc8be7473fac15378595f5 Mon Sep 17 00:00:00 2001 From: Neodymium <68879269+Neodymium7@users.noreply.github.com> Date: Wed, 24 May 2023 11:54:04 -0700 Subject: [PATCH 07/14] Fix window size retention (#1612) --- renderer/src/builtins/window/removeminimumsize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/src/builtins/window/removeminimumsize.js b/renderer/src/builtins/window/removeminimumsize.js index 964a8f0b..a0b6a1f5 100644 --- a/renderer/src/builtins/window/removeminimumsize.js +++ b/renderer/src/builtins/window/removeminimumsize.js @@ -15,7 +15,7 @@ export default new class RemoveMinimumSize extends Builtin { window.addEventListener("resize", this.onResize); const winprefs = DataStore.getData("windowprefs"); - if (!winprefs.height || !winprefs.width) return; // If the values don't exist exit + if (!winprefs.height || !winprefs.width) return DataStore.setData("windowprefs", {}); // If the values don't exist exit and initialize if ((winprefs.height >= DISCORD_MIN_HEIGHT) && (winprefs.width >= DISCORD_MIN_WIDTH)) return; // If both values are normally valid don't touch IPC.setWindowSize(winprefs.width, winprefs.height); } From a369b5a0f982e99d3bd0fdd950c98362cc3d0712 Mon Sep 17 00:00:00 2001 From: benji78 <47087231+benji78@users.noreply.github.com> Date: Wed, 24 May 2023 18:55:21 +0000 Subject: [PATCH 08/14] Closes #1615 (#1616) --- renderer/src/modules/addonmanager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/src/modules/addonmanager.js b/renderer/src/modules/addonmanager.js index f361f116..2c6cbb0d 100644 --- a/renderer/src/modules/addonmanager.js +++ b/renderer/src/modules/addonmanager.js @@ -220,7 +220,7 @@ export default class AddonManager { return error; } - if (shouldToast) Toasts.success(Strings.Addons.wasUnloaded.format({name: addon.name, version: addon.version})); + if (shouldToast) Toasts.success(Strings.Addons.wasLoaded.format({name: addon.name, version: addon.version})); this.emit("loaded", addon); if (!this.state[addon.id]) return this.state[addon.id] = false; From 83c0c81079bf2d08890d5e5baa4d029e8fe3ba0c Mon Sep 17 00:00:00 2001 From: Strencher <46447572+Strencher@users.noreply.github.com> Date: Wed, 24 May 2023 23:00:42 +0200 Subject: [PATCH 09/14] Cleanup & Improvements - Rename `getByProps()` to `getByKeys()` and deprecated *byProps methods & filters. - Fix a couple string errors - Rename `getByPrototypes()` to `getByPrototypeFields()` - Rename `getMangled()` to `getWithKey()` --- renderer/src/modules/api/webpack.js | 44 ++++++++++++++++---------- renderer/src/modules/webpackmodules.js | 8 ++--- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/renderer/src/modules/api/webpack.js b/renderer/src/modules/api/webpack.js index 81bbdb57..801db941 100644 --- a/renderer/src/modules/api/webpack.js +++ b/renderer/src/modules/api/webpack.js @@ -32,12 +32,17 @@ const Webpack = { * @memberof Webpack */ Filters: { + /** + * @deprecated + */ + byProps(...props) {return Filters.byKeys(props);}, + /** * Generates a function that filters by a set of properties. - * @param {...string} props List of property names + * @param {...string} keys List of property names * @returns {function} A filter that checks for a set of properties */ - byProps(...props) {return Filters.byProps(props);}, + byKeys(...keys) {return Filters.byKeys(keys);}, /** * Generates a function that filters by a set of properties on the object's prototype. @@ -85,11 +90,11 @@ const Webpack = { * @param {Boolean} [options.searchExports=false] Whether to execute the filter on webpack export getters. * @return {[Any, string]} */ - getMangled(filter, options = {}) { - if (("first" in options)) return Logger.error("BdApi.Webpack~getModule", "Unsupported option first."); - if (("defaultExport" in options) && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected."); - if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); - return WebpackModules.getMangled(filter, options); + getWithKey(filter, options = {}) { + if (("first" in options)) return Logger.error("BdApi.Webpack~getWithKey", "Unsupported option first."); + if (("defaultExport" in options) && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~getWithKey", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected."); + if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~getWithKey", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); + return WebpackModules.getWithKey(filter, options); }, /** @@ -102,13 +107,18 @@ const Webpack = { * @param {Boolean} [options.searchExports=false] Whether to execute the filter on webpack exports * @return {any} */ - getModule(filter, options = {}) { - if (("first" in options) && typeof(options.first) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.first", options.first, "boolean expected."); - if (("defaultExport" in options) && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected."); - if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); + get(filter, options = {}) { + if (("first" in options) && typeof(options.first) !== "boolean") return Logger.error("BdApi.Webpack~get", "Unsupported type used for options.first", options.first, "boolean expected."); + if (("defaultExport" in options) && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~get", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected."); + if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~get", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); return WebpackModules.getModule(filter, options); }, + /** + * @deprecated + */ + getModule() {return this.get.apply(this, arguments);}, + /** * Finds multiple modules using multiple filters. * @memberof Webpack @@ -134,7 +144,7 @@ const Webpack = { waitForModule(filter, options = {}) { if (("defaultExport" in options) && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~waitForModule", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected."); if (("signal" in options) && !(options.signal instanceof AbortSignal)) return Logger.error("BdApi.Webpack~waitForModule", "Unsupported type used for options.signal", options.signal, "AbortSignal expected."); - if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); + if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~waitForModule", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); return WebpackModules.getLazy(filter, options); }, @@ -184,7 +194,7 @@ const Webpack = { * @param {...string} prototypes Properties to use to filter modules * @return {Any[]} */ - getAllByPrototypes(...prototypes) { + getAllByPrototypeFields(...prototypes) { const options = getOptions(prototypes, {first: false}); return WebpackModules.getModule(Filters.byPrototypeFields(prototypes), options); @@ -195,10 +205,10 @@ const Webpack = { * @param {...string} props Properties to use to filter modules * @return {Any} */ - getByProps(...props) { + getByKeys(...props) { const options = getOptions(props); - return this.getModule(Filters.byProps(props), options); + return WebpackModules.getModule(Filters.byKeys(props), options); }, /** @@ -206,10 +216,10 @@ const Webpack = { * @param {...string} props Properties to use to filter modules * @return {Any[]} */ - getAllByProps(...props) { + getAllByKeys(...props) { const options = getOptions(props, {first: false}); - return WebpackModules.getModule(Filters.byProps(props), options); + return WebpackModules.getModule(Filters.byKeys(props), options); }, /** diff --git a/renderer/src/modules/webpackmodules.js b/renderer/src/modules/webpackmodules.js index b656aa56..f44877b1 100644 --- a/renderer/src/modules/webpackmodules.js +++ b/renderer/src/modules/webpackmodules.js @@ -22,7 +22,7 @@ export class Filters { * @param {module:WebpackModules.Filters~filter} filter - Additional filter * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties */ - static byProps(props, filter = m => m) { + static byKeys(props, filter = m => m) { return module => { if (!module) return false; if (typeof(module) !== "object" && typeof(module) !== "function") return false; @@ -275,7 +275,7 @@ export default class WebpackModules { * @param {Boolean} [options.searchExports=false] Whether to execute the filter on webpack export getters. * @return {[Any, string]} */ - static *getMangled(filter, {target = null, ...rest} = {}) { + static *getWithKey(filter, {target = null, ...rest} = {}) { yield target ??= this.getModule(exports => Object.values(exports).some(filter), rest @@ -333,7 +333,7 @@ export default class WebpackModules { * @return {Any} */ static getByProps(...props) { - return this.getModule(Filters.byProps(props)); + return this.getModule(Filters.byKeys(props)); } /** @@ -342,7 +342,7 @@ export default class WebpackModules { * @return {Any} */ static getAllByProps(...props) { - return this.getModule(Filters.byProps(props), {first: false}); + return this.getModule(Filters.byKeys(props), {first: false}); } /** From 0acc5a6f857168b0aafad1526399df6a2767010b Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Wed, 24 May 2023 18:24:18 -0400 Subject: [PATCH 10/14] Change to prototype keys --- renderer/src/modules/api/webpack.js | 29 +++++++++++++++----------- renderer/src/modules/webpackmodules.js | 6 +++--- renderer/src/ui/settings.js | 2 +- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/renderer/src/modules/api/webpack.js b/renderer/src/modules/api/webpack.js index 801db941..037468a6 100644 --- a/renderer/src/modules/api/webpack.js +++ b/renderer/src/modules/api/webpack.js @@ -44,12 +44,17 @@ const Webpack = { */ byKeys(...keys) {return Filters.byKeys(keys);}, + /** + * @deprecated + */ + byPrototypeFields(...props) {return Filters.byPrototypeKeys(props);}, + /** * Generates a function that filters by a set of properties on the object's prototype. * @param {...string} props List of property names * @returns {function} A filter that checks for a set of properties on the object's prototype. */ - byPrototypeFields(...props) {return Filters.byPrototypeFields(props);}, + byPrototypeKeys(...props) {return Filters.byPrototypeKeys(props);}, /** * Generates a function that filters by a regex. @@ -114,10 +119,16 @@ const Webpack = { return WebpackModules.getModule(filter, options); }, + /** + * Finds all modules matching a filter function. + * @param {Function} filter A function to use to filter modules + */ + getAll(filter) {return WebpackModules.getModule(filter, {first: false});}, + /** * @deprecated */ - getModule() {return this.get.apply(this, arguments);}, + getModule() {return Webpack.get(...arguments);}, /** * Finds multiple modules using multiple filters. @@ -148,12 +159,6 @@ const Webpack = { return WebpackModules.getLazy(filter, options); }, - /** - * Finds all modules matching a filter function. - * @param {Function} filter A function to use to filter modules - */ - getModules(filter) {return WebpackModules.getModule(filter, {first: false});}, - /** * Finds a module using its code. * @param {RegEx} regex A regular expression to use to filter modules @@ -183,10 +188,10 @@ const Webpack = { * @param {...string} prototypes Properties to use to filter modules * @return {Any} */ - getByPrototypes(...prototypes) { + getByPrototypeKeys(...prototypes) { const options = getOptions(prototypes); - return WebpackModules.getModule(Filters.byPrototypeFields(prototypes), options); + return WebpackModules.getModule(Filters.byPrototypeKeys(prototypes), options); }, /** @@ -194,10 +199,10 @@ const Webpack = { * @param {...string} prototypes Properties to use to filter modules * @return {Any[]} */ - getAllByPrototypeFields(...prototypes) { + getAllByPrototypeKeys(...prototypes) { const options = getOptions(prototypes, {first: false}); - return WebpackModules.getModule(Filters.byPrototypeFields(prototypes), options); + return WebpackModules.getModule(Filters.byPrototypeKeys(prototypes), options); }, /** diff --git a/renderer/src/modules/webpackmodules.js b/renderer/src/modules/webpackmodules.js index f44877b1..8cc303a8 100644 --- a/renderer/src/modules/webpackmodules.js +++ b/renderer/src/modules/webpackmodules.js @@ -41,7 +41,7 @@ export class Filters { * @param {module:WebpackModules.Filters~filter} filter - Additional filter * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties on the object's prototype */ - static byPrototypeFields(fields, filter = m => m) { + static byPrototypeKeys(fields, filter = m => m) { return module => { if (!module) return false; if (typeof(module) !== "object" && typeof(module) !== "function") return false; @@ -315,7 +315,7 @@ export default class WebpackModules { * @return {Any} */ static getByPrototypes(...prototypes) { - return this.getModule(Filters.byPrototypeFields(prototypes)); + return this.getModule(Filters.byPrototypeKeys(prototypes)); } /** @@ -324,7 +324,7 @@ export default class WebpackModules { * @return {Any} */ static getAllByPrototypes(...prototypes) { - return this.getModule(Filters.byPrototypeFields(prototypes), {first: false}); + return this.getModule(Filters.byPrototypeKeys(prototypes), {first: false}); } /** diff --git a/renderer/src/ui/settings.js b/renderer/src/ui/settings.js index 8b56da87..492ea12c 100644 --- a/renderer/src/ui/settings.js +++ b/renderer/src/ui/settings.js @@ -62,7 +62,7 @@ export default new class SettingsRenderer { } async patchSections() { - const UserSettings = await WebpackModules.getLazy(Filters.byPrototypeFields(["getPredicateSections"])); + const UserSettings = await WebpackModules.getLazy(Filters.byPrototypeKeys(["getPredicateSections"])); Patcher.after("SettingsManager", UserSettings.prototype, "getPredicateSections", (thisObject, args, returnValue) => { let location = returnValue.findIndex(s => s.section.toLowerCase() == "changelog") - 1; From 47da3f4d757be0eb3a7e9817ced569f7e7f7e31b Mon Sep 17 00:00:00 2001 From: Strencher <46447572+Strencher@users.noreply.github.com> Date: Fri, 9 Jun 2023 04:36:36 +0200 Subject: [PATCH 11/14] Fix openContextMenu function (#1632) --- renderer/src/modules/api/contextmenu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/src/modules/api/contextmenu.js b/renderer/src/modules/api/contextmenu.js index 33a9c288..51bdc4e7 100644 --- a/renderer/src/modules/api/contextmenu.js +++ b/renderer/src/modules/api/contextmenu.js @@ -22,7 +22,7 @@ const ContextMenuActions = (() => { const out = {}; try { - const ActionsModule = WebpackModules.getModule(m => Object.values(m).some(v => typeof v === "function" && v.toString().includes("CONTEXT_MENU_CLOSE")), {searchExports: false}); + const ActionsModule = WebpackModules.getModule((mod, target, id) => WebpackModules.require.m[id]?.toString().includes(`type:"CONTEXT_MENU_OPEN"`), {searchExports: false}); for (const key of Object.keys(ActionsModule)) { if (ActionsModule[key].toString().includes("CONTEXT_MENU_CLOSE")) { From 09d883007e263088142467c08eb2443264ebf737 Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Fri, 9 Jun 2023 09:29:19 -0400 Subject: [PATCH 12/14] Add store search and fix others --- renderer/src/modules/api/webpack.js | 39 ++++++++++++++++++-------- renderer/src/modules/webpackmodules.js | 12 +++++++- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/renderer/src/modules/api/webpack.js b/renderer/src/modules/api/webpack.js index 037468a6..16db9ce3 100644 --- a/renderer/src/modules/api/webpack.js +++ b/renderer/src/modules/api/webpack.js @@ -78,6 +78,13 @@ const Webpack = { */ byDisplayName(name) {return Filters.byDisplayName(name);}, + /** + * Generates a function that filters by a specific internal Store name. + * @param {string} name Name the store should have + * @returns {function} A filter that checks for a Store name match + */ + byStoreName(name) {return Filters.byStoreName(name);}, + /** * Generates a combined function from a list of filters. * @param {...function} filters A list of filters @@ -112,23 +119,26 @@ const Webpack = { * @param {Boolean} [options.searchExports=false] Whether to execute the filter on webpack exports * @return {any} */ - get(filter, options = {}) { + getModule(filter, options = {}) { if (("first" in options) && typeof(options.first) !== "boolean") return Logger.error("BdApi.Webpack~get", "Unsupported type used for options.first", options.first, "boolean expected."); - if (("defaultExport" in options) && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~get", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected."); - if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~get", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); + if (("defaultExport" in options) && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected."); + if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); return WebpackModules.getModule(filter, options); }, /** * Finds all modules matching a filter function. * @param {Function} filter A function to use to filter modules + * @param {object} [options] Options to configure the search + * @param {Boolean} [options.defaultExport=true] Whether to return default export when matching the default export + * @param {Boolean} [options.searchExports=false] Whether to execute the filter on webpack exports + * @return {any[]} */ - getAll(filter) {return WebpackModules.getModule(filter, {first: false});}, - - /** - * @deprecated - */ - getModule() {return Webpack.get(...arguments);}, + getModules(filter, options = {}) { + if (("defaultExport" in options) && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~getModules", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected."); + if (("searchExports" in options) && typeof(options.searchExports) !== "boolean") return Logger.error("BdApi.Webpack~getModules", "Unsupported type used for options.searchExports", options.searchExports, "boolean expected."); + return WebpackModules.getModule(filter, Object.assign(options, {first: false})); + }, /** * Finds multiple modules using multiple filters. @@ -232,7 +242,7 @@ const Webpack = { * @param {...String} props Strings to use to filter modules * @return {Any} */ - getByString(...strings) { + getByStrings(...strings) { const options = getOptions(strings); return WebpackModules.getModule(Filters.byStrings(...strings), options); @@ -243,11 +253,18 @@ const Webpack = { * @param {...String} strings Strings to use to filter modules * @return {Any[]} */ - getAllByString(...strings) { + getAllByStrings(...strings) { const options = getOptions(strings, {first: false}); return WebpackModules.getModule(Filters.byStrings(...strings), options); }, + + /** + * Finds an internal Store module using the name. + * @param {String} name Name of the store to find (usually includes "Store") + * @return {Any} + */ + getStore(name) {return WebpackModules.getModule(Filters.byStoreName(name));}, }; Object.freeze(Webpack); diff --git a/renderer/src/modules/webpackmodules.js b/renderer/src/modules/webpackmodules.js index 8cc303a8..b8e5652b 100644 --- a/renderer/src/modules/webpackmodules.js +++ b/renderer/src/modules/webpackmodules.js @@ -94,7 +94,6 @@ export class Filters { /** * Generates a {@link module:WebpackModules.Filters~filter} that filters by a set of properties. * @param {string} name - Name the module should have - * @param {module:WebpackModules.Filters~filter} filter - Additional filter * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties */ static byDisplayName(name) { @@ -103,6 +102,17 @@ export class Filters { }; } + /** + * Generates a {@link module:WebpackModules.Filters~filter} that filters by a set of properties. + * @param {string} name - Name the store should have (usually includes the word Store) + * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties + */ + static byStoreName(name) { + return module => { + return module?._dispatchToken && module?.getName?.() === name; + }; + } + /** * Generates a combined {@link module:WebpackModules.Filters~filter} from a list of filters. * @param {...module:WebpackModules.Filters~filter} filters - A list of filters From be4f788a03670aa107301b3be353f8ffe5ea879a Mon Sep 17 00:00:00 2001 From: Strencher <46447572+Strencher@users.noreply.github.com> Date: Wed, 14 Jun 2023 19:10:01 +0200 Subject: [PATCH 13/14] Fix patching context menu (#1633) --- renderer/src/modules/api/contextmenu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/src/modules/api/contextmenu.js b/renderer/src/modules/api/contextmenu.js index 51bdc4e7..da08e734 100644 --- a/renderer/src/modules/api/contextmenu.js +++ b/renderer/src/modules/api/contextmenu.js @@ -56,7 +56,7 @@ class MenuPatcher { if (!startupComplete) return Logger.warn("ContextMenu~Patcher", "Startup wasn't successfully, aborting initialization."); const {module, key} = (() => { - const foundModule = WebpackModules.getModule(m => Object.values(m).some(v => typeof v === "function" && v.toString().includes("CONTEXT_MENU_CLOSE")), {searchExports: false}); + const foundModule = WebpackModules.getModule(m => Object.values(m).some(v => typeof v === "function" && v.toString().includes(`type:"CONTEXT_MENU_CLOSE"`)), {searchExports: false}); const foundKey = Object.keys(foundModule).find(k => foundModule[k].length === 3); return {module: foundModule, key: foundKey}; From 9bb71d646249f684099f1301c541cd9c40e5edbe Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Wed, 14 Jun 2023 21:17:44 -0400 Subject: [PATCH 14/14] Fix tooltip search --- renderer/src/modules/discordmodules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/src/modules/discordmodules.js b/renderer/src/modules/discordmodules.js index 059aaf27..2e46f8e5 100644 --- a/renderer/src/modules/discordmodules.js +++ b/renderer/src/modules/discordmodules.js @@ -160,6 +160,6 @@ export default Utilities.memoizeObject({ // Make fallback component just pass children, so it can at least render that. const fallback = props => props.children?.({}) ?? null; - return WebpackModules.getModule(Filters.byPrototypeFields(["renderTooltip"]), {searchExports: true}) ?? fallback; + return WebpackModules.getModule(Filters.byPrototypeKeys(["renderTooltip"]), {searchExports: true}) ?? fallback; } });