Merge branch 'main' of https://github.com/Vendicated/Vencord
This commit is contained in:
commit
c320c0ff20
39 changed files with 858 additions and 1277 deletions
10
.github/ISSUE_TEMPLATE/blank.yml
vendored
10
.github/ISSUE_TEMPLATE/blank.yml
vendored
|
@ -5,15 +5,9 @@ body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
# READ THIS BEFORE OPENING AN ISSUE
|

|
||||||
|
|
||||||
This form is ONLY FOR DEVELOPERS. YOUR ISSUE WILL BE CLOSED AND YOU WILL POSSIBLY BE BLOCKED FROM THE REPOSITORY IF YOU IGNORE THIS.
|
GitHub Issues are for development, not support! Please use our [support server](https://vencord.dev/discord) unless you are a Vencord Developer.
|
||||||
|
|
||||||
DO NOT USE THIS FORM, unless
|
|
||||||
- you are a vencord contributor
|
|
||||||
- you were given explicit permission to use this form by a moderator in our support server
|
|
||||||
|
|
||||||
DO NOT USE THIS FORM FOR SECURITY RELATED ISSUES. [CREATE A SECURITY ADVISORY INSTEAD.](https://github.com/Vendicated/Vencord/security/advisories/new)
|
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: content
|
id: content
|
||||||
|
|
21
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
21
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
@ -7,24 +7,9 @@ body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
# READ THIS BEFORE OPENING AN ISSUE
|

|
||||||
|
|
||||||
This form is ONLY FOR DEVELOPERS. YOUR ISSUE WILL BE CLOSED AND YOU WILL POSSIBLY BE BLOCKED FROM THE REPOSITORY IF YOU IGNORE THIS.
|
GitHub Issues are for development, not support! Please use our [support server](https://vencord.dev/discord) unless you are a Vencord Developer.
|
||||||
|
|
||||||
DO NOT USE THIS FORM, unless
|
|
||||||
- you are a vencord contributor
|
|
||||||
- you were given explicit permission to use this form by a moderator in our support server
|
|
||||||
|
|
||||||
DO NOT USE THIS FORM FOR SECURITY RELATED ISSUES. [CREATE A SECURITY ADVISORY INSTEAD.](https://github.com/Vendicated/Vencord/security/advisories/new)
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: discord
|
|
||||||
attributes:
|
|
||||||
label: Discord Account
|
|
||||||
description: Who on Discord is making this request? Not required but encouraged for easier follow-up
|
|
||||||
placeholder: username#0000
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: bug-description
|
id: bug-description
|
||||||
|
@ -77,5 +62,5 @@ body:
|
||||||
options:
|
options:
|
||||||
- label: I am using Discord Stable or tried on Stable and this bug happens there as well
|
- label: I am using Discord Stable or tried on Stable and this bug happens there as well
|
||||||
required: true
|
required: true
|
||||||
- label: I have read the requirements for opening an issue above
|
- label: I am a Vencord Developer
|
||||||
required: true
|
required: true
|
||||||
|
|
BIN
.github/ISSUE_TEMPLATE/developer-banner.png
vendored
Normal file
BIN
.github/ISSUE_TEMPLATE/developer-banner.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
42
package.json
42
package.json
|
@ -24,7 +24,7 @@
|
||||||
"dev": "pnpm watch",
|
"dev": "pnpm watch",
|
||||||
"watchWeb": "pnpm buildWeb --watch",
|
"watchWeb": "pnpm buildWeb --watch",
|
||||||
"generatePluginJson": "tsx scripts/generatePluginList.ts",
|
"generatePluginJson": "tsx scripts/generatePluginList.ts",
|
||||||
"generateTypes": "tspc --emitDeclarationOnly --declaration --outDir packages/vencord-types",
|
"generateTypes": "tspc --emitDeclarationOnly --declaration --outDir packages/vencord-types --allowJs false",
|
||||||
"inject": "node scripts/runInstaller.mjs",
|
"inject": "node scripts/runInstaller.mjs",
|
||||||
"uninject": "node scripts/runInstaller.mjs",
|
"uninject": "node scripts/runInstaller.mjs",
|
||||||
"lint": "eslint",
|
"lint": "eslint",
|
||||||
|
@ -45,31 +45,31 @@
|
||||||
"virtual-merge": "^1.0.1"
|
"virtual-merge": "^1.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@stylistic/eslint-plugin": "^2.12.1",
|
"@stylistic/eslint-plugin": "^4.0.0",
|
||||||
"@types/chrome": "^0.0.287",
|
"@types/chrome": "^0.0.304",
|
||||||
"@types/diff": "^6.0.0",
|
"@types/diff": "^7.0.1",
|
||||||
"@types/lodash": "^4.17.14",
|
"@types/lodash": "^4.17.14",
|
||||||
"@types/node": "^22.10.5",
|
"@types/node": "^22.10.5",
|
||||||
"@types/react": "^19.0.2",
|
"@types/react": "^19.0.10",
|
||||||
"@types/react-dom": "^19.0.2",
|
"@types/react-dom": "^19.0.4",
|
||||||
"@types/yazl": "^2.4.5",
|
"@types/yazl": "^2.4.5",
|
||||||
"diff": "^7.0.0",
|
"diff": "^7.0.0",
|
||||||
"discord-types": "^1.3.26",
|
"discord-types": "^1.3.26",
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"eslint": "^9.17.0",
|
"eslint": "^9.20.1",
|
||||||
"eslint-import-resolver-alias": "^1.1.2",
|
"eslint-import-resolver-alias": "^1.1.2",
|
||||||
"eslint-plugin-path-alias": "2.1.0",
|
"eslint-plugin-path-alias": "2.1.0",
|
||||||
"eslint-plugin-react": "^7.37.3",
|
"eslint-plugin-react": "^7.37.3",
|
||||||
"eslint-plugin-simple-header": "^1.2.1",
|
"eslint-plugin-simple-header": "^1.2.1",
|
||||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||||
"eslint-plugin-unused-imports": "^4.1.4",
|
"eslint-plugin-unused-imports": "^4.1.4",
|
||||||
"highlight.js": "11.7.0",
|
"highlight.js": "11.11.1",
|
||||||
"html-minifier-terser": "^7.2.0",
|
"html-minifier-terser": "^7.2.0",
|
||||||
"moment": "^2.22.2",
|
"moment": "^2.22.2",
|
||||||
"puppeteer-core": "^23.11.1",
|
"puppeteer-core": "^24.2.1",
|
||||||
"standalone-electron-types": "^1.0.0",
|
"standalone-electron-types": "^34.2.0",
|
||||||
"stylelint": "^16.12.0",
|
"stylelint": "^16.12.0",
|
||||||
"stylelint-config-standard": "^36.0.1",
|
"stylelint-config-standard": "^37.0.0",
|
||||||
"ts-patch": "^3.3.0",
|
"ts-patch": "^3.3.0",
|
||||||
"ts-pattern": "^5.6.0",
|
"ts-pattern": "^5.6.0",
|
||||||
"tsx": "^4.19.2",
|
"tsx": "^4.19.2",
|
||||||
|
@ -79,10 +79,10 @@
|
||||||
"typescript-transform-paths": "^3.5.3",
|
"typescript-transform-paths": "^3.5.3",
|
||||||
"zip-local": "^0.3.5"
|
"zip-local": "^0.3.5"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@9.1.0",
|
"packageManager": "pnpm@10.4.1",
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
"eslint@9.17.0": "patches/eslint@9.17.0.patch",
|
"eslint@9.20.1": "patches/eslint@9.20.1.patch",
|
||||||
"eslint-plugin-path-alias@2.1.0": "patches/eslint-plugin-path-alias@2.1.0.patch"
|
"eslint-plugin-path-alias@2.1.0": "patches/eslint-plugin-path-alias@2.1.0.patch"
|
||||||
},
|
},
|
||||||
"peerDependencyRules": {
|
"peerDependencyRules": {
|
||||||
|
@ -95,18 +95,14 @@
|
||||||
"source-map-resolve": "*",
|
"source-map-resolve": "*",
|
||||||
"resolve-url": "*",
|
"resolve-url": "*",
|
||||||
"source-map-url": "*",
|
"source-map-url": "*",
|
||||||
"urix": "*"
|
"urix": "*",
|
||||||
}
|
"q": "*"
|
||||||
},
|
},
|
||||||
"webExt": {
|
"onlyBuiltDependencies": [
|
||||||
"artifactsDir": "./dist",
|
"esbuild"
|
||||||
"build": {
|
]
|
||||||
"overwriteDest": true
|
|
||||||
},
|
|
||||||
"sourceDir": "./dist/firefox-unpacked"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18",
|
"node": ">=18"
|
||||||
"pnpm": ">=9"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@vencord/types",
|
"name": "@vencord/types",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "0.1.3",
|
"version": "1.11.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"types": "index.d.ts",
|
"types": "index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -13,16 +13,16 @@
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/fs-extra": "^11.0.4",
|
"@types/fs-extra": "^11.0.4",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.3.0",
|
||||||
"tsx": "^3.12.6"
|
"tsx": "^4.19.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash": "^4.14.191",
|
"@types/lodash": "4.17.15",
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^22.13.4",
|
||||||
"@types/react": "^18.2.0",
|
"@types/react": "18.3.1",
|
||||||
"@types/react-dom": "^18.0.10",
|
"@types/react-dom": "18.3.1",
|
||||||
"discord-types": "^1.3.26",
|
"discord-types": "^1.3.26",
|
||||||
"standalone-electron-types": "^1.0.0",
|
"standalone-electron-types": "^34.2.0",
|
||||||
"type-fest": "^3.5.3"
|
"type-fest": "^4.35.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1592
pnpm-lock.yaml
1592
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -4,11 +4,11 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { Settings } from "@api/Settings";
|
||||||
import { PluginIpcMappings } from "@main/ipcPlugins";
|
import { PluginIpcMappings } from "@main/ipcPlugins";
|
||||||
import type { UserThemeHeader } from "@main/themes";
|
import type { UserThemeHeader } from "@main/themes";
|
||||||
import { IpcEvents } from "@shared/IpcEvents";
|
import { IpcEvents } from "@shared/IpcEvents";
|
||||||
import { IpcRes } from "@utils/types";
|
import { IpcRes } from "@utils/types";
|
||||||
import type { Settings } from "api/Settings";
|
|
||||||
import { ipcRenderer } from "electron";
|
import { ipcRenderer } from "electron";
|
||||||
|
|
||||||
function invoke<T = any>(event: IpcEvents, ...args: any[]) {
|
function invoke<T = any>(event: IpcEvents, ...args: any[]) {
|
||||||
|
|
|
@ -68,7 +68,7 @@ export async function loadLazyChunks() {
|
||||||
|
|
||||||
const isWorkerAsset = await fetch(wreq.p + wreq.u(id))
|
const isWorkerAsset = await fetch(wreq.p + wreq.u(id))
|
||||||
.then(r => r.text())
|
.then(r => r.text())
|
||||||
.then(t => t.includes("importScripts("));
|
.then(t => /importScripts\(|self\.postMessage/.test(t));
|
||||||
|
|
||||||
if (isWorkerAsset) {
|
if (isWorkerAsset) {
|
||||||
invalidChunks.add(id);
|
invalidChunks.add(id);
|
||||||
|
@ -174,7 +174,7 @@ export async function loadLazyChunks() {
|
||||||
await Promise.all(chunksLeft.map(async id => {
|
await Promise.all(chunksLeft.map(async id => {
|
||||||
const isWorkerAsset = await fetch(wreq.p + wreq.u(id))
|
const isWorkerAsset = await fetch(wreq.p + wreq.u(id))
|
||||||
.then(r => r.text())
|
.then(r => r.text())
|
||||||
.then(t => t.includes("importScripts("));
|
.then(t => /importScripts\(|self\.postMessage/.test(t));
|
||||||
|
|
||||||
// Loads the chunk. Currently this only happens with the language packs which are loaded differently
|
// Loads the chunk. Currently this only happens with the language packs which are loaded differently
|
||||||
if (!isWorkerAsset) {
|
if (!isWorkerAsset) {
|
||||||
|
|
|
@ -16,8 +16,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "SCALE_DOWN:",
|
find: "SCALE_DOWN:",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /!\(null==(\i)\|\|0===\i\|\|null==(\i)\|\|0===\i\)/,
|
match: /(?<="IMAGE"===\i\?)\i(?=\?)/,
|
||||||
replace: (_, width, height) => `!((null == ${width} || 0 === ${width}) && (null == ${height} || 0 === ${height}))`
|
replace: "true"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -85,7 +85,7 @@ export default definePlugin({
|
||||||
replace: "$&onRequestClose:$self.onPopoutClose,"
|
replace: "$&onRequestClose:$self.onPopoutClose,"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /(?<=\.avatarWrapper,)/,
|
match: /(?<=#{intl::SET_STATUS}\),)/,
|
||||||
replace: "ref:$self.accountPanelRef,onContextMenu:$self.openAccountPanelContextMenu,"
|
replace: "ref:$self.accountPanelRef,onContextMenu:$self.openAccountPanelContextMenu,"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -26,10 +26,18 @@ export default definePlugin({
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: '"ChannelAttachButton"',
|
find: '"ChannelAttachButton"',
|
||||||
replacement: {
|
replacement: [
|
||||||
|
{
|
||||||
|
// FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
|
||||||
match: /\.attachButtonInner,"aria-label":.{0,50},onDoubleClick:(.+?:void 0),.{0,30}?\.\.\.(\i),/,
|
match: /\.attachButtonInner,"aria-label":.{0,50},onDoubleClick:(.+?:void 0),.{0,30}?\.\.\.(\i),/,
|
||||||
replace: "$&onClick:$1,onContextMenu:$2.onClick,",
|
replace: "$&onClick:$1,onContextMenu:$2.onClick,",
|
||||||
|
noWarn: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
match: /\.attachButtonInner,"aria-label":.{0,50},onDoubleClick:(.+?:void 0),.{0,100}\},(\i)\).{0,100}children:\i/,
|
||||||
|
replace: "$&,onClick:$1,onContextMenu:$2.onClick,",
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -50,12 +50,24 @@ export default definePlugin({
|
||||||
find: ".decorationGridItem,",
|
find: ".decorationGridItem,",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /(?<==)\i=>{let{children.{20,100}decorationGridItem/,
|
// FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
|
||||||
replace: "$self.DecorationGridItem=$&"
|
match: /(?<==)\i=>{let{children.{20,200}decorationGridItem/,
|
||||||
|
replace: "$self.DecorationGridItem=$&",
|
||||||
|
noWarn: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
|
||||||
match: /(?<==)\i=>{let{user:\i,avatarDecoration/,
|
match: /(?<==)\i=>{let{user:\i,avatarDecoration/,
|
||||||
replace: "$self.DecorationGridDecoration=$&"
|
replace: "$self.DecorationGridDecoration=$&",
|
||||||
|
noWarn: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
match: /(?<==)\i=>{var{children.{20,200}decorationGridItem/,
|
||||||
|
replace: "$self.DecorationGridItem=$&",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
match: /(?<==)\i=>{var{user:\i,avatarDecoration/,
|
||||||
|
replace: "$self.DecorationGridDecoration=$&",
|
||||||
},
|
},
|
||||||
// Remove NEW label from decor avatar decorations
|
// Remove NEW label from decor avatar decorations
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { CopyIcon, DeleteIcon } from "@components/Icons";
|
import { CopyIcon, DeleteIcon } from "@components/Icons";
|
||||||
import { Alerts, Clipboard, ContextMenuApi, Menu, UserStore } from "webpack/common";
|
import { Alerts, Clipboard, ContextMenuApi, Menu, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
import { Decoration } from "../../lib/api";
|
import { Decoration } from "../../lib/api";
|
||||||
import { useCurrentUserDecorationsStore } from "../../lib/stores/CurrentUserDecorationsStore";
|
import { useCurrentUserDecorationsStore } from "../../lib/stores/CurrentUserDecorationsStore";
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { app } from "electron";
|
||||||
|
|
||||||
app.on("browser-window-created", (_, win) => {
|
app.on("browser-window-created", (_, win) => {
|
||||||
win.webContents.on("frame-created", (_, { frame }) => {
|
win.webContents.on("frame-created", (_, { frame }) => {
|
||||||
frame.once("dom-ready", () => {
|
frame?.once("dom-ready", () => {
|
||||||
if (frame.url.startsWith("https://open.spotify.com/embed/")) {
|
if (frame.url.startsWith("https://open.spotify.com/embed/")) {
|
||||||
const settings = RendererSettings.store.plugins?.FixSpotifyEmbeds;
|
const settings = RendererSettings.store.plugins?.FixSpotifyEmbeds;
|
||||||
if (!settings?.enabled) return;
|
if (!settings?.enabled) return;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { app } from "electron";
|
||||||
|
|
||||||
app.on("browser-window-created", (_, win) => {
|
app.on("browser-window-created", (_, win) => {
|
||||||
win.webContents.on("frame-created", (_, { frame }) => {
|
win.webContents.on("frame-created", (_, { frame }) => {
|
||||||
frame.once("dom-ready", () => {
|
frame?.once("dom-ready", () => {
|
||||||
if (frame.url.startsWith("https://www.youtube.com/")) {
|
if (frame.url.startsWith("https://www.youtube.com/")) {
|
||||||
const settings = RendererSettings.store.plugins?.FixYoutubeEmbeds;
|
const settings = RendererSettings.store.plugins?.FixYoutubeEmbeds;
|
||||||
if (!settings?.enabled) return;
|
if (!settings?.enabled) return;
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { Devs } from "@utils/constants";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findStoreLazy } from "@webpack";
|
import { findStoreLazy } from "@webpack";
|
||||||
import { Button, Forms, showToast, TextInput, Toasts, Tooltip, useEffect, useState } from "webpack/common";
|
import { Button, Forms, showToast, TextInput, Toasts, Tooltip, useEffect, useState } from "@webpack/common";
|
||||||
|
|
||||||
const enum ActivitiesTypes {
|
const enum ActivitiesTypes {
|
||||||
Game,
|
Game,
|
||||||
|
|
|
@ -34,7 +34,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "#{intl::FRIENDS_ALL_HEADER}",
|
find: "#{intl::FRIENDS_ALL_HEADER}",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /toString\(\)\}\);case (\i\.\i)\.BLOCKED/,
|
match: /toString\(\)\}\);case (\i\.\i)\.PENDING/,
|
||||||
replace: 'toString()});case $1.IMPLICIT:return "Implicit — "+arguments[1];case $1.BLOCKED'
|
replace: 'toString()});case $1.IMPLICIT:return "Implicit — "+arguments[1];case $1.BLOCKED'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -50,7 +50,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "#{intl::FRIENDS_SECTION_ONLINE}",
|
find: "#{intl::FRIENDS_SECTION_ONLINE}",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /,{id:(\i\.\i)\.BLOCKED,show:.+?className:(\i\.item)/,
|
match: /,{id:(\i\.\i)\.PENDING,show:.+?className:(\i\.item)/,
|
||||||
replace: (rest, relationShipTypes, className) => `,{id:${relationShipTypes}.IMPLICIT,show:true,className:${className},content:"Implicit"}${rest}`
|
replace: (rest, relationShipTypes, className) => `,{id:${relationShipTypes}.IMPLICIT,show:true,className:${className},content:"Implicit"}${rest}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -58,7 +58,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: '"FriendsStore"',
|
find: '"FriendsStore"',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=case (\i\.\i)\.BLOCKED:return (\i)\.type===\i\.\i\.BLOCKED)/,
|
match: /(?<=case (\i\.\i)\.SUGGESTIONS:return \d+===(\i)\.type)/,
|
||||||
replace: ";case $1.IMPLICIT:return $2.type===5"
|
replace: ";case $1.IMPLICIT:return $2.type===5"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -65,10 +65,18 @@ export default definePlugin({
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "{isSidebarVisible:",
|
find: "{isSidebarVisible:",
|
||||||
replacement: {
|
replacement: [
|
||||||
|
{
|
||||||
|
// FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
|
||||||
match: /(?<=let\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/,
|
match: /(?<=let\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/,
|
||||||
replace: ":[$1?.startsWith('members')?$self.render():null,$2"
|
replace: ":[$1?.startsWith('members')?$self.render():null,$2",
|
||||||
|
noWarn: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
match: /(?<=var\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/,
|
||||||
|
replace: ":[$1?.startsWith('members')?$self.render():null,$2",
|
||||||
|
},
|
||||||
|
],
|
||||||
predicate: () => settings.store.memberList
|
predicate: () => settings.store.memberList
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -84,8 +84,14 @@ export default definePlugin({
|
||||||
find: ".USER_MENTION)",
|
find: ".USER_MENTION)",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
|
// FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
|
||||||
match: /onContextMenu:\i,color:\i,\.\.\.\i(?=,children:)(?<=user:(\i),channel:(\i).{0,500}?)/,
|
match: /onContextMenu:\i,color:\i,\.\.\.\i(?=,children:)(?<=user:(\i),channel:(\i).{0,500}?)/,
|
||||||
replace: "$&,color:$self.getColorInt($1?.id,$2?.id)"
|
replace: "$&,color:$self.getColorInt($1?.id,$2?.id)",
|
||||||
|
noWarn: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
match: /(?<=onContextMenu:\i,color:)\i(?=\},\i\),\{children)(?<=user:(\i),channel:(\i).{0,500}?)/,
|
||||||
|
replace: "$self.getColorInt($1?.id,$2?.id)",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
predicate: () => settings.store.chatMentions
|
predicate: () => settings.store.chatMentions
|
||||||
|
|
|
@ -96,6 +96,6 @@
|
||||||
|
|
||||||
.vc-shiki-root .vc-shiki-table-cell:last-child {
|
.vc-shiki-root .vc-shiki-table-cell:last-child {
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
word-break: break-word;
|
overflow-wrap: break-word;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ export default definePlugin({
|
||||||
replacement: [
|
replacement: [
|
||||||
// Make the channel appear as muted if it's hidden
|
// Make the channel appear as muted if it's hidden
|
||||||
{
|
{
|
||||||
match: /{channel:(\i),name:\i,muted:(\i).+?;/,
|
match: /\.subtitle,.+?;(?=return\(0,\i\.jsxs?\))(?<={channel:(\i),name:\i,muted:(\i).+?;)/,
|
||||||
replace: (m, channel, muted) => `${m}${muted}=$self.isHiddenChannel(${channel})?true:${muted};`
|
replace: (m, channel, muted) => `${m}${muted}=$self.isHiddenChannel(${channel})?true:${muted};`
|
||||||
},
|
},
|
||||||
// Add the hidden eye icon if the channel is hidden
|
// Add the hidden eye icon if the channel is hidden
|
||||||
|
@ -204,7 +204,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
// Hide unreads
|
// Hide unreads
|
||||||
predicate: () => settings.store.hideUnreads === true,
|
predicate: () => settings.store.hideUnreads === true,
|
||||||
match: /{channel:(\i),name:\i,.+?unread:(\i).+?;/,
|
match: /\.subtitle,.+?;(?=return\(0,\i\.jsxs?\))(?<={channel:(\i),name:\i,.+?unread:(\i).+?)/,
|
||||||
replace: (m, channel, unread) => `${m}${unread}=$self.isHiddenChannel(${channel})?false:${unread};`
|
replace: (m, channel, unread) => `${m}${unread}=$self.isHiddenChannel(${channel})?false:${unread};`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -485,7 +485,7 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: '="NowPlayingViewStore",',
|
find: '"NowPlayingViewStore"',
|
||||||
replacement: {
|
replacement: {
|
||||||
// Make active now voice states on hidden channels
|
// Make active now voice states on hidden channels
|
||||||
match: /(getVoiceStateForUser.{0,150}?)&&\i\.\i\.canWithPartialContext.{0,20}VIEW_CHANNEL.+?}\)(?=\?)/,
|
match: /(getVoiceStateForUser.{0,150}?)&&\i\.\i\.canWithPartialContext.{0,20}VIEW_CHANNEL.+?}\)(?=\?)/,
|
||||||
|
|
|
@ -77,7 +77,7 @@ export const SpotifyStore = proxyLazyWebpack(() => {
|
||||||
|
|
||||||
class SpotifyStore extends Store {
|
class SpotifyStore extends Store {
|
||||||
public mPosition = 0;
|
public mPosition = 0;
|
||||||
private start = 0;
|
public _start = 0;
|
||||||
|
|
||||||
public track: Track | null = null;
|
public track: Track | null = null;
|
||||||
public device: Device | null = null;
|
public device: Device | null = null;
|
||||||
|
@ -100,26 +100,26 @@ export const SpotifyStore = proxyLazyWebpack(() => {
|
||||||
public get position(): number {
|
public get position(): number {
|
||||||
let pos = this.mPosition;
|
let pos = this.mPosition;
|
||||||
if (this.isPlaying) {
|
if (this.isPlaying) {
|
||||||
pos += Date.now() - this.start;
|
pos += Date.now() - this._start;
|
||||||
}
|
}
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public set position(p: number) {
|
public set position(p: number) {
|
||||||
this.mPosition = p;
|
this.mPosition = p;
|
||||||
this.start = Date.now();
|
this._start = Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
prev() {
|
prev() {
|
||||||
this.req("post", "/previous");
|
this._req("post", "/previous");
|
||||||
}
|
}
|
||||||
|
|
||||||
next() {
|
next() {
|
||||||
this.req("post", "/next");
|
this._req("post", "/next");
|
||||||
}
|
}
|
||||||
|
|
||||||
setVolume(percent: number) {
|
setVolume(percent: number) {
|
||||||
this.req("put", "/volume", {
|
this._req("put", "/volume", {
|
||||||
query: {
|
query: {
|
||||||
volume_percent: Math.round(percent)
|
volume_percent: Math.round(percent)
|
||||||
}
|
}
|
||||||
|
@ -131,17 +131,17 @@ export const SpotifyStore = proxyLazyWebpack(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
setPlaying(playing: boolean) {
|
setPlaying(playing: boolean) {
|
||||||
this.req("put", playing ? "/play" : "/pause");
|
this._req("put", playing ? "/play" : "/pause");
|
||||||
}
|
}
|
||||||
|
|
||||||
setRepeat(state: Repeat) {
|
setRepeat(state: Repeat) {
|
||||||
this.req("put", "/repeat", {
|
this._req("put", "/repeat", {
|
||||||
query: { state }
|
query: { state }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setShuffle(state: boolean) {
|
setShuffle(state: boolean) {
|
||||||
this.req("put", "/shuffle", {
|
this._req("put", "/shuffle", {
|
||||||
query: { state }
|
query: { state }
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.shuffle = state;
|
this.shuffle = state;
|
||||||
|
@ -154,7 +154,7 @@ export const SpotifyStore = proxyLazyWebpack(() => {
|
||||||
|
|
||||||
this.isSettingPosition = true;
|
this.isSettingPosition = true;
|
||||||
|
|
||||||
return this.req("put", "/seek", {
|
return this._req("put", "/seek", {
|
||||||
query: {
|
query: {
|
||||||
position_ms: Math.round(ms)
|
position_ms: Math.round(ms)
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ export const SpotifyStore = proxyLazyWebpack(() => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private req(method: "post" | "get" | "put", route: string, data: any = {}) {
|
_req(method: "post" | "get" | "put", route: string, data: any = {}) {
|
||||||
if (this.device?.is_active)
|
if (this.device?.is_active)
|
||||||
(data.query ??= {}).device_id = this.device.id;
|
(data.query ??= {}).device_id = this.device.id;
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,22 @@ export default definePlugin({
|
||||||
authors: [Devs.Megu],
|
authors: [Devs.Megu],
|
||||||
patches: [{
|
patches: [{
|
||||||
find: "#{intl::ACTIVITY_SETTINGS}",
|
find: "#{intl::ACTIVITY_SETTINGS}",
|
||||||
replacement: {
|
replacement: [
|
||||||
|
{
|
||||||
|
// FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
|
||||||
match: /(?<=}\)([,;])(\i\.settings)\.forEach.+?(\i)\.push.+}\)}\))/,
|
match: /(?<=}\)([,;])(\i\.settings)\.forEach.+?(\i)\.push.+}\)}\))/,
|
||||||
replace: (_, commaOrSemi, settings, elements) => "" +
|
replace: (_, commaOrSemi, settings, elements) => "" +
|
||||||
`${commaOrSemi}${settings}?.[0]==="CHANGELOG"` +
|
`${commaOrSemi}${settings}?.[0]==="CHANGELOG"` +
|
||||||
`&&${elements}.push({section:"StartupTimings",label:"Startup Timings",element:$self.StartupTimingPage})`
|
`&&${elements}.push({section:"StartupTimings",label:"Startup Timings",element:$self.StartupTimingPage})`,
|
||||||
}
|
noWarn: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
match: /(?<=}\)([,;])(\i\.settings)\.forEach.+?(\i)\.push.+\)\)\}\))(?=\)\})/,
|
||||||
|
replace: (_, commaOrSemi, settings, elements) => "" +
|
||||||
|
`${commaOrSemi}${settings}?.[0]==="CHANGELOG"` +
|
||||||
|
`&&${elements}.push({section:"StartupTimings",label:"Startup Timings",element:$self.StartupTimingPage})`,
|
||||||
|
},
|
||||||
|
]
|
||||||
}],
|
}],
|
||||||
StartupTimingPage
|
StartupTimingPage
|
||||||
});
|
});
|
||||||
|
|
|
@ -41,11 +41,20 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: '="SYSTEM_TAG"',
|
find: '="SYSTEM_TAG"',
|
||||||
replacement: {
|
replacement: [
|
||||||
|
{
|
||||||
// Add next to username (compact mode)
|
// Add next to username (compact mode)
|
||||||
|
// FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
|
||||||
match: /className:\i\(\)\(\i\.className(?:,\i\.clickable)?,\i\)}\),(?=\i)/g,
|
match: /className:\i\(\)\(\i\.className(?:,\i\.clickable)?,\i\)}\),(?=\i)/g,
|
||||||
replace: "$&$self.CompactPronounsChatComponentWrapper(arguments[0]),"
|
replace: "$&$self.CompactPronounsChatComponentWrapper(arguments[0]),",
|
||||||
}
|
noWarn: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Add next to username (compact mode)
|
||||||
|
match: /className:\i\(\)\(\i\.className(?:,\i\.clickable)?,\i\)}\)\),(?=\i)/g,
|
||||||
|
replace: "$&$self.CompactPronounsChatComponentWrapper(arguments[0]),",
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ function VoiceChannelTooltip({ channel, isLocked }: VoiceChannelTooltipProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VoiceChannelIndicatorProps {
|
export interface VoiceChannelIndicatorProps {
|
||||||
userId: string;
|
userId: string;
|
||||||
isActionButton?: boolean;
|
isActionButton?: boolean;
|
||||||
shouldHighlight?: boolean;
|
shouldHighlight?: boolean;
|
||||||
|
|
|
@ -193,10 +193,18 @@ export default definePlugin({
|
||||||
// Avatar component used in User DMs "User Profile" popup in the right and Profiles Modal pfp
|
// Avatar component used in User DMs "User Profile" popup in the right and Profiles Modal pfp
|
||||||
{
|
{
|
||||||
find: ".overlay:void 0,status:",
|
find: ".overlay:void 0,status:",
|
||||||
replacement: {
|
replacement: [
|
||||||
|
{
|
||||||
|
// FIXME(Bundler spread transform related): Remove old compatiblity once enough time has passed, if they don't revert
|
||||||
match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",{...\2,/,
|
match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",{...\2,/,
|
||||||
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openAvatar($1)},"
|
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openAvatar($1)},",
|
||||||
|
noWarn: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",.{0,100}className:\i,/,
|
||||||
|
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openAvatar($1)},",
|
||||||
|
}
|
||||||
|
],
|
||||||
all: true
|
all: true
|
||||||
},
|
},
|
||||||
// Banners
|
// Banners
|
||||||
|
|
|
@ -10,7 +10,7 @@ import adguard from "file://adguard.js?minify";
|
||||||
|
|
||||||
app.on("browser-window-created", (_, win) => {
|
app.on("browser-window-created", (_, win) => {
|
||||||
win.webContents.on("frame-created", (_, { frame }) => {
|
win.webContents.on("frame-created", (_, { frame }) => {
|
||||||
frame.once("dom-ready", () => {
|
frame?.once("dom-ready", () => {
|
||||||
if (!RendererSettings.store.plugins?.YoutubeAdblock?.enabled) return;
|
if (!RendererSettings.store.plugins?.YoutubeAdblock?.enabled) return;
|
||||||
|
|
||||||
if (frame.url.includes("youtube.com/embed/") || (frame.url.includes("discordsays") && frame.url.includes("youtube.com"))) {
|
if (frame.url.includes("youtube.com/embed/") || (frame.url.includes("discordsays") && frame.url.includes("youtube.com"))) {
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
@media(width <= 485px) {
|
@media(width <= 485px) {
|
||||||
.vc-image-modal {
|
.vc-image-modal {
|
||||||
display: relative;
|
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
overflow: initial;
|
overflow: initial;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ export function makeLazy<T>(factory: () => T, attempts = 5): () => T {
|
||||||
let tries = 0;
|
let tries = 0;
|
||||||
let cache: T;
|
let cache: T;
|
||||||
return () => {
|
return () => {
|
||||||
if (!cache && attempts > tries++) {
|
if (cache === undefined && attempts > tries++) {
|
||||||
cache = factory();
|
cache = factory();
|
||||||
if (!cache && attempts === tries)
|
if (cache === undefined && attempts === tries)
|
||||||
console.error("Lazy factory failed:", factory);
|
console.error("Lazy factory failed:", factory);
|
||||||
}
|
}
|
||||||
return cache;
|
return cache;
|
||||||
|
|
|
@ -41,7 +41,12 @@ export interface PatchReplacement {
|
||||||
match: string | RegExp;
|
match: string | RegExp;
|
||||||
/** The replacement string or function which returns the string for the patch replacement */
|
/** The replacement string or function which returns the string for the patch replacement */
|
||||||
replace: string | ReplaceFn;
|
replace: string | ReplaceFn;
|
||||||
/** A function which returns whether this patch replacement should be applied */
|
/** Do not warn if this replacement did no changes */
|
||||||
|
noWarn?: boolean;
|
||||||
|
/**
|
||||||
|
* A function which returns whether this patch replacement should be applied.
|
||||||
|
* This is ran before patches are registered, so if this returns false, the patch will never be registered.
|
||||||
|
*/
|
||||||
predicate?(): boolean;
|
predicate?(): boolean;
|
||||||
/** The minimum build number for this patch to be applied */
|
/** The minimum build number for this patch to be applied */
|
||||||
fromBuild?: number;
|
fromBuild?: number;
|
||||||
|
@ -61,7 +66,10 @@ export interface Patch {
|
||||||
noWarn?: boolean;
|
noWarn?: boolean;
|
||||||
/** Only apply this set of replacements if all of them succeed. Use this if your replacements depend on each other */
|
/** Only apply this set of replacements if all of them succeed. Use this if your replacements depend on each other */
|
||||||
group?: boolean;
|
group?: boolean;
|
||||||
/** A function which returns whether this patch should be applied */
|
/**
|
||||||
|
* A function which returns whether this patch replacement should be applied.
|
||||||
|
* This is ran before patches are registered, so if this returns false, the patch will never be registered.
|
||||||
|
*/
|
||||||
predicate?(): boolean;
|
predicate?(): boolean;
|
||||||
/** The minimum build number for this patch to be applied */
|
/** The minimum build number for this patch to be applied */
|
||||||
fromBuild?: number;
|
fromBuild?: number;
|
||||||
|
|
|
@ -41,7 +41,7 @@ export const Switch = waitForComponent<t.Switch>("Switch", filters.componentByCo
|
||||||
|
|
||||||
const Tooltips = mapMangledModuleLazy(".tooltipTop,bottom:", {
|
const Tooltips = mapMangledModuleLazy(".tooltipTop,bottom:", {
|
||||||
Tooltip: filters.componentByCode("this.renderTooltip()]"),
|
Tooltip: filters.componentByCode("this.renderTooltip()]"),
|
||||||
TooltipContainer: filters.componentByCode('="div",')
|
TooltipContainer: filters.componentByCode('="div"')
|
||||||
}) as {
|
}) as {
|
||||||
Tooltip: t.Tooltip,
|
Tooltip: t.Tooltip,
|
||||||
TooltipContainer: t.TooltipContainer;
|
TooltipContainer: t.TooltipContainer;
|
||||||
|
|
|
@ -29,7 +29,7 @@ export type GenericStore = t.FluxStore & Record<string, any>;
|
||||||
|
|
||||||
export const DraftType = findByPropsLazy("ChannelMessage", "SlashCommand");
|
export const DraftType = findByPropsLazy("ChannelMessage", "SlashCommand");
|
||||||
|
|
||||||
export let MessageStore: Omit<Stores.MessageStore, "getMessages"> & {
|
export let MessageStore: Omit<Stores.MessageStore, "getMessages"> & GenericStore & {
|
||||||
getMessages(chanId: string): any;
|
getMessages(chanId: string): any;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
2
src/webpack/common/types/components.d.ts
vendored
2
src/webpack/common/types/components.d.ts
vendored
|
@ -496,7 +496,7 @@ export type Avatar = ComponentType<PropsWithChildren<{
|
||||||
}>>;
|
}>>;
|
||||||
|
|
||||||
type FocusLock = ComponentType<PropsWithChildren<{
|
type FocusLock = ComponentType<PropsWithChildren<{
|
||||||
containerRef: RefObject<HTMLElement>;
|
containerRef: Ref<HTMLElement>;
|
||||||
}>>;
|
}>>;
|
||||||
|
|
||||||
export type Icon = ComponentType<JSX.IntrinsicElements["svg"] & {
|
export type Icon = ComponentType<JSX.IntrinsicElements["svg"] & {
|
||||||
|
|
3
src/webpack/common/types/stores.d.ts
vendored
3
src/webpack/common/types/stores.d.ts
vendored
|
@ -16,7 +16,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DraftType } from "@webpack/common";
|
|
||||||
import { Channel, Guild, Role } from "discord-types/general";
|
import { Channel, Guild, Role } from "discord-types/general";
|
||||||
|
|
||||||
import { FluxDispatcher, FluxEvents } from "./utils";
|
import { FluxDispatcher, FluxEvents } from "./utils";
|
||||||
|
@ -229,7 +228,7 @@ export class ThemeStore extends FluxStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type useStateFromStores = <T>(
|
export type useStateFromStores = <T>(
|
||||||
stores: t.FluxStore[],
|
stores: any[],
|
||||||
mapper: () => T,
|
mapper: () => T,
|
||||||
dependencies?: any,
|
dependencies?: any,
|
||||||
isEqual?: (old: T, newer: T) => boolean
|
isEqual?: (old: T, newer: T) => boolean
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { runtimeHashMessageKey } from "@utils/intlHash";
|
|
||||||
import type { Channel } from "discord-types/general";
|
import type { Channel } from "discord-types/general";
|
||||||
|
|
||||||
// eslint-disable-next-line path-alias/no-relative
|
// eslint-disable-next-line path-alias/no-relative
|
||||||
|
@ -58,8 +57,8 @@ export const { match, P }: Pick<typeof import("ts-pattern"), "match" | "P"> = ma
|
||||||
export const lodash: typeof import("lodash") = findByPropsLazy("debounce", "cloneDeep");
|
export const lodash: typeof import("lodash") = findByPropsLazy("debounce", "cloneDeep");
|
||||||
|
|
||||||
export const i18n = mapMangledModuleLazy('defaultLocale:"en-US"', {
|
export const i18n = mapMangledModuleLazy('defaultLocale:"en-US"', {
|
||||||
t: filters.byProps(runtimeHashMessageKey("DISCORD")),
|
t: m => m?.[Symbol.toStringTag] === "IntlMessagesProxy",
|
||||||
intl: filters.byProps("string", "format"),
|
intl: m => m != null && Object.getPrototypeOf(m)?.withFormatters != null
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
export let SnowflakeUtils: t.SnowflakeUtils;
|
export let SnowflakeUtils: t.SnowflakeUtils;
|
||||||
|
|
|
@ -12,8 +12,8 @@ import { canonicalizeReplacement } from "@utils/patches";
|
||||||
import { Patch, PatchReplacement } from "@utils/types";
|
import { Patch, PatchReplacement } from "@utils/types";
|
||||||
|
|
||||||
import { traceFunctionWithResults } from "../debug/Tracer";
|
import { traceFunctionWithResults } from "../debug/Tracer";
|
||||||
import { _blacklistBadModules, _initWebpack, factoryListeners, findModuleId, moduleListeners, waitForSubscriptions, wreq } from "./webpack";
|
import { _blacklistBadModules, _initWebpack, factoryListeners, findModuleFactory, moduleListeners, waitForSubscriptions, wreq } from "./webpack";
|
||||||
import { AnyModuleFactory, AnyWebpackRequire, MaybePatchedModuleFactory, ModuleExports, PatchedModuleFactory, WebpackRequire } from "./wreq.d";
|
import { AnyModuleFactory, AnyWebpackRequire, MaybePatchedModuleFactory, PatchedModuleFactory, WebpackRequire } from "./wreq.d";
|
||||||
|
|
||||||
export const patches = [] as Patch[];
|
export const patches = [] as Patch[];
|
||||||
|
|
||||||
|
@ -27,28 +27,26 @@ export const patchTimings = [] as Array<[plugin: string, moduleId: PropertyKey,
|
||||||
|
|
||||||
export const getBuildNumber = makeLazy(() => {
|
export const getBuildNumber = makeLazy(() => {
|
||||||
try {
|
try {
|
||||||
try {
|
function matchBuildNumber(factoryStr: string) {
|
||||||
if (wreq.m[128014]?.toString().includes("Trying to open a changelog for an invalid build number")) {
|
const buildNumberMatch = factoryStr.match(/.concat\("(\d+?)"\)/);
|
||||||
const hardcodedGetBuildNumber = wreq(128014).b as () => number;
|
if (buildNumberMatch == null) {
|
||||||
|
|
||||||
if (typeof hardcodedGetBuildNumber === "function" && typeof hardcodedGetBuildNumber() === "number") {
|
|
||||||
return hardcodedGetBuildNumber();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch { }
|
|
||||||
|
|
||||||
const moduleId = findModuleId("Trying to open a changelog for an invalid build number");
|
|
||||||
if (moduleId == null) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const exports = Object.values<ModuleExports>(wreq(moduleId));
|
return Number(buildNumberMatch[1]);
|
||||||
if (exports.length !== 1 || typeof exports[0] !== "function") {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildNumber = exports[0]();
|
const hardcodedFactoryStr = String(wreq.m[128014]);
|
||||||
return typeof buildNumber === "number" ? buildNumber : -1;
|
if (hardcodedFactoryStr.includes("Trying to open a changelog for an invalid build number")) {
|
||||||
|
const hardcodedBuildNumber = matchBuildNumber(hardcodedFactoryStr);
|
||||||
|
|
||||||
|
if (hardcodedBuildNumber !== -1) {
|
||||||
|
return hardcodedBuildNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleFactory = findModuleFactory("Trying to open a changelog for an invalid build number");
|
||||||
|
return matchBuildNumber(String(moduleFactory));
|
||||||
} catch {
|
} catch {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -122,12 +120,12 @@ define(Function.prototype, "m", {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
patchThisInstance();
|
|
||||||
|
|
||||||
if (wreq == null && this.c != null) {
|
if (wreq == null && this.c != null) {
|
||||||
logger.info("Main WebpackInstance found" + interpolateIfDefined` in ${fileName}` + ", initializing internal references to WebpackRequire");
|
logger.info("Main WebpackInstance found" + interpolateIfDefined` in ${fileName}` + ", initializing internal references to WebpackRequire");
|
||||||
_initWebpack(this as WebpackRequire);
|
_initWebpack(this as WebpackRequire);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
patchThisInstance();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -193,13 +191,13 @@ define(Function.prototype, "m", {
|
||||||
|
|
||||||
// Overwrite Webpack's defineExports function to define the export descriptors configurable.
|
// Overwrite Webpack's defineExports function to define the export descriptors configurable.
|
||||||
// This is needed so we can later blacklist specific exports from Webpack search by making them non-enumerable
|
// This is needed so we can later blacklist specific exports from Webpack search by making them non-enumerable
|
||||||
this.d = function (exports: object, getters: object) {
|
this.d = function (exports, definition) {
|
||||||
for (const key in getters) {
|
for (const key in definition) {
|
||||||
if (Object.hasOwn(getters, key) && !Object.hasOwn(exports, key)) {
|
if (Object.hasOwn(definition, key) && !Object.hasOwn(exports, key)) {
|
||||||
Object.defineProperty(exports, key, {
|
Object.defineProperty(exports, key, {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
get: getters[key],
|
get: definition[key],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,11 +295,6 @@ function updateExistingFactory(moduleFactories: AnyWebpackRequire["m"], moduleId
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingFactory != null) {
|
if (existingFactory != null) {
|
||||||
// Sanity check to make sure these factories are equal
|
|
||||||
if (String(newFactory) !== String(existingFactory)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If existingFactory exists in any of the Webpack instances we track, it's either wrapped in our proxy, or it has already been required.
|
// If existingFactory exists in any of the Webpack instances we track, it's either wrapped in our proxy, or it has already been required.
|
||||||
// In the case it is wrapped in our proxy, and the instance we are setting does not already have it, we need to make sure the instance contains our proxy too.
|
// In the case it is wrapped in our proxy, and the instance we are setting does not already have it, we need to make sure the instance contains our proxy too.
|
||||||
if (moduleFactoriesWithFactory !== moduleFactories && existingFactory[SYM_IS_PROXIED_FACTORY]) {
|
if (moduleFactoriesWithFactory !== moduleFactories && existingFactory[SYM_IS_PROXIED_FACTORY]) {
|
||||||
|
@ -417,9 +410,6 @@ function runFactoryWithWrap(patchedFactory: PatchedModuleFactory, thisArg: unkno
|
||||||
}
|
}
|
||||||
|
|
||||||
exports = module.exports;
|
exports = module.exports;
|
||||||
if (exports == null) {
|
|
||||||
return factoryReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof require === "function" && require.c) {
|
if (typeof require === "function" && require.c) {
|
||||||
if (_blacklistBadModules(require.c, exports, module.id)) {
|
if (_blacklistBadModules(require.c, exports, module.id)) {
|
||||||
|
@ -427,6 +417,10 @@ function runFactoryWithWrap(patchedFactory: PatchedModuleFactory, thisArg: unkno
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (exports == null) {
|
||||||
|
return factoryReturn;
|
||||||
|
}
|
||||||
|
|
||||||
for (const callback of moduleListeners) {
|
for (const callback of moduleListeners) {
|
||||||
try {
|
try {
|
||||||
callback(exports, module.id);
|
callback(exports, module.id);
|
||||||
|
@ -482,23 +476,23 @@ function patchFactory(moduleId: PropertyKey, originalFactory: AnyModuleFactory):
|
||||||
for (let i = 0; i < patches.length; i++) {
|
for (let i = 0; i < patches.length; i++) {
|
||||||
const patch = patches[i];
|
const patch = patches[i];
|
||||||
|
|
||||||
const moduleMatches = typeof patch.find === "string"
|
const buildNumber = getBuildNumber();
|
||||||
? code.includes(patch.find)
|
const shouldCheckBuildNumber = buildNumber !== -1;
|
||||||
: (patch.find.global && (patch.find.lastIndex = 0), patch.find.test(code));
|
|
||||||
|
|
||||||
if (!moduleMatches) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eager patches cannot retrieve the build number because this code runs before the module for it is loaded
|
|
||||||
const buildNumber = Settings.eagerPatches ? -1 : getBuildNumber();
|
|
||||||
const shouldCheckBuildNumber = !Settings.eagerPatches && buildNumber !== -1;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
shouldCheckBuildNumber &&
|
shouldCheckBuildNumber &&
|
||||||
(patch.fromBuild != null && buildNumber < patch.fromBuild) ||
|
(patch.fromBuild != null && buildNumber < patch.fromBuild) ||
|
||||||
(patch.toBuild != null && buildNumber > patch.toBuild)
|
(patch.toBuild != null && buildNumber > patch.toBuild)
|
||||||
) {
|
) {
|
||||||
|
patches.splice(i--, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleMatches = typeof patch.find === "string"
|
||||||
|
? code.includes(patch.find)
|
||||||
|
: (patch.find.global && (patch.find.lastIndex = 0), patch.find.test(code));
|
||||||
|
|
||||||
|
if (!moduleMatches) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,7 +534,7 @@ function patchFactory(moduleId: PropertyKey, originalFactory: AnyModuleFactory):
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newCode === code) {
|
if (newCode === code) {
|
||||||
if (!patch.noWarn) {
|
if (!(patch.noWarn || replacement.noWarn)) {
|
||||||
logger.warn(`Patch by ${patch.plugin} had no effect (Module id is ${String(moduleId)}): ${replacement.match}`);
|
logger.warn(`Patch by ${patch.plugin} had no effect (Module id is ${String(moduleId)}): ${replacement.match}`);
|
||||||
if (IS_DEV) {
|
if (IS_DEV) {
|
||||||
logger.debug("Function Source:\n", code);
|
logger.debug("Function Source:\n", code);
|
||||||
|
@ -562,8 +556,13 @@ function patchFactory(moduleId: PropertyKey, originalFactory: AnyModuleFactory):
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pluginsList = [...patchedBy];
|
||||||
|
if (!patchedBy.has(patch.plugin)) {
|
||||||
|
pluginsList.push(patch.plugin);
|
||||||
|
}
|
||||||
|
|
||||||
code = newCode;
|
code = newCode;
|
||||||
patchedSource = `// Webpack Module ${String(moduleId)} - Patched by ${[...patchedBy, patch.plugin].join(", ")}\n${newCode}\n//# sourceURL=WebpackModule${String(moduleId)}`;
|
patchedSource = `// Webpack Module ${String(moduleId)} - Patched by ${pluginsList.join(", ")}\n${newCode}\n//# sourceURL=WebpackModule${String(moduleId)}`;
|
||||||
patchedFactory = (0, eval)(patchedSource);
|
patchedFactory = (0, eval)(patchedSource);
|
||||||
|
|
||||||
if (!patchedBy.has(patch.plugin)) {
|
if (!patchedBy.has(patch.plugin)) {
|
||||||
|
|
|
@ -131,7 +131,7 @@ function shouldIgnoreValue(value: any) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePropertyNonEnumerable(target: Object, key: PropertyKey) {
|
function makePropertyNonEnumerable(target: Record<PropertyKey, any>, key: PropertyKey) {
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
||||||
if (descriptor == null) return;
|
if (descriptor == null) return;
|
||||||
|
|
||||||
|
@ -499,12 +499,12 @@ export function findExportedComponentLazy<T extends object = any>(...props: Prop
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAllPropertyNames(object: Object, includeNonEnumerable: boolean) {
|
function getAllPropertyNames(object: Record<PropertyKey, any>, includeNonEnumerable: boolean) {
|
||||||
const names = new Set<PropertyKey>();
|
const names = new Set<PropertyKey>();
|
||||||
|
|
||||||
const getKeys = includeNonEnumerable ? Object.getOwnPropertyNames : Object.keys;
|
const getKeys = includeNonEnumerable ? Object.getOwnPropertyNames : Object.keys;
|
||||||
do {
|
do {
|
||||||
getKeys(object).forEach(name => names.add(name));
|
getKeys(object).forEach(name => name !== "__esModule" && names.add(name));
|
||||||
object = Object.getPrototypeOf(object);
|
object = Object.getPrototypeOf(object);
|
||||||
} while (object != null);
|
} while (object != null);
|
||||||
|
|
||||||
|
|
13
src/webpack/wreq.d.ts
vendored
13
src/webpack/wreq.d.ts
vendored
|
@ -17,14 +17,11 @@ export type Module = {
|
||||||
/** exports can be anything, however initially it is always an empty object */
|
/** exports can be anything, however initially it is always an empty object */
|
||||||
export type ModuleFactory = (this: ModuleExports, module: Module, exports: ModuleExports, require: WebpackRequire) => void;
|
export type ModuleFactory = (this: ModuleExports, module: Module, exports: ModuleExports, require: WebpackRequire) => void;
|
||||||
|
|
||||||
export type WebpackQueues = unique symbol | "__webpack_queues__";
|
/** Keys here can be symbols too, but we can't properly type them */
|
||||||
export type WebpackExports = unique symbol | "__webpack_exports__";
|
|
||||||
export type WebpackError = unique symbol | "__webpack_error__";
|
|
||||||
|
|
||||||
export type AsyncModulePromise = Promise<ModuleExports> & {
|
export type AsyncModulePromise = Promise<ModuleExports> & {
|
||||||
[WebpackQueues]: (fnQueue: ((queue: any[]) => any)) => any;
|
"__webpack_queues__": (fnQueue: ((queue: any[]) => any)) => any;
|
||||||
[WebpackExports]: ModuleExports;
|
"__webpack_exports__": ModuleExports;
|
||||||
[WebpackError]?: any;
|
"__webpack_error__"?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AsyncModuleBody = (
|
export type AsyncModuleBody = (
|
||||||
|
@ -152,7 +149,7 @@ export type WebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & {
|
||||||
* }
|
* }
|
||||||
* // exports is now { exportName: someExportedValue } (but each value is actually a getter)
|
* // exports is now { exportName: someExportedValue } (but each value is actually a getter)
|
||||||
*/
|
*/
|
||||||
d: (this: WebpackRequire, exports: AnyRecord, definiton: AnyRecord) => void;
|
d: (this: WebpackRequire, exports: Record<PropertyKey, any>, definiton: Record<PropertyKey, () => ModuleExports>) => void;
|
||||||
/** The ensure chunk handlers, which are used to ensure the files of the chunks are loaded, or load if necessary */
|
/** The ensure chunk handlers, which are used to ensure the files of the chunks are loaded, or load if necessary */
|
||||||
f: EnsureChunkHandlers;
|
f: EnsureChunkHandlers;
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue