Merge branch 'main' into development

This commit is contained in:
Zack Rauen 2023-11-10 22:13:48 -05:00
commit 63f5e80d8c
16 changed files with 979 additions and 902 deletions

View File

@ -2,6 +2,38 @@
This changelog starts with the restructured 1.0.0 release that happened after context isolation changes. The changelogs here should more-or-less mirror the ones that get shown in the client but probably with less formatting and pizzazz. This changelog starts with the restructured 1.0.0 release that happened after context isolation changes. The changelogs here should more-or-less mirror the ones that get shown in the client but probably with less formatting and pizzazz.
## 1.9.4
### Added
- New css variable `--os-accent-color`
- Temporary `Buffer` polyfill
### Removed
### Changed
- `BdApi.Net.fetch` now has an optional `timeout` parameter
### Fixed
- Fixes not being able to use `http` for `BdApi.Net.fetch`.
- Bad URLs and other early errors in `BdApi.Net.fetch` now handled better.
## 1.9.3
### Added
- Multiple shorthand functions under `BdApi.Webpack`
- New `getStore` filter
### Removed
### Changed
- Updated translations
### Fixed
- Fixed header color in light mode.
- Fixed window size retention for users of remove minimum size option.
- Fixed a toast saying an addon was loaded when it was unloaded.
- Fixed context menu patching API for plugins.
## 1.9.2 ## 1.9.2
### Added ### Added

View File

@ -1,6 +1,6 @@
{ {
"name": "betterdiscord", "name": "betterdiscord",
"version": "1.9.3", "version": "1.9.5",
"description": "Enhances Discord by adding functionality and themes.", "description": "Enhances Discord by adding functionality and themes.",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {

File diff suppressed because it is too large Load Diff

View File

@ -6,12 +6,13 @@ const redirectCodes = new Set([301, 302, 307, 308]);
/** /**
* @typedef {Object} FetchOptions * @typedef {Object} FetchOptions
* @property {"GET" | "PUT" | "POST" | "DELETE"} [method] - Request method. * @property {"GET" | "PUT" | "POST" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD" | "CONNECT" | "TRACE"} [method] - Request method.
* @property {Record<string, string>} [headers] - Request headers. * @property {Record<string, string>} [headers] - Request headers.
* @property {"manual" | "follow"} [redirect] - Whether to follow redirects. * @property {"manual" | "follow"} [redirect] - Whether to follow redirects.
* @property {number} [maxRedirects] - Maximum amount of redirects to be followed. * @property {number} [maxRedirects] - Maximum amount of redirects to be followed.
* @property {AbortSignal} [signal] - Signal to abruptly cancel the request * @property {AbortSignal} [signal] - Signal to abruptly cancel the request
* @property {Uint8Array | string} [body] - Defines a request body. Data must be serializable. * @property {Uint8Array | string} [body] - Defines a request body. Data must be serializable.
* @property {number} [timeout] - Request timeout time.
*/ */
/** /**

View File

@ -34,12 +34,12 @@ export default function () {
if (!Reflect.has(window, chunkName)) { if (!Reflect.has(window, chunkName)) {
predefine(window, chunkName, instance => { predefine(window, chunkName, instance => {
predefine(instance, "push", () => { instance.push([[Symbol()], {}, require => {
instance.push([[Symbol()], {}, require => { require.d = (target, exports) => {
require.d = (target, exports) => { for (const key in exports) {
for (const key in exports) { if (!Reflect.has(exports, key)) continue;
if (!Reflect.has(exports, key) || target[key]) continue;
try {
Object.defineProperty(target, key, { Object.defineProperty(target, key, {
get: () => exports[key](), get: () => exports[key](),
set: v => {exports[key] = () => v;}, set: v => {exports[key] = () => v;},
@ -47,11 +47,13 @@ export default function () {
configurable: true configurable: true
}); });
} }
}; catch (error) {
}]); // eslint-disable-next-line no-console
console.error(error);
instance.pop(); }
}); }
};
}]);
}); });
} }
}; };

View File

@ -30,7 +30,10 @@
"postcss-easy-import": "^4.0.0", "postcss-easy-import": "^4.0.0",
"postcss-loader": "^6.2.1", "postcss-loader": "^6.2.1",
"stylelint": "^14.3.0", "stylelint": "^14.3.0",
"webpack": "^5.73.0", "stylelint-config-standard": "^24.0.0",
"stylelint-config-standard": "^24.0.0" "webpack": "^5.73.0"
},
"dependencies": {
"buffer": "^6.0.3"
} }
} }

View File

@ -1,24 +1,21 @@
// fixed, improved, added, progress // fixed, improved, added, progress
export default { export default {
description: "This update has a few important bugfixes but it also contains some important QOL updates for plugin developers!", description: "This update is just a hotfix for the recent Discord update!",
changes: [ changes: [
{ {
title: "What's New?", title: "What's Fixed?",
type: "improved", type: "improved",
items: [ items: [
"Updated translations for many languages! Thank you to our many contributors!", "Patching webpack modules is now fixed for plugins.",
"New shorthand API methods for developers available under `BdApi.Webpack`. Documentation should be updated soon!", "Themes are placed later in the DOM than Discord's CSS giving them priority.",
"Also a new `Filter` has been added for internal stores. This includes the `getStore` shorthand!" "BetterDiscord's modals should all be working."
] ]
}, },
{ {
title: "Bug Fixes", title: "What's not fixed?",
type: "fixed", type: "fixed",
items: [ items: [
"Fixed header color in light mode. (Thanks @Fede)", "Individual plugins and themes will still need to make their own updates.",
"Fixed window size retention for users of remove minimum size option. (Thanks @Neodymium)",
"Fixed a toast saying an addon was loaded when it was unloaded. (Thanks @benji78)",
"Fixed context menu patching API for plugins. (Thanks @Strencher)"
] ]
} }
] ]

View File

@ -1,10 +1,12 @@
import Remote from "../../polyfill/remote"; import Remote from "../../polyfill/remote";
const methods = new Set(["GET", "PUT", "POST", "DELETE"]); const redirects = new Set(["manual", "follow"]);
const methods = new Set(["GET", "PUT", "POST", "DELETE", "PATCH", "OPTIONS", "HEAD", "CONNECT", "TRACE"]);
const bodylessStatusCodes = new Set([101, 204, 205, 304]);
class FetchResponse extends Response { class FetchResponse extends Response {
constructor(options) { constructor(options) {
super(options.content, { super(bodylessStatusCodes.has(options.status) ? null : options.content, {
headers: new Headers(options.headers), headers: new Headers(options.headers),
method: options.method ?? "GET", method: options.method ?? "GET",
body: options.content, body: options.content,
@ -34,12 +36,13 @@ const convertSignal = signal => {
/** /**
* @typedef {Object} FetchOptions * @typedef {Object} FetchOptions
* @property {"GET" | "PUT" | "POST" | "DELETE"} [method] - Request method. * @property {"GET" | "PUT" | "POST" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD" | "CONNECT" | "TRACE"} [method] - Request method.
* @property {Record<string, string>} [headers] - Request headers. * @property {Record<string, string>} [headers] - Request headers.
* @property {"manual" | "follow"} [redirect] - Whether to follow redirects. * @property {"manual" | "follow"} [redirect] - Whether to follow redirects.
* @property {number} [maxRedirects] - Maximum amount of redirects to be followed. * @property {number} [maxRedirects] - Maximum amount of redirects to be followed.
* @property {AbortSignal} [signal] - Signal to abruptly cancel the request * @property {AbortSignal} [signal] - Signal to abruptly cancel the request
* @property {Uint8Array | string} [body] - Defines a request body. Data must be serializable. * @property {Uint8Array | string} [body] - Defines a request body. Data must be serializable.
* @property {number} [timeout] - Request timeout time.
*/ */
/** /**
@ -55,8 +58,12 @@ export default function fetch(url, options = {}) {
data.headers = options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers; data.headers = options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers;
} }
if (typeof options.redirect === "string" && redirects.has(options.redirect)) data.redirect = options.redirect;
if (typeof options.body === "string" || options.body instanceof Uint8Array) data.body = options.body; 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 (typeof options.method === "string" && methods.has(options.method)) data.method = options.method;
if (typeof options.maxRedirects === "number") data.maxRedirects = options.maxRedirects;
if (typeof options.timeout === "number") data.timeout = options.timeout;
if (options.signal instanceof AbortSignal) data.signal = convertSignal(options.signal); if (options.signal instanceof AbortSignal) data.signal = convertSignal(options.signal);
let ctx; let ctx;

View File

@ -198,7 +198,7 @@ export default class DOMManager {
} }
} }
DOMManager.createElement("bd-head", {target: document.head}); DOMManager.createElement("bd-head", {target: document.body});
DOMManager.createElement("bd-body", {target: document.body}); DOMManager.createElement("bd-body", {target: document.body});
DOMManager.createElement("bd-scripts", {target: DOMManager.bdHead}); DOMManager.createElement("bd-scripts", {target: DOMManager.bdHead});
DOMManager.createElement("bd-styles", {target: DOMManager.bdHead}); DOMManager.createElement("bd-styles", {target: DOMManager.bdHead});

View File

@ -16,20 +16,20 @@ export default new class LocaleManager {
} }
initialize() { initialize() {
this.setLocale(this.discordLocale); this.setLocale();
LocaleStore?.addChangeListener((newLocale) => this.setLocale(newLocale)); LocaleStore?.addChangeListener(() => this.setLocale());
} }
setLocale(newLocale) { setLocale() {
let newStrings; let newStrings;
if (newLocale != this.defaultLocale) { if (this.discordLocale != this.defaultLocale) {
newStrings = Locales[newLocale]; newStrings = Locales[this.discordLocale];
if (!newStrings) return this.setLocale(this.defaultLocale); if (!newStrings) return this.setLocale(this.defaultLocale);
} }
else { else {
newStrings = Locales[this.defaultLocale]; newStrings = Locales[this.defaultLocale];
} }
this.locale = newLocale; this.locale = this.discordLocale;
Utilities.extendTruthy(this.strings, newStrings); Utilities.extendTruthy(this.strings, newStrings);
Events.emit("strings-updated"); Events.emit("strings-updated");
} }

View File

@ -190,7 +190,7 @@ export default class WebpackModules {
if (!modules.hasOwnProperty(index)) continue; if (!modules.hasOwnProperty(index)) continue;
let module = null; let module = null;
try {module = modules[index]} catch {continue;}; try {module = modules[index];} catch {continue;}
const {exports} = module; const {exports} = module;
if (!exports || exports === window || exports === document.documentElement || exports[Symbol.toStringTag] === "DOMTokenList") continue; if (!exports || exports === window || exports === document.documentElement || exports[Symbol.toStringTag] === "DOMTokenList") continue;

View File

@ -1,17 +1,13 @@
import WebpackModules from "@modules/webpackmodules"; import Logger from "@common/logger";
Object.defineProperty(window, "Buffer", { Object.defineProperty(window, "Buffer", {
get() {return Buffer.getBuffer().Buffer;}, get() {
Logger.warn("Deprecated", `Usage of the Buffer global is deprecated. Consider using web standards such as Uint8Array and TextDecoder/TextEncoder.`);
return Buffer;
},
configurable: true, configurable: true,
enumerable: false enumerable: false
}); });
export default class Buffer { export default Buffer;
static getBuffer() {
if (this.cached) return this.cached;
this.cached = WebpackModules.getByProps("INSPECT_MAX_BYTES");
return this.cached;
}
}

View File

@ -5,7 +5,7 @@ import vm from "./vm";
import fs from "./fs"; import fs from "./fs";
import request from "./request"; import request from "./request";
import https from "./https"; import https from "./https";
import Buffer from "./buffer"; import buffer from "./buffer";
import crypto from "./crypto"; import crypto from "./crypto";
import Remote from "./remote"; import Remote from "./remote";
import Logger from "common/logger"; import Logger from "common/logger";
@ -37,7 +37,7 @@ export const createRequire = function (path) {
case "process": return window.process; case "process": return window.process;
case "vm": return vm; case "vm": return vm;
case "module": return Module; case "module": return Module;
case "buffer": return Buffer.getBuffer(); case "buffer": return buffer;
case "crypto": return crypto; case "crypto": return crypto;
default: default:

View File

@ -33,12 +33,8 @@ export default class Modals {
static get hasModalOpen() {return !!document.getElementsByClassName("bd-modal").length;} static get hasModalOpen() {return !!document.getElementsByClassName("bd-modal").length;}
static get ModalActions() { static get ModalActions() {
return this._ModalActions ??= { return this._ModalActions ??= WebpackModules.getByProps("openModal", "closeModal");
openModal: WebpackModules.getModule(m => typeof m === "function" && m?.toString().includes("onCloseCallback") && m?.toString().includes("Layer"), {searchExports: true}),
closeModal: WebpackModules.getModule(m => typeof m === "function" && m?.toString().includes("onCloseCallback()"), {searchExports: true})
};
} }
static get ModalQueue() {return this._ModalQueue ??= [];} static get ModalQueue() {return this._ModalQueue ??= [];}
static async initialize() { static async initialize() {

View File

@ -3,7 +3,7 @@ import DOMManager from "@modules/dommanager";
export default class Notices { export default class Notices {
static get baseClass() {return this.__baseClass ??= WebpackModules.getByProps("container", "base")?.base;} static get baseClass() {return this.__baseClass ??= WebpackModules.getByProps("container", "base", "sidebar")?.base;}
static get errorPageClass() {return this.__errorPageClass ??= WebpackModules.getByProps("errorPage")?.errorPage;} static get errorPageClass() {return this.__errorPageClass ??= WebpackModules.getByProps("errorPage")?.errorPage;}
/** Shorthand for `type = "info"` for {@link module:Notices.show} */ /** Shorthand for `type = "info"` for {@link module:Notices.show} */

View File

@ -6,7 +6,7 @@ const basePkg = require("../package.json");
module.exports = { module.exports = {
mode: "development", mode: "development",
target: "node", target: "electron-renderer",
devtool: false, devtool: false,
entry: "./src/index.js", entry: "./src/index.js",
output: { output: {
@ -31,7 +31,10 @@ module.exports = {
data$: path.resolve("src", "modules"), data$: path.resolve("src", "modules"),
builtins$: path.resolve("src", "modules"), builtins$: path.resolve("src", "modules"),
common: path.resolve(__dirname, "..", "common") common: path.resolve(__dirname, "..", "common")
} },
fallback: {
buffer: require.resolve("buffer/"),
},
}, },
module: { module: {
rules: [ rules: [
@ -53,7 +56,10 @@ module.exports = {
}), }),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
"process.env.__VERSION__": JSON.stringify(basePkg.version) "process.env.__VERSION__": JSON.stringify(basePkg.version)
}) }),
new webpack.ProvidePlugin({
Buffer: [require.resolve("buffer/"), "Buffer"],
}),
], ],
optimization: { optimization: {
minimizer: [ minimizer: [