From 77084203c6ff51d1a484bb22ba57cf7017d647ad Mon Sep 17 00:00:00 2001 From: dorkbutt Date: Fri, 6 Jun 2025 12:20:47 -0400 Subject: [PATCH 01/25] fork init --- src/plugins/other-usrbg/index.tsx | 120 +++++++++++++++++++++++++++++ src/plugins/other-usrbg/users.json | 6 ++ 2 files changed, 126 insertions(+) create mode 100644 src/plugins/other-usrbg/index.tsx create mode 100644 src/plugins/other-usrbg/users.json diff --git a/src/plugins/other-usrbg/index.tsx b/src/plugins/other-usrbg/index.tsx new file mode 100644 index 00000000..d77e8780 --- /dev/null +++ b/src/plugins/other-usrbg/index.tsx @@ -0,0 +1,120 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2023 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import { definePluginSettings } from "@api/Settings"; +import { Link } from "@components/Link"; +import { Devs } from "@utils/constants"; +import definePlugin, { OptionType } from "@utils/types"; + +const API_URL = "https://usrbg.dorkbutt.lol/users/users.json"; + +interface UsrbgApiReturn { + endpoint: string; + bucket: string; + prefix: string; + users: Record; +} + +const settings = definePluginSettings({ + nitroFirst: { + description: "Banner to use if both Nitro and USRBG banners are present", + type: OptionType.SELECT, + options: [ + { label: "Nitro banner", value: true, default: true }, + { label: "USRBG banner", value: false }, + ] + }, + voiceBackground: { + description: "Use USRBG banners as voice chat backgrounds", + type: OptionType.BOOLEAN, + default: true, + restartNeeded: true + } +}); + +export default definePlugin({ + name: "FORKED - USRBG", + description: "Displays user banners from dorkbutt's USRBG server, allowing anyone to get a banner without Nitro", + authors: [Devs.dorkbutt, Devs.AutumnVN, Devs.katlyn, Devs.pylix, Devs.TheKodeToad], + settings, + patches: [ + { + find: '.banner)==null?"COMPLETE"', + replacement: { + match: /(?<=void 0:)\i.getPreviewBanner\(\i,\i,\i\)/, + replace: "$self.patchBannerUrl(arguments[0])||$&" + + } + }, + { + find: "\"data-selenium-video-tile\":", + predicate: () => settings.store.voiceBackground, + replacement: [ + { + match: /(?<=function\((\i),\i\)\{)(?=let.{20,40},style:)/, + replace: "$1.style=$self.getVoiceBackgroundStyles($1);" + } + ] + } + ], + + data: null as UsrbgApiReturn | null, + + settingsAboutComponent: () => { + return ( + "Message @dorkbutt about getting your personal banner added!" + ); + }, + + getVoiceBackgroundStyles({ className, participantUserId }: any) { + if (className.includes("tile_")) { + if (this.userHasBackground(participantUserId)) { + return { + backgroundImage: `url(${this.getImageUrl(participantUserId)})`, + backgroundSize: "cover", + backgroundPosition: "center", + backgroundRepeat: "no-repeat" + }; + } + } + }, + + patchBannerUrl({ displayProfile }: any) { + if (displayProfile?.banner && settings.store.nitroFirst) return; + if (this.userHasBackground(displayProfile?.userId)) return this.getImageUrl(displayProfile?.userId); + }, + + userHasBackground(userId: string) { + return !!this.data?.users[userId]; + }, + + getImageUrl(userId: string): string | null { + if (!this.userHasBackground(userId)) return null; + + // We can assert that data exists because userHasBackground returned true + const { endpoint, bucket, prefix, users: { [userId]: etag } } = this.data!; + return `${endpoint}/${bucket}/${prefix}${userId}?${etag}`; + }, + + async start() { + const res = await fetch(API_URL); + if (res.ok) { + this.data = await res.json(); + } + } +}); diff --git a/src/plugins/other-usrbg/users.json b/src/plugins/other-usrbg/users.json new file mode 100644 index 00000000..9ac83479 --- /dev/null +++ b/src/plugins/other-usrbg/users.json @@ -0,0 +1,6 @@ +{"endpoint":"https://usrbg.dorkbutt.lol","bucket":"usrbg","prefix":"v2/", + "users":{ + "862105885660676146":"db1d", + "578012873813524530":"315c" + } +} From acccc963ae18024412fa7b8f0f1210c78be92d54 Mon Sep 17 00:00:00 2001 From: dorkbutt Date: Fri, 6 Jun 2025 13:00:30 -0400 Subject: [PATCH 02/25] please work --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 61575d4b..3a2b1492 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +# A fork. A fork. We're a fork. + + # Vencord [![Codeberg Mirror](https://img.shields.io/static/v1?style=for-the-badge&label=Codeberg%20Mirror&message=codeberg.org/Vee/cord&color=2185D0&logo=data:image/png;base64,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)](https://codeberg.org/Vee/cord) From 741af9eb43f0daa2e37aeea91dbf75ab8e0ec366 Mon Sep 17 00:00:00 2001 From: dorkbutt Date: Fri, 6 Jun 2025 13:07:45 -0400 Subject: [PATCH 03/25] changed branches. --- .github/ISSUE_TEMPLATE/blank.yml | 25 ------ .github/ISSUE_TEMPLATE/bug_report.yml | 66 -------------- .github/ISSUE_TEMPLATE/config.yml | 8 -- .github/ISSUE_TEMPLATE/developer-banner.png | Bin 31992 -> 0 bytes .github/workflows/build.yml | 80 ----------------- .github/workflows/codeberg-mirror.yml | 22 ----- .github/workflows/publish.yml | 45 ---------- .github/workflows/reportBrokenPlugins.yml | 95 -------------------- .github/workflows/test.yml | 32 ------- 9 files changed, 373 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/blank.yml delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/developer-banner.png delete mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/codeberg-mirror.yml delete mode 100644 .github/workflows/publish.yml delete mode 100644 .github/workflows/reportBrokenPlugins.yml delete mode 100644 .github/workflows/test.yml diff --git a/.github/ISSUE_TEMPLATE/blank.yml b/.github/ISSUE_TEMPLATE/blank.yml deleted file mode 100644 index 89588f3d..00000000 --- a/.github/ISSUE_TEMPLATE/blank.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Blank Issue -description: Create a blank issue. ALWAYS FIRST USE OUR SUPPORT CHANNEL! ONLY USE THIS FORM IF YOU ARE A CONTRIBUTOR OR WERE TOLD TO DO SO IN THE SUPPORT CHANNEL. - -body: - - type: markdown - attributes: - value: | - ![Are you a developer? No? This form is not for you!](https://github.com/Vendicated/Vencord/blob/main/.github/ISSUE_TEMPLATE/developer-banner.png?raw=true) - - GitHub Issues are for development, not support! Please use our [support server](https://vencord.dev/discord) unless you are a Vencord Developer. - - - type: textarea - id: content - attributes: - label: Content - validations: - required: true - - - type: checkboxes - id: agreement-check - attributes: - label: Request Agreement - options: - - label: I have read the requirements for opening an issue above - required: true diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index c08f4635..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: Bug/Crash Report -description: Create a bug or crash report for Vencord. ALWAYS FIRST USE OUR SUPPORT CHANNEL! ONLY USE THIS FORM IF YOU ARE A CONTRIBUTOR OR WERE TOLD TO DO SO IN THE SUPPORT CHANNEL. -labels: [bug] -title: "[Bug] " - -body: - - type: markdown - attributes: - value: | - ![Are you a developer? No? This form is not for you!](https://github.com/Vendicated/Vencord/blob/main/.github/ISSUE_TEMPLATE/developer-banner.png?raw=true) - - GitHub Issues are for development, not support! Please use our [support server](https://vencord.dev/discord) unless you are a Vencord Developer. - - - type: textarea - id: bug-description - attributes: - label: What happens when the bug or crash occurs? - description: Where does this bug or crash occur, when does it occur, etc. - placeholder: The bug/crash happens sometimes when I do ..., causing this to not work/the app to crash. I think it happens because of ... - validations: - required: true - - - type: textarea - id: expected-behaviour - attributes: - label: What is the expected behaviour? - description: Simply detail what the expected behaviour is. - placeholder: I expect Vencord/Discord to open the ... page instead of ..., it prevents me from doing ... - validations: - required: true - - - type: textarea - id: steps-to-take - attributes: - label: How do you recreate this bug or crash? - description: Give us a list of steps in order to recreate the bug or crash. - placeholder: | - 1. Do ... - 2. Then ... - 3. Do this ..., ... and then ... - 4. Observe "the bug" or "the crash" - validations: - required: true - - - type: textarea - id: crash-log - attributes: - label: Errors - description: Open the Developer Console with Ctrl/Cmd + Shift + i. Then look for any red errors (Ignore network errors like Failed to load resource) and paste them between the "```". - value: | - ``` - Replace this text with your crash-log. - ``` - validations: - required: false - - - type: checkboxes - id: agreement-check - attributes: - label: Request Agreement - description: We only accept reports for bugs that happen on Discord Stable. Canary and PTB are Development branches and may be unstable - options: - - label: I am using Discord Stable or tried on Stable and this bug happens there as well - required: true - - label: I am a Vencord Developer - required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index bc5d9766..00000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,8 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Vencord Support Server - url: https://discord.gg/D9uwnFnqmd - about: If you need help regarding Vencord, please join our support server! - - name: Vencord Installer - url: https://github.com/Vencord/Installer - about: You can find the Vencord Installer here diff --git a/.github/ISSUE_TEMPLATE/developer-banner.png b/.github/ISSUE_TEMPLATE/developer-banner.png deleted file mode 100644 index 5fa12fc370750c460f8d0959d5f73828c63b6e3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31992 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 WKXLqM0$yeQOioH!vP#@2=>GuWUFmuN diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index b1cbc302..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Build DevBuild -on: - push: - branches: - - main - paths: - - .github/workflows/build.yml - - src/** - - browser/** - - scripts/build/** - - package.json - - pnpm-lock.yaml -env: - FORCE_COLOR: true - -jobs: - Build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json - - - name: Use Node.js 20 - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: "pnpm" - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build web - run: pnpm buildWebStandalone - - - name: Build - run: pnpm build --standalone - - - name: Generate plugin list - run: pnpm generatePluginJson dist/plugins.json dist/plugin-readmes.json - - - name: Clean up obsolete files - run: | - rm -rf dist/*-unpacked dist/vendor Vencord.user.css vencordDesktopRenderer.css vencordDesktopRenderer.css.map - - - name: Get some values needed for the release - id: release_values - run: | - echo "release_tag=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - - - name: Upload DevBuild as release - if: github.repository == 'Vendicated/Vencord' - run: | - gh release upload devbuild --clobber dist/* - gh release edit devbuild --title "DevBuild $RELEASE_TAG" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RELEASE_TAG: ${{ env.release_tag }} - - - name: Upload DevBuild to builds repo - if: github.repository == 'Vendicated/Vencord' - run: | - git config --global user.name "$USERNAME" - git config --global user.email actions@github.com - - git clone https://$USERNAME:$API_TOKEN@github.com/$GH_REPO.git upload - cd upload - - GLOBIGNORE=.git:.gitignore:README.md:LICENSE - rm -rf * - cp -r ../dist/* . - - git add -A - git commit -m "Builds for https://github.com/$GITHUB_REPOSITORY/commit/$GITHUB_SHA" - git push --force https://$USERNAME:$API_TOKEN@github.com/$GH_REPO.git - env: - API_TOKEN: ${{ secrets.BUILDS_TOKEN }} - GH_REPO: Vencord/builds - USERNAME: GitHub-Actions diff --git a/.github/workflows/codeberg-mirror.yml b/.github/workflows/codeberg-mirror.yml deleted file mode 100644 index 5acae6a4..00000000 --- a/.github/workflows/codeberg-mirror.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Sync to Codeberg -concurrency: - group: ${{ github.ref }} - cancel-in-progress: true -on: - push: - workflow_dispatch: - schedule: - - cron: "0 */6 * * *" - -jobs: - codeberg: - if: github.repository == 'Vendicated/Vencord' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: pixta-dev/repository-mirroring-action@674e65a7d483ca28dafaacba0d07351bdcc8bd75 # v1.1.1 - with: - target_repo_url: "git@codeberg.org:Vee/cord.git" - ssh_private_key: ${{ secrets.CODEBERG_SSH_PRIVATE_KEY }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 190e3069..00000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Release Browser Extension -on: - push: - tags: - - v* - -jobs: - Publish: - if: github.repository == 'Vendicated/Vencord' - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: check that tag matches package.json version - run: | - pkg_version="v$(jq -r .version < package.json)" - if [[ "${{ github.ref_name }}" != "$pkg_version" ]]; then - echo "Tag ${{ github.ref_name }} does not match package.json version $pkg_version" >&2 - exit 1 - fi - - - uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json - - - name: Use Node.js 19 - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: "pnpm" - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build web - run: pnpm buildWebStandalone - - - name: Publish extension - run: | - cd dist/chromium-unpacked - pnpx chrome-webstore-upload-cli@2.1.0 upload --auto-publish - env: - EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }} - CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID }} - CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }} - REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }} diff --git a/.github/workflows/reportBrokenPlugins.yml b/.github/workflows/reportBrokenPlugins.yml deleted file mode 100644 index f1e53e4d..00000000 --- a/.github/workflows/reportBrokenPlugins.yml +++ /dev/null @@ -1,95 +0,0 @@ -name: Test Patches -on: - workflow_dispatch: - inputs: - discord_branch: - type: choice - description: "Discord Branch to test patches on" - options: - - both - - stable - - canary - default: both - webhook_url: - type: string - description: "Webhook URL that the report will be posted to. This will be visible for everyone, so DO NOT pass sensitive webhooks like discord webhook. This is meant to be used by Venbot." - required: false - # schedule: - # # Every day at midnight - # - cron: 0 0 * * * - -jobs: - TestPlugins: - if: github.repository == 'Vendicated/Vencord' - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - if: ${{ github.event_name == 'schedule' }} - with: - ref: dev - - - uses: actions/checkout@v4 - if: ${{ github.event_name == 'workflow_dispatch' }} - - - uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json - - - name: Use Node.js 20 - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: "pnpm" - - - name: Install dependencies - run: | - pnpm install --frozen-lockfile - - - name: Install Google Chrome - id: setup-chrome - uses: browser-actions/setup-chrome@82b9ce628cc5595478a9ebadc480958a36457dc2 - with: - chrome-version: stable - - - name: Build Vencord Reporter Version - run: pnpm buildReporter - - - name: Run Reporter - timeout-minutes: 10 - run: | - export PATH="$PWD/node_modules/.bin:$PATH" - export CHROMIUM_BIN=${{ steps.setup-chrome.outputs.chrome-path }} - - esbuild scripts/generateReport.ts > dist/report.mjs - - stable_output_file=$(mktemp) - canary_output_file=$(mktemp) - - pids="" - - branch="${{ inputs.discord_branch }}" - if [[ "${{ github.event_name }}" = "schedule" ]]; then - branch="both" - fi - - if [[ "$branch" = "both" || "$branch" = "stable" ]]; then - node dist/report.mjs > "$stable_output_file" & - pids+=" $!" - fi - - if [[ "$branch" = "both" || "$branch" = "canary" ]]; then - USE_CANARY=true node dist/report.mjs > "$canary_output_file" & - pids+=" $!" - fi - - exit_code=0 - for pid in $pids; do - if ! wait "$pid"; then - exit_code=1 - fi - done - - cat "$stable_output_file" "$canary_output_file" >> $GITHUB_STEP_SUMMARY - exit $exit_code - env: - WEBHOOK_URL: ${{ inputs.webhook_url || secrets.DISCORD_WEBHOOK }} - WEBHOOK_SECRET: ${{ secrets.WEBHOOK_SECRET }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 7a2b320b..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: test -on: - push: - pull_request: - branches: - - main - - dev -jobs: - test: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json - - - name: Use Node.js 20 - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: "pnpm" - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Lint & Test if desktop version compiles - run: pnpm test - - - name: Test if web version compiles - run: pnpm buildWeb - - - name: Test if plugin structure is valid - run: pnpm generatePluginJson From 2a87063176b881ceed67779aed15b4e54d56cce9 Mon Sep 17 00:00:00 2001 From: dorkbutt <git@nomadants.net> Date: Fri, 6 Jun 2025 13:08:27 -0400 Subject: [PATCH 04/25] and added a loose piece. --- .jforgejo/ISSUE_TEMPLATE/blank.yml | 25 +++++ .jforgejo/ISSUE_TEMPLATE/bug_report.yml | 66 ++++++++++++ .jforgejo/ISSUE_TEMPLATE/config.yml | 8 ++ .jforgejo/ISSUE_TEMPLATE/developer-banner.png | Bin 0 -> 31992 bytes .jforgejo/workflows/build.yml | 80 +++++++++++++++ .jforgejo/workflows/codeberg-mirror.yml | 22 ++++ .jforgejo/workflows/publish.yml | 45 +++++++++ .jforgejo/workflows/reportBrokenPlugins.yml | 95 ++++++++++++++++++ .jforgejo/workflows/test.yml | 32 ++++++ 9 files changed, 373 insertions(+) create mode 100644 .jforgejo/ISSUE_TEMPLATE/blank.yml create mode 100644 .jforgejo/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .jforgejo/ISSUE_TEMPLATE/config.yml create mode 100644 .jforgejo/ISSUE_TEMPLATE/developer-banner.png create mode 100644 .jforgejo/workflows/build.yml create mode 100644 .jforgejo/workflows/codeberg-mirror.yml create mode 100644 .jforgejo/workflows/publish.yml create mode 100644 .jforgejo/workflows/reportBrokenPlugins.yml create mode 100644 .jforgejo/workflows/test.yml diff --git a/.jforgejo/ISSUE_TEMPLATE/blank.yml b/.jforgejo/ISSUE_TEMPLATE/blank.yml new file mode 100644 index 00000000..89588f3d --- /dev/null +++ b/.jforgejo/ISSUE_TEMPLATE/blank.yml @@ -0,0 +1,25 @@ +name: Blank Issue +description: Create a blank issue. ALWAYS FIRST USE OUR SUPPORT CHANNEL! ONLY USE THIS FORM IF YOU ARE A CONTRIBUTOR OR WERE TOLD TO DO SO IN THE SUPPORT CHANNEL. + +body: + - type: markdown + attributes: + value: | + ![Are you a developer? No? This form is not for you!](https://github.com/Vendicated/Vencord/blob/main/.github/ISSUE_TEMPLATE/developer-banner.png?raw=true) + + GitHub Issues are for development, not support! Please use our [support server](https://vencord.dev/discord) unless you are a Vencord Developer. + + - type: textarea + id: content + attributes: + label: Content + validations: + required: true + + - type: checkboxes + id: agreement-check + attributes: + label: Request Agreement + options: + - label: I have read the requirements for opening an issue above + required: true diff --git a/.jforgejo/ISSUE_TEMPLATE/bug_report.yml b/.jforgejo/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..c08f4635 --- /dev/null +++ b/.jforgejo/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,66 @@ +name: Bug/Crash Report +description: Create a bug or crash report for Vencord. ALWAYS FIRST USE OUR SUPPORT CHANNEL! ONLY USE THIS FORM IF YOU ARE A CONTRIBUTOR OR WERE TOLD TO DO SO IN THE SUPPORT CHANNEL. +labels: [bug] +title: "[Bug] <title>" + +body: + - type: markdown + attributes: + value: | + ![Are you a developer? No? This form is not for you!](https://github.com/Vendicated/Vencord/blob/main/.github/ISSUE_TEMPLATE/developer-banner.png?raw=true) + + GitHub Issues are for development, not support! Please use our [support server](https://vencord.dev/discord) unless you are a Vencord Developer. + + - type: textarea + id: bug-description + attributes: + label: What happens when the bug or crash occurs? + description: Where does this bug or crash occur, when does it occur, etc. + placeholder: The bug/crash happens sometimes when I do ..., causing this to not work/the app to crash. I think it happens because of ... + validations: + required: true + + - type: textarea + id: expected-behaviour + attributes: + label: What is the expected behaviour? + description: Simply detail what the expected behaviour is. + placeholder: I expect Vencord/Discord to open the ... page instead of ..., it prevents me from doing ... + validations: + required: true + + - type: textarea + id: steps-to-take + attributes: + label: How do you recreate this bug or crash? + description: Give us a list of steps in order to recreate the bug or crash. + placeholder: | + 1. Do ... + 2. Then ... + 3. Do this ..., ... and then ... + 4. Observe "the bug" or "the crash" + validations: + required: true + + - type: textarea + id: crash-log + attributes: + label: Errors + description: Open the Developer Console with Ctrl/Cmd + Shift + i. Then look for any red errors (Ignore network errors like Failed to load resource) and paste them between the "```". + value: | + ``` + Replace this text with your crash-log. + ``` + validations: + required: false + + - type: checkboxes + id: agreement-check + attributes: + label: Request Agreement + description: We only accept reports for bugs that happen on Discord Stable. Canary and PTB are Development branches and may be unstable + options: + - label: I am using Discord Stable or tried on Stable and this bug happens there as well + required: true + - label: I am a Vencord Developer + required: true diff --git a/.jforgejo/ISSUE_TEMPLATE/config.yml b/.jforgejo/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..bc5d9766 --- /dev/null +++ b/.jforgejo/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Vencord Support Server + url: https://discord.gg/D9uwnFnqmd + about: If you need help regarding Vencord, please join our support server! + - name: Vencord Installer + url: https://github.com/Vencord/Installer + about: You can find the Vencord Installer here diff --git a/.jforgejo/ISSUE_TEMPLATE/developer-banner.png b/.jforgejo/ISSUE_TEMPLATE/developer-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..5fa12fc370750c460f8d0959d5f73828c63b6e3d GIT binary patch literal 31992 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 WKXLqM0$yeQOioH!vP#@2=>GuWUFmuN literal 0 HcmV?d00001 diff --git a/.jforgejo/workflows/build.yml b/.jforgejo/workflows/build.yml new file mode 100644 index 00000000..b1cbc302 --- /dev/null +++ b/.jforgejo/workflows/build.yml @@ -0,0 +1,80 @@ +name: Build DevBuild +on: + push: + branches: + - main + paths: + - .github/workflows/build.yml + - src/** + - browser/** + - scripts/build/** + - package.json + - pnpm-lock.yaml +env: + FORCE_COLOR: true + +jobs: + Build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json + + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build web + run: pnpm buildWebStandalone + + - name: Build + run: pnpm build --standalone + + - name: Generate plugin list + run: pnpm generatePluginJson dist/plugins.json dist/plugin-readmes.json + + - name: Clean up obsolete files + run: | + rm -rf dist/*-unpacked dist/vendor Vencord.user.css vencordDesktopRenderer.css vencordDesktopRenderer.css.map + + - name: Get some values needed for the release + id: release_values + run: | + echo "release_tag=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + + - name: Upload DevBuild as release + if: github.repository == 'Vendicated/Vencord' + run: | + gh release upload devbuild --clobber dist/* + gh release edit devbuild --title "DevBuild $RELEASE_TAG" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ env.release_tag }} + + - name: Upload DevBuild to builds repo + if: github.repository == 'Vendicated/Vencord' + run: | + git config --global user.name "$USERNAME" + git config --global user.email actions@github.com + + git clone https://$USERNAME:$API_TOKEN@github.com/$GH_REPO.git upload + cd upload + + GLOBIGNORE=.git:.gitignore:README.md:LICENSE + rm -rf * + cp -r ../dist/* . + + git add -A + git commit -m "Builds for https://github.com/$GITHUB_REPOSITORY/commit/$GITHUB_SHA" + git push --force https://$USERNAME:$API_TOKEN@github.com/$GH_REPO.git + env: + API_TOKEN: ${{ secrets.BUILDS_TOKEN }} + GH_REPO: Vencord/builds + USERNAME: GitHub-Actions diff --git a/.jforgejo/workflows/codeberg-mirror.yml b/.jforgejo/workflows/codeberg-mirror.yml new file mode 100644 index 00000000..5acae6a4 --- /dev/null +++ b/.jforgejo/workflows/codeberg-mirror.yml @@ -0,0 +1,22 @@ +name: Sync to Codeberg +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true +on: + push: + workflow_dispatch: + schedule: + - cron: "0 */6 * * *" + +jobs: + codeberg: + if: github.repository == 'Vendicated/Vencord' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: pixta-dev/repository-mirroring-action@674e65a7d483ca28dafaacba0d07351bdcc8bd75 # v1.1.1 + with: + target_repo_url: "git@codeberg.org:Vee/cord.git" + ssh_private_key: ${{ secrets.CODEBERG_SSH_PRIVATE_KEY }} diff --git a/.jforgejo/workflows/publish.yml b/.jforgejo/workflows/publish.yml new file mode 100644 index 00000000..190e3069 --- /dev/null +++ b/.jforgejo/workflows/publish.yml @@ -0,0 +1,45 @@ +name: Release Browser Extension +on: + push: + tags: + - v* + +jobs: + Publish: + if: github.repository == 'Vendicated/Vencord' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: check that tag matches package.json version + run: | + pkg_version="v$(jq -r .version < package.json)" + if [[ "${{ github.ref_name }}" != "$pkg_version" ]]; then + echo "Tag ${{ github.ref_name }} does not match package.json version $pkg_version" >&2 + exit 1 + fi + + - uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json + + - name: Use Node.js 19 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build web + run: pnpm buildWebStandalone + + - name: Publish extension + run: | + cd dist/chromium-unpacked + pnpx chrome-webstore-upload-cli@2.1.0 upload --auto-publish + env: + EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }} + CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID }} + CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }} + REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }} diff --git a/.jforgejo/workflows/reportBrokenPlugins.yml b/.jforgejo/workflows/reportBrokenPlugins.yml new file mode 100644 index 00000000..f1e53e4d --- /dev/null +++ b/.jforgejo/workflows/reportBrokenPlugins.yml @@ -0,0 +1,95 @@ +name: Test Patches +on: + workflow_dispatch: + inputs: + discord_branch: + type: choice + description: "Discord Branch to test patches on" + options: + - both + - stable + - canary + default: both + webhook_url: + type: string + description: "Webhook URL that the report will be posted to. This will be visible for everyone, so DO NOT pass sensitive webhooks like discord webhook. This is meant to be used by Venbot." + required: false + # schedule: + # # Every day at midnight + # - cron: 0 0 * * * + +jobs: + TestPlugins: + if: github.repository == 'Vendicated/Vencord' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + if: ${{ github.event_name == 'schedule' }} + with: + ref: dev + + - uses: actions/checkout@v4 + if: ${{ github.event_name == 'workflow_dispatch' }} + + - uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json + + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Install dependencies + run: | + pnpm install --frozen-lockfile + + - name: Install Google Chrome + id: setup-chrome + uses: browser-actions/setup-chrome@82b9ce628cc5595478a9ebadc480958a36457dc2 + with: + chrome-version: stable + + - name: Build Vencord Reporter Version + run: pnpm buildReporter + + - name: Run Reporter + timeout-minutes: 10 + run: | + export PATH="$PWD/node_modules/.bin:$PATH" + export CHROMIUM_BIN=${{ steps.setup-chrome.outputs.chrome-path }} + + esbuild scripts/generateReport.ts > dist/report.mjs + + stable_output_file=$(mktemp) + canary_output_file=$(mktemp) + + pids="" + + branch="${{ inputs.discord_branch }}" + if [[ "${{ github.event_name }}" = "schedule" ]]; then + branch="both" + fi + + if [[ "$branch" = "both" || "$branch" = "stable" ]]; then + node dist/report.mjs > "$stable_output_file" & + pids+=" $!" + fi + + if [[ "$branch" = "both" || "$branch" = "canary" ]]; then + USE_CANARY=true node dist/report.mjs > "$canary_output_file" & + pids+=" $!" + fi + + exit_code=0 + for pid in $pids; do + if ! wait "$pid"; then + exit_code=1 + fi + done + + cat "$stable_output_file" "$canary_output_file" >> $GITHUB_STEP_SUMMARY + exit $exit_code + env: + WEBHOOK_URL: ${{ inputs.webhook_url || secrets.DISCORD_WEBHOOK }} + WEBHOOK_SECRET: ${{ secrets.WEBHOOK_SECRET }} diff --git a/.jforgejo/workflows/test.yml b/.jforgejo/workflows/test.yml new file mode 100644 index 00000000..7a2b320b --- /dev/null +++ b/.jforgejo/workflows/test.yml @@ -0,0 +1,32 @@ +name: test +on: + push: + pull_request: + branches: + - main + - dev +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json + + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Lint & Test if desktop version compiles + run: pnpm test + + - name: Test if web version compiles + run: pnpm buildWeb + + - name: Test if plugin structure is valid + run: pnpm generatePluginJson From 9051269657880b0e6615815d5f6bea5d74250629 Mon Sep 17 00:00:00 2001 From: dorkbutt <git@nomadants.net> Date: Fri, 6 Jun 2025 15:00:54 -0400 Subject: [PATCH 05/25] resorting to original installation method --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 3a2b1492..be6f3936 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # A fork. A fork. We're a fork. +Installing is the same as the Vencord devs laid out: [(Install)](https://docs.vencord.dev/installing/) +* Beyond that, be sure to clone *this* repository instead of their upstream one. + * `git clone https://git.dorkbutt.lol/dorkbutt/vencord` +* After completing the steps, go to Settings > Vencord > Plugins and search for +"FORKED - usrbg" and enable it. Be sure to tweak its settings! + # Vencord From f4888f29f192a9924e19f2c24fafdbe2e381267e Mon Sep 17 00:00:00 2001 From: dorkbutt <git@nomadants.net> Date: Fri, 4 Jul 2025 13:12:52 -0400 Subject: [PATCH 06/25] equal parts lazy and educated CSP fix. --- src/main/csp/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/csp/index.ts b/src/main/csp/index.ts index c4192f4b..72c29ca0 100644 --- a/src/main/csp/index.ts +++ b/src/main/csp/index.ts @@ -63,6 +63,9 @@ export const CspPolicies: PolicyMap = { "dearrow-thumb.ajay.app": ImageSrc, // Dearrow Thumbnail CDN "usrbg.is-hardly.online": ImageSrc, // USRBG API "icons.duckduckgo.com": ImageSrc, // DuckDuckGo Favicon API (Reverse Image Search) + + // forked addition + "usrbg.dorkbutt.lol": ImageAndCssSrc, }; const findHeader = (headers: PolicyMap, headerName: Lowercase<string>) => { From a202904f7dc76c7aafeca766c8ca5431d2b434d0 Mon Sep 17 00:00:00 2001 From: dorkbutt <git@nomadants.net> Date: Fri, 4 Jul 2025 13:15:16 -0400 Subject: [PATCH 07/25] add all subdomains for my personal domain. --- src/main/csp/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/csp/index.ts b/src/main/csp/index.ts index 72c29ca0..9075b9ad 100644 --- a/src/main/csp/index.ts +++ b/src/main/csp/index.ts @@ -65,7 +65,7 @@ export const CspPolicies: PolicyMap = { "icons.duckduckgo.com": ImageSrc, // DuckDuckGo Favicon API (Reverse Image Search) // forked addition - "usrbg.dorkbutt.lol": ImageAndCssSrc, + "*.dorkbutt.lol": ImageAndCssSrc; }; const findHeader = (headers: PolicyMap, headerName: Lowercase<string>) => { From 82f668ab92afd21302833b278f215a7abebfcbb8 Mon Sep 17 00:00:00 2001 From: dorkbutt <git@nomadants.net> Date: Fri, 4 Jul 2025 13:16:12 -0400 Subject: [PATCH 08/25] replaced incorrect semicolon with comma --- src/main/csp/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/csp/index.ts b/src/main/csp/index.ts index 9075b9ad..a46da7ee 100644 --- a/src/main/csp/index.ts +++ b/src/main/csp/index.ts @@ -65,7 +65,7 @@ export const CspPolicies: PolicyMap = { "icons.duckduckgo.com": ImageSrc, // DuckDuckGo Favicon API (Reverse Image Search) // forked addition - "*.dorkbutt.lol": ImageAndCssSrc; + "*.dorkbutt.lol": ImageAndCssSrc, }; const findHeader = (headers: PolicyMap, headerName: Lowercase<string>) => { From 09ed2c78ba0eda30d1ad621f49094bf290bd14d9 Mon Sep 17 00:00:00 2001 From: dorkbutt <git@nomadants.net> Date: Thu, 17 Jul 2025 19:19:09 -0400 Subject: [PATCH 09/25] updated to Vencord v1.12.6 --- src/plugins/usrbg-fork/index.tsx | 120 +++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/plugins/usrbg-fork/index.tsx diff --git a/src/plugins/usrbg-fork/index.tsx b/src/plugins/usrbg-fork/index.tsx new file mode 100644 index 00000000..d77e8780 --- /dev/null +++ b/src/plugins/usrbg-fork/index.tsx @@ -0,0 +1,120 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2023 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +import { definePluginSettings } from "@api/Settings"; +import { Link } from "@components/Link"; +import { Devs } from "@utils/constants"; +import definePlugin, { OptionType } from "@utils/types"; + +const API_URL = "https://usrbg.dorkbutt.lol/users/users.json"; + +interface UsrbgApiReturn { + endpoint: string; + bucket: string; + prefix: string; + users: Record<string, string>; +} + +const settings = definePluginSettings({ + nitroFirst: { + description: "Banner to use if both Nitro and USRBG banners are present", + type: OptionType.SELECT, + options: [ + { label: "Nitro banner", value: true, default: true }, + { label: "USRBG banner", value: false }, + ] + }, + voiceBackground: { + description: "Use USRBG banners as voice chat backgrounds", + type: OptionType.BOOLEAN, + default: true, + restartNeeded: true + } +}); + +export default definePlugin({ + name: "FORKED - USRBG", + description: "Displays user banners from dorkbutt's USRBG server, allowing anyone to get a banner without Nitro", + authors: [Devs.dorkbutt, Devs.AutumnVN, Devs.katlyn, Devs.pylix, Devs.TheKodeToad], + settings, + patches: [ + { + find: '.banner)==null?"COMPLETE"', + replacement: { + match: /(?<=void 0:)\i.getPreviewBanner\(\i,\i,\i\)/, + replace: "$self.patchBannerUrl(arguments[0])||$&" + + } + }, + { + find: "\"data-selenium-video-tile\":", + predicate: () => settings.store.voiceBackground, + replacement: [ + { + match: /(?<=function\((\i),\i\)\{)(?=let.{20,40},style:)/, + replace: "$1.style=$self.getVoiceBackgroundStyles($1);" + } + ] + } + ], + + data: null as UsrbgApiReturn | null, + + settingsAboutComponent: () => { + return ( + "Message @dorkbutt about getting your personal banner added!" + ); + }, + + getVoiceBackgroundStyles({ className, participantUserId }: any) { + if (className.includes("tile_")) { + if (this.userHasBackground(participantUserId)) { + return { + backgroundImage: `url(${this.getImageUrl(participantUserId)})`, + backgroundSize: "cover", + backgroundPosition: "center", + backgroundRepeat: "no-repeat" + }; + } + } + }, + + patchBannerUrl({ displayProfile }: any) { + if (displayProfile?.banner && settings.store.nitroFirst) return; + if (this.userHasBackground(displayProfile?.userId)) return this.getImageUrl(displayProfile?.userId); + }, + + userHasBackground(userId: string) { + return !!this.data?.users[userId]; + }, + + getImageUrl(userId: string): string | null { + if (!this.userHasBackground(userId)) return null; + + // We can assert that data exists because userHasBackground returned true + const { endpoint, bucket, prefix, users: { [userId]: etag } } = this.data!; + return `${endpoint}/${bucket}/${prefix}${userId}?${etag}`; + }, + + async start() { + const res = await fetch(API_URL); + if (res.ok) { + this.data = await res.json(); + } + } +}); From bef4b013823954c81ef439f3a1c6d1e8e3d5c809 Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Thu, 3 Jul 2025 20:14:59 -0400 Subject: [PATCH 10/25] fix Expression Cloner, ServerInfo & SeeSummaries plugins (#3536) --- src/plugins/expressionCloner/index.tsx | 14 ++++++++++---- src/plugins/pauseInvitesForever/index.tsx | 6 +++--- src/plugins/seeSummaries/index.tsx | 8 +++++--- src/plugins/serverInfo/GuildInfoModal.tsx | 4 ++-- src/utils/discord.tsx | 13 +++++++++++++ 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/plugins/expressionCloner/index.tsx b/src/plugins/expressionCloner/index.tsx index c1244fae..6f84e7f7 100644 --- a/src/plugins/expressionCloner/index.tsx +++ b/src/plugins/expressionCloner/index.tsx @@ -20,12 +20,13 @@ import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/Co import { migratePluginSettings } from "@api/Settings"; import { CheckedTextInput } from "@components/CheckedTextInput"; import { Devs } from "@utils/constants"; +import { getGuildAcronym } from "@utils/discord"; import { Logger } from "@utils/Logger"; import { Margins } from "@utils/margins"; import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal"; import definePlugin from "@utils/types"; import { findByCodeLazy, findStoreLazy } from "@webpack"; -import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common"; +import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, IconUtils, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common"; import { Guild } from "discord-types/general"; import { Promisable } from "type-fest"; @@ -250,13 +251,18 @@ function CloneModal({ data }: { data: Sticker | Emoji; }) { width: "100%", height: "100%", }} - src={g.getIconURL(512, true)} + src={IconUtils.getGuildIconURL({ + id: g.id, + icon: g.icon, + canAnimate: true, + size: 512 + })} alt={g.name} /> ) : ( <Forms.FormText style={{ - fontSize: getFontSize(g.acronym), + fontSize: getFontSize(getGuildAcronym(g)), width: "100%", overflow: "hidden", whiteSpace: "nowrap", @@ -264,7 +270,7 @@ function CloneModal({ data }: { data: Sticker | Emoji; }) { cursor: isCloning ? "not-allowed" : "pointer", }} > - {g.acronym} + {getGuildAcronym(g)} </Forms.FormText> )} </div> diff --git a/src/plugins/pauseInvitesForever/index.tsx b/src/plugins/pauseInvitesForever/index.tsx index 432d1c1c..577d8bd7 100644 --- a/src/plugins/pauseInvitesForever/index.tsx +++ b/src/plugins/pauseInvitesForever/index.tsx @@ -18,7 +18,7 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; -import { getIntlMessage } from "@utils/discord"; +import { getIntlMessage, hasGuildFeature } from "@utils/discord"; import definePlugin from "@utils/types"; import { Constants, GuildStore, PermissionStore, RestAPI } from "@webpack/common"; @@ -27,8 +27,8 @@ function showDisableInvites(guildId: string) { if (!guild) return false; return ( - // @ts-ignore - !guild.hasFeature("INVITES_DISABLED") && + // @ts-expect-error + !hasGuildFeature(guild, "INVITES_DISABLED") && PermissionStore.getGuildPermissionProps(guild).canManageRoles ); } diff --git a/src/plugins/seeSummaries/index.tsx b/src/plugins/seeSummaries/index.tsx index de50e0a9..343348f1 100644 --- a/src/plugins/seeSummaries/index.tsx +++ b/src/plugins/seeSummaries/index.tsx @@ -7,6 +7,7 @@ import { DataStore } from "@api/index"; import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { hasGuildFeature } from "@utils/discord"; import definePlugin, { OptionType } from "@utils/types"; import { findByCodeLazy, findByPropsLazy } from "@webpack"; import { ChannelStore, GuildStore } from "@webpack/common"; @@ -57,7 +58,7 @@ export default definePlugin({ { find: "SUMMARIZEABLE.has", replacement: { - match: /\i\.hasFeature\(\i\.\i\.SUMMARIES_ENABLED\w+?\)/g, + match: /\i\.features\.has\(\i\.\i\.SUMMARIES_ENABLED\w+?\)/g, replace: "true" } }, @@ -109,7 +110,8 @@ export default definePlugin({ const channel = ChannelStore.getChannel(channelId); // SUMMARIES_ENABLED feature is not in discord-types const guild = GuildStore.getGuild(channel.guild_id); - // @ts-ignore - return guild.hasFeature("SUMMARIES_ENABLED_GA"); + + // @ts-expect-error + return hasGuildFeature(guild, "SUMMARIES_ENABLED_GA"); } }); diff --git a/src/plugins/serverInfo/GuildInfoModal.tsx b/src/plugins/serverInfo/GuildInfoModal.tsx index c62352f2..359590cf 100644 --- a/src/plugins/serverInfo/GuildInfoModal.tsx +++ b/src/plugins/serverInfo/GuildInfoModal.tsx @@ -7,7 +7,7 @@ import "./styles.css"; import { classNameFactory } from "@api/Styles"; -import { openImageModal, openUserProfile } from "@utils/discord"; +import { getGuildAcronym, openImageModal, openUserProfile } from "@utils/discord"; import { classes } from "@utils/misc"; import { ModalRoot, ModalSize, openModal } from "@utils/modal"; import { useAwaiter } from "@utils/react"; @@ -103,7 +103,7 @@ function GuildInfoModal({ guild }: GuildProps) { width: 512, })} /> - : <div aria-hidden className={classes(IconClasses.childWrapper, IconClasses.acronym)}>{guild.acronym}</div> + : <div aria-hidden className={classes(IconClasses.childWrapper, IconClasses.acronym)}>{getGuildAcronym(guild)}</div> } <div className={cl("name-and-description")}> diff --git a/src/utils/discord.tsx b/src/utils/discord.tsx index e04ad201..fce909c3 100644 --- a/src/utils/discord.tsx +++ b/src/utils/discord.tsx @@ -19,6 +19,7 @@ import { MessageObject } from "@api/MessageEvents"; import { ChannelActionCreators, ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, i18n, IconUtils, InviteActions, MessageActions, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common"; import { Channel, Guild, Message, User } from "discord-types/general"; +import GuildFeatures from "discord-types/other/Constants"; import { Except } from "type-fest"; import { runtimeHashMessageKey } from "./intlHash"; @@ -218,3 +219,15 @@ export function getEmojiURL(id: string, animated: boolean, size: number) { const url = IconUtils.getEmojiURL({ id, animated, size }); return animated ? url.replace(".webp", ".gif") : url; } + +// Discord has a similar function in their code +export function getGuildAcronym(guild: Guild): string { + return guild.name + .replaceAll("'s ", " ") + .replace(/\w+/g, m => m[0]) + .replace(/\s/g, ""); +} + +export function hasGuildFeature(guild: Guild, feature: keyof GuildFeatures["GuildFeatures"]): boolean { + return guild.features?.has(feature) ?? false; +} From 0e75d8a42f04ce1a376d3a4eeb2346e359c16db8 Mon Sep 17 00:00:00 2001 From: Amia <9750071+aamiaa@users.noreply.github.com> Date: Fri, 4 Jul 2025 15:04:12 +0200 Subject: [PATCH 11/25] Fix ImplicitRelationships & RelationshipNotifier (#3539) --- src/plugins/implicitRelationships/index.ts | 3 +-- src/plugins/relationshipNotifier/utils.ts | 4 ++-- src/webpack/common/types/stores.d.ts | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plugins/implicitRelationships/index.ts b/src/plugins/implicitRelationships/index.ts index 4a8cf5fb..d57370a0 100644 --- a/src/plugins/implicitRelationships/index.ts +++ b/src/plugins/implicitRelationships/index.ts @@ -125,12 +125,11 @@ export default definePlugin({ // Implicit relationships are defined as users that you: // 1. Have an affinity for // 2. Do not have a relationship with - await this.refreshUserAffinities(); const userAffinities: Record<string, any>[] = UserAffinitiesStore.getUserAffinities(); const relationships = RelationshipStore.getMutableRelationships(); const nonFriendAffinities = userAffinities.filter(a => !RelationshipStore.getRelationshipType(a.otherUserId)); nonFriendAffinities.forEach(a => { - relationships[a.otherUserId] = 5; + relationships.set(a.otherUserId, 5); }); RelationshipStore.emitChange(); diff --git a/src/plugins/relationshipNotifier/utils.ts b/src/plugins/relationshipNotifier/utils.ts index 75cf2d3a..09ef5cdd 100644 --- a/src/plugins/relationshipNotifier/utils.ts +++ b/src/plugins/relationshipNotifier/utils.ts @@ -173,8 +173,8 @@ export async function syncFriends() { friends.requests = []; const relationShips = RelationshipStore.getMutableRelationships(); - for (const id in relationShips) { - switch (relationShips[id]) { + for (const [id, type] of relationShips) { + switch (type) { case RelationshipType.FRIEND: friends.friends.push(id); break; diff --git a/src/webpack/common/types/stores.d.ts b/src/webpack/common/types/stores.d.ts index 9a2dd132..f0235986 100644 --- a/src/webpack/common/types/stores.d.ts +++ b/src/webpack/common/types/stores.d.ts @@ -255,5 +255,5 @@ export class RelationshipStore extends FluxStore { getSince(userId: string): string; /** @returns Format: [userId: Enum value from constants.RelationshipTypes] */ - getMutableRelationships(): Record<number, number>; + getMutableRelationships(): Map<string, number>; } From 2f6dfd9bee09f253d1e73509e8bf110a28240a8e Mon Sep 17 00:00:00 2001 From: Etorix <92535668+EtorixDev@users.noreply.github.com> Date: Fri, 4 Jul 2025 07:09:10 -0700 Subject: [PATCH 12/25] Experiments: fix edge case in experiment rollout detection (#3497) Co-authored-by: V <vendicated@riseup.net> --- src/plugins/experiments/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/experiments/index.tsx b/src/plugins/experiments/index.tsx index 967197ad..eee732d0 100644 --- a/src/plugins/experiments/index.tsx +++ b/src/plugins/experiments/index.tsx @@ -68,8 +68,8 @@ export default definePlugin({ { find: 'type:"user",revision', replacement: { - match: /!(\i)&&"CONNECTION_OPEN".+?;/g, - replace: "$1=!0;" + match: /!(\i)(?=&&"CONNECTION_OPEN")/, + replace: "!($1=true)" } }, { From 34fa7cba208535e78c6350a4ce14a2b4f2bdcdd4 Mon Sep 17 00:00:00 2001 From: Amia <9750071+aamiaa@users.noreply.github.com> Date: Tue, 8 Jul 2025 01:04:14 +0200 Subject: [PATCH 13/25] MutualGroupDMs: fix member count label (#3541) --- src/plugins/mutualGroupDMs/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/mutualGroupDMs/index.tsx b/src/plugins/mutualGroupDMs/index.tsx index 796a91db..b90eb7ed 100644 --- a/src/plugins/mutualGroupDMs/index.tsx +++ b/src/plugins/mutualGroupDMs/index.tsx @@ -24,7 +24,7 @@ import { isNonNullish } from "@utils/guards"; import { Logger } from "@utils/Logger"; import definePlugin from "@utils/types"; import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; -import { Avatar, ChannelStore, Clickable, IconUtils, RelationshipStore, ScrollerThin, useMemo, UserStore } from "@webpack/common"; +import { Avatar, ChannelStore, Clickable, IconUtils, RelationshipStore, ScrollerThin, Text, useMemo, UserStore } from "@webpack/common"; import { Channel, User } from "discord-types/general"; import { JSX } from "react"; @@ -73,7 +73,7 @@ function renderClickableGDMs(mutualDms: Channel[], onClose: () => void) { </Avatar> <div className={MutualsListClasses.details}> <div className={MutualsListClasses.name}>{getGroupDMName(c)}</div> - <div className={MutualsListClasses.nick}>{c.recipients.length + 1} Members</div> + <Text variant="text-xs/medium">{c.recipients.length + 1} Members</Text> </div> </Clickable> )); From 3bbf885146072ce17bc06ebc71b42f64152ea2e3 Mon Sep 17 00:00:00 2001 From: nyx <60797172+verticalsync@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:05:56 +0300 Subject: [PATCH 14/25] ShowMeYourName: fix gradient role compatibility (#3495) Co-authored-by: V <vendicated@riseup.net> --- src/plugins/showMeYourName/styles.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/showMeYourName/styles.css b/src/plugins/showMeYourName/styles.css index 7a1455d9..e93fc451 100644 --- a/src/plugins/showMeYourName/styles.css +++ b/src/plugins/showMeYourName/styles.css @@ -1,5 +1,7 @@ .vc-smyn-suffix { color: var(--text-muted); + -webkit-text-fill-color: initial; + isolation: isolate; } .vc-smyn-suffix::before { From 619b0ef8581c3b4e822597c381f41f2aca1e348a Mon Sep 17 00:00:00 2001 From: V <vendicated@riseup.net> Date: Thu, 10 Jul 2025 00:38:39 +0200 Subject: [PATCH 15/25] refactor discord types into separate npm package (#3520) Co-authored-by: V <vendicated@riseup.net> Co-authored-by: sadan <117494111+sadan4@users.noreply.github.com> Co-authored-by: ezzud <contact@ezzud.fr> --- package.json | 2 +- packages/discord-types/LICENSE | 165 +++++++++++ packages/discord-types/README.md | 42 +++ packages/discord-types/enums/commands.ts | 27 ++ packages/discord-types/enums/index.ts | 1 + packages/discord-types/package.json | 19 ++ packages/discord-types/src/classes.d.ts | 21 ++ .../discord-types/src/common/Channel.d.ts | 83 ++++++ packages/discord-types/src/common/Guild.d.ts | 64 +++++ .../discord-types/src/common/GuildMember.d.ts | 26 ++ packages/discord-types/src/common/Record.d.ts | 12 + packages/discord-types/src/common/Role.d.ts | 33 +++ packages/discord-types/src/common/User.d.ts | 66 +++++ packages/discord-types/src/common/index.d.ts | 7 + .../src/common/messages/Commands.d.ts | 61 +++++ .../src/common/messages/Embed.d.ts | 70 +++++ .../src/common/messages/Emoji.d.ts | 42 +++ .../src/common/messages/Message.d.ts | 191 +++++++++++++ .../src/common/messages/index.d.ts | 4 + .../discord-types/src}/components.d.ts | 22 +- packages/discord-types/src/flux.d.ts | 30 ++ packages/discord-types/src/fluxEvents.d.ts | 22 ++ packages/discord-types/src/index.d.ts | 9 + .../discord-types/src}/menu.d.ts | 20 +- .../src/stores/ChannelStore.d.ts | 24 ++ .../discord-types/src/stores/DraftStore.d.ts | 43 +++ .../discord-types/src/stores/EmojiStore.d.ts | 57 ++++ .../discord-types/src/stores/FluxStore.d.ts | 44 +++ .../src/stores/GuildMemberStore.d.ts | 27 ++ .../src/stores/GuildRoleStore.d.ts | 7 + .../discord-types/src/stores/GuildStore.d.ts | 8 + .../src/stores/MessageStore.d.ts | 13 + .../src/stores/RelationshipStore.d.ts | 21 ++ .../src/stores/SelectedChannelStore.d.ts | 14 + .../src/stores/SelectedGuildStore.d.ts | 14 + .../discord-types/src/stores/ThemeStore.d.ts | 18 ++ .../discord-types/src/stores/UserStore.d.ts | 10 + .../discord-types/src/stores/WindowStore.d.ts | 7 + packages/discord-types/src/stores/index.d.ts | 32 +++ .../discord-types/src}/utils.d.ts | 36 ++- .../discord-types/webpack/index.d.ts | 27 +- packages/vencord-types/package.json | 1 - pnpm-lock.yaml | 43 ++- scripts/build/build.mjs | 2 +- scripts/build/common.mjs | 2 +- src/api/ChatButtons.tsx | 2 +- src/api/Commands/commandHelpers.ts | 10 +- src/api/Commands/index.ts | 25 +- src/api/Commands/types.ts | 108 +------- src/api/DataStore/index.ts | 4 +- src/api/MemberListDecorators.tsx | 2 +- src/api/MessageDecorations.tsx | 2 +- src/api/MessageEvents.ts | 3 +- src/api/MessagePopover.tsx | 2 +- src/api/MessageUpdater.ts | 3 +- src/api/Settings.ts | 2 +- src/components/DonateButton.tsx | 2 +- .../PluginSettings/ContributorModal.tsx | 2 +- src/components/PluginSettings/PluginModal.tsx | 2 +- src/debug/loadLazyChunks.ts | 3 +- src/debug/runReporter.ts | 3 +- src/main/patcher.ts | 2 +- src/plugins/_api/badges/index.tsx | 2 +- src/plugins/_core/noTrack.ts | 2 +- src/plugins/_core/settings.tsx | 2 +- src/plugins/_core/supportHelper.tsx | 3 +- .../accountPanelServerProfile/index.tsx | 2 +- src/plugins/biggerStreamPreview/index.tsx | 2 +- .../webpack/types/stores.ts | 2 +- src/plugins/copyUserURLs/index.tsx | 2 +- .../decor/lib/stores/UsersDecorationsStore.ts | 2 +- .../decor/ui/modals/ChangeDecorationModal.tsx | 2 +- src/plugins/expressionCloner/index.tsx | 2 +- src/plugins/fakeNitro/index.tsx | 4 +- src/plugins/fakeProfileThemes/index.tsx | 8 +- src/plugins/favEmojiFirst/index.ts | 2 +- src/plugins/forceOwnerCrown/index.ts | 2 +- src/plugins/fullSearchContext/index.tsx | 2 +- src/plugins/greetStickerPicker/index.tsx | 2 +- src/plugins/hideAttachments/index.tsx | 4 +- src/plugins/index.ts | 2 +- src/plugins/invisibleChat.desktop/index.tsx | 2 +- src/plugins/memberCount/index.tsx | 2 +- src/plugins/mentionAvatars/index.tsx | 2 +- src/plugins/messageLatency/index.tsx | 2 +- src/plugins/messageLinkEmbeds/index.tsx | 6 +- src/plugins/messageLogger/index.tsx | 2 +- src/plugins/messageTags/index.ts | 4 +- src/plugins/mutualGroupDMs/index.tsx | 2 +- src/plugins/newGuildSettings/index.tsx | 2 +- src/plugins/noBlockedMessages/index.ts | 2 +- src/plugins/noReplyMention/index.tsx | 2 +- src/plugins/onePingPerDM/index.ts | 2 +- src/plugins/pauseInvitesForever/index.tsx | 1 - .../components/RolesAndUsersPermissions.tsx | 3 +- .../components/UserPermissions.tsx | 2 +- src/plugins/permissionsViewer/index.tsx | 4 +- src/plugins/permissionsViewer/utils.ts | 2 +- src/plugins/petpet/index.ts | 7 +- src/plugins/pinDms/index.tsx | 2 +- src/plugins/platformIndicators/index.tsx | 2 +- src/plugins/previewMessage/index.tsx | 2 +- src/plugins/quickReply/index.ts | 2 +- .../readAllNotificationsButton/index.tsx | 2 +- src/plugins/relationshipNotifier/types.ts | 2 +- src/plugins/relationshipNotifier/utils.ts | 2 +- src/plugins/replyTimestamp/index.tsx | 2 +- src/plugins/reviewDB/index.tsx | 2 +- src/plugins/seeSummaries/index.tsx | 1 - src/plugins/serverInfo/GuildInfoModal.tsx | 2 +- src/plugins/serverInfo/index.tsx | 2 +- src/plugins/showConnections/index.tsx | 2 +- .../components/HiddenChannelLockScreen.tsx | 2 +- src/plugins/showHiddenChannels/index.tsx | 2 +- src/plugins/showMeYourName/index.tsx | 4 +- src/plugins/showTimeoutDuration/index.tsx | 2 +- src/plugins/sortFriendRequests/index.tsx | 2 +- src/plugins/spotifyShareCommands/index.ts | 3 +- src/plugins/themeAttributes/index.ts | 2 +- .../translate/TranslationAccessory.tsx | 2 +- src/plugins/typingIndicator/index.tsx | 2 +- src/plugins/typingTweaks/index.tsx | 2 +- src/plugins/unsuppressEmbeds/index.tsx | 2 +- .../PronounsChatComponent.tsx | 2 +- src/plugins/userVoiceShow/components.tsx | 2 +- src/plugins/validReply/index.ts | 3 +- src/plugins/vcNarrator/index.tsx | 11 +- src/plugins/viewIcons/index.tsx | 2 +- src/plugins/viewRaw/index.tsx | 2 +- src/plugins/whoReacted/index.tsx | 3 +- src/plugins/xsOverlay/index.tsx | 2 +- src/utils/apng-canvas.js | 19 +- src/utils/discord.tsx | 5 +- src/utils/types.ts | 3 +- src/webpack/common/classes.ts | 3 +- src/webpack/common/components.ts | 2 +- src/webpack/common/index.ts | 3 - src/webpack/common/menu.ts | 3 +- src/webpack/common/stores.ts | 24 +- src/webpack/common/types/classes.d.ts | 39 --- src/webpack/common/types/fluxEvents.d.ts | 40 --- src/webpack/common/types/index.d.ts | 24 -- src/webpack/common/types/stores.d.ts | 259 ------------------ src/webpack/common/utils.ts | 6 +- src/webpack/index.ts | 2 +- src/webpack/patchWebpack.ts | 3 +- src/webpack/types.ts | 28 ++ src/webpack/webpack.ts | 5 +- tsconfig.json | 3 +- 149 files changed, 1561 insertions(+), 751 deletions(-) create mode 100644 packages/discord-types/LICENSE create mode 100644 packages/discord-types/README.md create mode 100644 packages/discord-types/enums/commands.ts create mode 100644 packages/discord-types/enums/index.ts create mode 100644 packages/discord-types/package.json create mode 100644 packages/discord-types/src/classes.d.ts create mode 100644 packages/discord-types/src/common/Channel.d.ts create mode 100644 packages/discord-types/src/common/Guild.d.ts create mode 100644 packages/discord-types/src/common/GuildMember.d.ts create mode 100644 packages/discord-types/src/common/Record.d.ts create mode 100644 packages/discord-types/src/common/Role.d.ts create mode 100644 packages/discord-types/src/common/User.d.ts create mode 100644 packages/discord-types/src/common/index.d.ts create mode 100644 packages/discord-types/src/common/messages/Commands.d.ts create mode 100644 packages/discord-types/src/common/messages/Embed.d.ts create mode 100644 packages/discord-types/src/common/messages/Emoji.d.ts create mode 100644 packages/discord-types/src/common/messages/Message.d.ts create mode 100644 packages/discord-types/src/common/messages/index.d.ts rename {src/webpack/common/types => packages/discord-types/src}/components.d.ts (89%) create mode 100644 packages/discord-types/src/flux.d.ts create mode 100644 packages/discord-types/src/fluxEvents.d.ts create mode 100644 packages/discord-types/src/index.d.ts rename {src/webpack/common/types => packages/discord-types/src}/menu.d.ts (71%) create mode 100644 packages/discord-types/src/stores/ChannelStore.d.ts create mode 100644 packages/discord-types/src/stores/DraftStore.d.ts create mode 100644 packages/discord-types/src/stores/EmojiStore.d.ts create mode 100644 packages/discord-types/src/stores/FluxStore.d.ts create mode 100644 packages/discord-types/src/stores/GuildMemberStore.d.ts create mode 100644 packages/discord-types/src/stores/GuildRoleStore.d.ts create mode 100644 packages/discord-types/src/stores/GuildStore.d.ts create mode 100644 packages/discord-types/src/stores/MessageStore.d.ts create mode 100644 packages/discord-types/src/stores/RelationshipStore.d.ts create mode 100644 packages/discord-types/src/stores/SelectedChannelStore.d.ts create mode 100644 packages/discord-types/src/stores/SelectedGuildStore.d.ts create mode 100644 packages/discord-types/src/stores/ThemeStore.d.ts create mode 100644 packages/discord-types/src/stores/UserStore.d.ts create mode 100644 packages/discord-types/src/stores/WindowStore.d.ts create mode 100644 packages/discord-types/src/stores/index.d.ts rename {src/webpack/common/types => packages/discord-types/src}/utils.d.ts (92%) rename src/webpack/wreq.d.ts => packages/discord-types/webpack/index.d.ts (90%) delete mode 100644 src/webpack/common/types/classes.d.ts delete mode 100644 src/webpack/common/types/fluxEvents.d.ts delete mode 100644 src/webpack/common/types/index.d.ts delete mode 100644 src/webpack/common/types/stores.d.ts create mode 100644 src/webpack/types.ts diff --git a/package.json b/package.json index 8a6173ef..81b9a1c5 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,8 @@ "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@types/yazl": "^2.4.5", + "@vencord/discord-types": "link:packages/discord-types", "diff": "^7.0.0", - "discord-types": "^1.3.26", "esbuild": "^0.25.1", "eslint": "9.20.1", "eslint-import-resolver-alias": "^1.1.2", diff --git a/packages/discord-types/LICENSE b/packages/discord-types/LICENSE new file mode 100644 index 00000000..0a041280 --- /dev/null +++ b/packages/discord-types/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/packages/discord-types/README.md b/packages/discord-types/README.md new file mode 100644 index 00000000..82a98dd8 --- /dev/null +++ b/packages/discord-types/README.md @@ -0,0 +1,42 @@ +# Discord Types + +This package provides TypeScript types for the Webpack modules of Discord's web app. + +While it was primarily created for Vencord, other client mods could also benefit from this, so it is published as a standalone package! + +## Installation + +```bash +npm install -D @vencord/discord-types +yarn add -D @vencord/discord-types +pnpm add -D @vencord/discord-types +``` + +## Example Usage + +```ts +import type { UserStore } from "@vencord/discord-types"; + +const userStore: UserStore = findStore("UserStore"); // findStore is up to you to implement, this library only provides types and no runtime code +``` + +## Enums + +This library also exports some const enums that you can use from Typescript code: +```ts +import { ApplicationCommandType } from "@vencord/discord-types/enums"; + +console.log(ApplicationCommandType.CHAT_INPUT); // 1 +``` + +### License + +This package is licensed under the [LGPL-3.0](./LICENSE) (or later) license. + +A very short summary of the license is that you can use this package as a library in both open source and closed source projects, +similar to an MIT-licensed project. +However, if you modify the code of this package, you must release source code of your modified version under the same license. + +### Credit + +This package was inspired by Swishilicous' [discord-types](https://www.npmjs.com/package/discord-types) package. diff --git a/packages/discord-types/enums/commands.ts b/packages/discord-types/enums/commands.ts new file mode 100644 index 00000000..0556e72d --- /dev/null +++ b/packages/discord-types/enums/commands.ts @@ -0,0 +1,27 @@ +export const enum ApplicationCommandOptionType { + SUB_COMMAND = 1, + SUB_COMMAND_GROUP = 2, + STRING = 3, + INTEGER = 4, + BOOLEAN = 5, + USER = 6, + CHANNEL = 7, + ROLE = 8, + MENTIONABLE = 9, + NUMBER = 10, + ATTACHMENT = 11, +} + +export const enum ApplicationCommandInputType { + BUILT_IN = 0, + BUILT_IN_TEXT = 1, + BUILT_IN_INTEGRATION = 2, + BOT = 3, + PLACEHOLDER = 4, +} + +export const enum ApplicationCommandType { + CHAT_INPUT = 1, + USER = 2, + MESSAGE = 3, +} diff --git a/packages/discord-types/enums/index.ts b/packages/discord-types/enums/index.ts new file mode 100644 index 00000000..62074d46 --- /dev/null +++ b/packages/discord-types/enums/index.ts @@ -0,0 +1 @@ +export * from "./commands"; diff --git a/packages/discord-types/package.json b/packages/discord-types/package.json new file mode 100644 index 00000000..7b8726fd --- /dev/null +++ b/packages/discord-types/package.json @@ -0,0 +1,19 @@ +{ + "name": "@vencord/discord-types", + "author": "Vencord Contributors", + "description": "Typescript definitions for the webpack modules of the Discord Web app", + "version": "1.0.0", + "license": "LGPL-3.0-or-later", + "types": "src/index.d.ts", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/Vendicated/Vencord.git", + "directory": "packages/discord-types" + }, + "dependencies": { + "@types/react": "^19.0.10", + "moment": "^2.22.2", + "type-fest": "^4.41.0" + } +} diff --git a/packages/discord-types/src/classes.d.ts b/packages/discord-types/src/classes.d.ts new file mode 100644 index 00000000..752ba3f0 --- /dev/null +++ b/packages/discord-types/src/classes.d.ts @@ -0,0 +1,21 @@ +export interface ImageModalClasses { + image: string, + modal: string, +} + +export interface ButtonWrapperClasses { + hoverScale: string; + buttonWrapper: string; + button: string; + iconMask: string; + buttonContent: string; + icon: string; + pulseIcon: string; + pulseButton: string; + notificationDot: string; + sparkleContainer: string; + sparkleStar: string; + sparklePlus: string; + sparkle: string; + active: string; +} diff --git a/packages/discord-types/src/common/Channel.d.ts b/packages/discord-types/src/common/Channel.d.ts new file mode 100644 index 00000000..7ad5ce53 --- /dev/null +++ b/packages/discord-types/src/common/Channel.d.ts @@ -0,0 +1,83 @@ +import { DiscordRecord } from "./Record"; + +export class Channel extends DiscordRecord { + constructor(channel: object); + application_id: number | undefined; + bitrate: number; + defaultAutoArchiveDuration: number | undefined; + flags: number; + guild_id: string; + icon: string; + id: string; + lastMessageId: string; + lastPinTimestamp: string | undefined; + member: unknown; + memberCount: number | undefined; + memberIdsPreview: string[] | undefined; + memberListId: unknown; + messageCount: number | undefined; + name: string; + nicks: Record<string, unknown>; + nsfw: boolean; + originChannelId: unknown; + ownerId: string; + parent_id: string; + permissionOverwrites: { + [role: string]: { + id: string; + type: number; + deny: bigint; + allow: bigint; + }; + }; + position: number; + rateLimitPerUser: number; + rawRecipients: { + id: string; + avatar: string; + username: string; + public_flags: number; + discriminator: string; + }[]; + recipients: string[]; + rtcRegion: string; + threadMetadata: { + locked: boolean; + archived: boolean; + invitable: boolean; + createTimestamp: string | undefined; + autoArchiveDuration: number; + archiveTimestamp: string | undefined; + }; + topic: string; + type: number; + userLimit: number; + videoQualityMode: undefined; + + get accessPermissions(): bigint; + get lastActiveTimestamp(): number; + + computeLurkerPermissionsAllowList(): unknown; + getApplicationId(): unknown; + getGuildId(): string; + getRecipientId(): unknown; + hasFlag(flag: number): boolean; + isActiveThread(): boolean; + isArchivedThread(): boolean; + isCategory(): boolean; + isDM(): boolean; + isDirectory(): boolean; + isForumChannel(): boolean; + isGroupDM(): boolean; + isGuildStageVoice(): boolean; + isGuildVoice(): boolean; + isListenModeCapable(): boolean; + isManaged(): boolean; + isMultiUserDM(): boolean; + isNSFW(): boolean; + isOwner(): boolean; + isPrivate(): boolean; + isSystemDM(): boolean; + isThread(): boolean; + isVocal(): boolean; +} diff --git a/packages/discord-types/src/common/Guild.d.ts b/packages/discord-types/src/common/Guild.d.ts new file mode 100644 index 00000000..5b5c3c74 --- /dev/null +++ b/packages/discord-types/src/common/Guild.d.ts @@ -0,0 +1,64 @@ +import { Role } from './Role'; +import { DiscordRecord } from './Record'; + +// copy(Object.keys(findByProps("CREATOR_MONETIZABLE")).map(JSON.stringify).join("|")) +export type GuildFeatures = + "INVITE_SPLASH" | "VIP_REGIONS" | "VANITY_URL" | "MORE_EMOJI" | "MORE_STICKERS" | "MORE_SOUNDBOARD" | "VERIFIED" | "COMMERCE" | "DISCOVERABLE" | "COMMUNITY" | "FEATURABLE" | "NEWS" | "HUB" | "PARTNERED" | "ANIMATED_ICON" | "BANNER" | "ENABLED_DISCOVERABLE_BEFORE" | "WELCOME_SCREEN_ENABLED" | "MEMBER_VERIFICATION_GATE_ENABLED" | "PREVIEW_ENABLED" | "ROLE_SUBSCRIPTIONS_ENABLED" | "ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE" | "CREATOR_MONETIZABLE" | "CREATOR_MONETIZABLE_PROVISIONAL" | "CREATOR_MONETIZABLE_WHITEGLOVE" | "CREATOR_MONETIZABLE_DISABLED" | "CREATOR_MONETIZABLE_RESTRICTED" | "CREATOR_STORE_PAGE" | "CREATOR_MONETIZABLE_PENDING_NEW_OWNER_ONBOARDING" | "PRODUCTS_AVAILABLE_FOR_PURCHASE" | "GUILD_WEB_PAGE_VANITY_URL" | "THREADS_ENABLED" | "THREADS_ENABLED_TESTING" | "NEW_THREAD_PERMISSIONS" | "ROLE_ICONS" | "TEXT_IN_STAGE_ENABLED" | "TEXT_IN_VOICE_ENABLED" | "HAS_DIRECTORY_ENTRY" | "ANIMATED_BANNER" | "LINKED_TO_HUB" | "EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT" | "GUILD_HOME_DEPRECATION_OVERRIDE" | "GUILD_HOME_TEST" | "GUILD_HOME_OVERRIDE" | "GUILD_ONBOARDING" | "GUILD_ONBOARDING_EVER_ENABLED" | "GUILD_ONBOARDING_HAS_PROMPTS" | "GUILD_SERVER_GUIDE" | "INTERNAL_EMPLOYEE_ONLY" | "AUTO_MODERATION" | "INVITES_DISABLED" | "BURST_REACTIONS" | "SOUNDBOARD" | "SHARD" | "ACTIVITY_FEED_ENABLED_BY_USER" | "ACTIVITY_FEED_DISABLED_BY_USER" | "SUMMARIES_ENABLED_GA" | "LEADERBOARD_ENABLED" | "SUMMARIES_ENABLED_BY_USER" | "SUMMARIES_OPT_OUT_EXPERIENCE" | "CHANNEL_ICON_EMOJIS_GENERATED" | "NON_COMMUNITY_RAID_ALERTS" | "RAID_ALERTS_DISABLED" | "AUTOMOD_TRIGGER_USER_PROFILE" | "ENABLED_MODERATION_EXPERIENCE_FOR_NON_COMMUNITY" | "GUILD_PRODUCTS_ALLOW_ARCHIVED_FILE" | "CLAN" | "MEMBER_VERIFICATION_MANUAL_APPROVAL" | "FORWARDING_DISABLED" | "MEMBER_VERIFICATION_ROLLOUT_TEST" | "AUDIO_BITRATE_128_KBPS" | "AUDIO_BITRATE_256_KBPS" | "AUDIO_BITRATE_384_KBPS" | "VIDEO_BITRATE_ENHANCED" | "MAX_FILE_SIZE_50_MB" | "MAX_FILE_SIZE_100_MB" | "GUILD_TAGS" | "ENHANCED_ROLE_COLORS" | "PREMIUM_TIER_3_OVERRIDE" | "REPORT_TO_MOD_PILOT" | "TIERLESS_BOOSTING_SYSTEM_MESSAGE"; +export type GuildPremiumFeatures = + "ANIMATED_ICON" | "STAGE_CHANNEL_VIEWERS_150" | "ROLE_ICONS" | "GUILD_TAGS" | "BANNER" | "MAX_FILE_SIZE_50_MB" | "VIDEO_QUALITY_720_60FPS" | "STAGE_CHANNEL_VIEWERS_50" | "VIDEO_QUALITY_1080_60FPS" | "MAX_FILE_SIZE_100_MB" | "VANITY_URL" | "VIDEO_BITRATE_ENHANCED" | "STAGE_CHANNEL_VIEWERS_300" | "AUDIO_BITRATE_128_KBPS" | "ANIMATED_BANNER" | "TIERLESS_BOOSTING" | "ENHANCED_ROLE_COLORS" | "INVITE_SPLASH" | "AUDIO_BITRATE_256_KBPS" | "AUDIO_BITRATE_384_KBPS"; + +export class Guild extends DiscordRecord { + constructor(guild: object); + afkChannelId: string | undefined; + afkTimeout: number; + applicationCommandCounts: { + 0: number; + 1: number; + 2: number; + }; + application_id: unknown; + banner: string | undefined; + defaultMessageNotifications: number; + description: string | undefined; + discoverySplash: string | undefined; + explicitContentFilter: number; + features: Set<GuildFeatures>; + homeHeader: string | undefined; + hubType: unknown; + icon: string | undefined; + id: string; + joinedAt: Date; + latestOnboardingQuestionId: string | undefined; + maxMembers: number; + maxStageVideoChannelUsers: number; + maxVideoChannelUsers: number; + mfaLevel: number; + moderatorReporting: unknown; + name: string; + nsfwLevel: number; + ownerConfiguredContentLevel: number; + ownerId: string; + preferredLocale: string; + premiumFeatures: { + additionalEmojiSlots: number; + additionalSoundSlots: number; + additionalStickerSlots: number; + features: Array<GuildPremiumFeatures>; + }; + premiumProgressBarEnabled: boolean; + premiumSubscriberCount: number; + premiumTier: number; + profile: { + badge: string | undefined; + tag: string | undefined; + } | undefined; + publicUpdatesChannelId: string | undefined; + roles: Record<string, Role>; + rulesChannelId: string | undefined; + safetyAlertsChannelId: string | undefined; + splash: string | undefined; + systemChannelFlags: number; + systemChannelId: string | undefined; + vanityURLCode: string | undefined; + verificationLevel: number; +} diff --git a/packages/discord-types/src/common/GuildMember.d.ts b/packages/discord-types/src/common/GuildMember.d.ts new file mode 100644 index 00000000..5cd47682 --- /dev/null +++ b/packages/discord-types/src/common/GuildMember.d.ts @@ -0,0 +1,26 @@ +export interface GuildMember { + avatar: string | undefined; + avatarDecoration: string | undefined; + banner: string | undefined; + bio: string; + colorRoleId: string | undefined; + colorString: string; + colorStrings: { + primaryColor: string | undefined; + secondaryColor: string | undefined; + tertiaryColor: string | undefined; + }; + communicationDisabledUntil: string | undefined; + flags: number; + fullProfileLoadedTimestamp: number; + guildId: string; + highestRoleId: string; + hoistRoleId: string; + iconRoleId: string; + isPending: boolean | undefined; + joinedAt: string | undefined; + nick: string | undefined; + premiumSince: string | undefined; + roles: string[]; + userId: string; +} diff --git a/packages/discord-types/src/common/Record.d.ts b/packages/discord-types/src/common/Record.d.ts new file mode 100644 index 00000000..8f033058 --- /dev/null +++ b/packages/discord-types/src/common/Record.d.ts @@ -0,0 +1,12 @@ +type Updater = (value: any) => any; + +/** + * Common Record class extended by various Discord data structures, like User, Channel, Guild, etc. + */ +export class DiscordRecord { + toJS(): Record<string, any>; + + set(key: string, value: any): this; + merge(data: Record<string, any>): this; + update(key: string, defaultValueOrUpdater: Updater | any, updater?: Updater): this; +} diff --git a/packages/discord-types/src/common/Role.d.ts b/packages/discord-types/src/common/Role.d.ts new file mode 100644 index 00000000..7b038984 --- /dev/null +++ b/packages/discord-types/src/common/Role.d.ts @@ -0,0 +1,33 @@ +export interface Role { + color: number; + colorString: string | undefined; + colorStrings: { + primaryColor: string | undefined; + secondaryColor: string | undefined; + tertiaryColor: string | undefined; + }; + colors: { + primary_color: number | undefined; + secondary_color: number | undefined; + tertiary_color: number | undefined; + }; + flags: number; + hoist: boolean; + icon: string | undefined; + id: string; + managed: boolean; + mentionable: boolean; + name: string; + originalPosition: number; + permissions: bigint; + position: number; + /** + * probably incomplete + */ + tags: { + bot_id: string; + integration_id: string; + premium_subscriber: unknown; + } | undefined; + unicodeEmoji: string | undefined; +} diff --git a/packages/discord-types/src/common/User.d.ts b/packages/discord-types/src/common/User.d.ts new file mode 100644 index 00000000..a5503bcb --- /dev/null +++ b/packages/discord-types/src/common/User.d.ts @@ -0,0 +1,66 @@ +// TODO: a lot of optional params can also be null, not just undef + +import { DiscordRecord } from "./Record"; + +export class User extends DiscordRecord { + constructor(user: object); + accentColor: number; + avatar: string; + banner: string; + bio: string; + bot: boolean; + desktop: boolean; + discriminator: string; + email: string | undefined; + flags: number; + globalName: string | undefined; + guildMemberAvatars: Record<string, string>; + id: string; + mfaEnabled: boolean; + mobile: boolean; + nsfwAllowed: boolean | undefined; + phone: string | undefined; + premiumType: number | undefined; + premiumUsageFlags: number; + publicFlags: number; + purchasedFlags: number; + system: boolean; + username: string; + verified: boolean; + themeColors?: [number, number]; + + get createdAt(): Date; + get hasPremiumPerks(): boolean; + get tag(): string; + get usernameNormalized(): string; + + addGuildAvatarHash(guildId: string, avatarHash: string): User; + getAvatarSource(guildId: string, canAnimate?: boolean): { uri: string; }; + getAvatarURL(guildId?: string | null, t?: unknown, canAnimate?: boolean): string; + hasAvatarForGuild(guildId: string): boolean; + hasDisabledPremium(): boolean; + hasFlag(flag: number): boolean; + hasFreePremium(): boolean; + hasHadSKU(e: unknown): boolean; + hasPremiumUsageFlag(flag: number): boolean; + hasPurchasedFlag(flag: number): boolean; + hasUrgentMessages(): boolean; + isClaimed(): boolean; + isLocalBot(): boolean; + isNonUserBot(): boolean; + isPhoneVerified(): boolean; + isStaff(): boolean; + isSystemUser(): boolean; + isVerifiedBot(): boolean; + removeGuildAvatarHash(guildId: string): User; + toString(): string; +} + +export interface UserJSON { + avatar: string; + avatarDecoration: unknown | undefined; + discriminator: string; + id: string; + publicFlags: number; + username: string; +} diff --git a/packages/discord-types/src/common/index.d.ts b/packages/discord-types/src/common/index.d.ts new file mode 100644 index 00000000..f85a7c72 --- /dev/null +++ b/packages/discord-types/src/common/index.d.ts @@ -0,0 +1,7 @@ +export * from "./Channel"; +export * from "./Guild"; +export * from "./GuildMember"; +export * from "./messages"; +export * from "./Role"; +export * from "./User"; +export * from "./Record"; diff --git a/packages/discord-types/src/common/messages/Commands.d.ts b/packages/discord-types/src/common/messages/Commands.d.ts new file mode 100644 index 00000000..8dc9f9a7 --- /dev/null +++ b/packages/discord-types/src/common/messages/Commands.d.ts @@ -0,0 +1,61 @@ +import { Channel } from "../Channel"; +import { Guild } from "../Guild"; +import { Promisable } from "type-fest"; +import { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType } from "../../../enums"; + +export interface CommandContext { + channel: Channel; + guild?: Guild; +} + +export interface CommandOption { + name: string; + displayName?: string; + type: ApplicationCommandOptionType; + description: string; + displayDescription?: string; + required?: boolean; + options?: CommandOption[]; + choices?: Array<ChoicesOption>; +} + +export interface ChoicesOption { + label: string; + value: string; + name: string; + displayName?: string; +} + +export interface CommandReturnValue { + content: string; + // TODO: implement + // cancel?: boolean; +} + +export interface CommandArgument { + type: ApplicationCommandOptionType; + name: string; + value: string; + focused: undefined; + options: CommandArgument[]; +} + +export interface Command { + id?: string; + applicationId?: string; + type?: ApplicationCommandType; + inputType?: ApplicationCommandInputType; + plugin?: string; + + name: string; + untranslatedName?: string; + displayName?: string; + description: string; + untranslatedDescription?: string; + displayDescription?: string; + + options?: CommandOption[]; + predicate?(ctx: CommandContext): boolean; + + execute(args: CommandArgument[], ctx: CommandContext): Promisable<void | CommandReturnValue>; +} diff --git a/packages/discord-types/src/common/messages/Embed.d.ts b/packages/discord-types/src/common/messages/Embed.d.ts new file mode 100644 index 00000000..4edd9ced --- /dev/null +++ b/packages/discord-types/src/common/messages/Embed.d.ts @@ -0,0 +1,70 @@ +export interface Embed { + author?: { + name: string; + url: string; + iconURL: string | undefined; + iconProxyURL: string | undefined; + }; + color: string; + fields: []; + id: string; + image?: { + height: number; + width: number; + url: string; + proxyURL: string; + }; + provider?: { + name: string; + url: string | undefined; + }; + rawDescription: string; + rawTitle: string; + referenceId: unknown; + timestamp: string; + thumbnail?: { + height: number; + proxyURL: string | undefined; + url: string; + width: number; + }; + type: string; + url: string | undefined; + video?: { + height: number; + width: number; + url: string; + proxyURL: string | undefined; + }; +} + +export interface EmbedJSON { + author?: { + name: string; + url: string; + icon_url: string; + proxy_icon_url: string; + }; + title: string; + color: string; + description: string; + type: string; + url: string | undefined; + provider?: { + name: string; + url: string; + }; + timestamp: string; + thumbnail?: { + height: number; + width: number; + url: string; + proxy_url: string | undefined; + }; + video?: { + height: number; + width: number; + url: string; + proxy_url: string | undefined; + }; +} diff --git a/packages/discord-types/src/common/messages/Emoji.d.ts b/packages/discord-types/src/common/messages/Emoji.d.ts new file mode 100644 index 00000000..793e90f8 --- /dev/null +++ b/packages/discord-types/src/common/messages/Emoji.d.ts @@ -0,0 +1,42 @@ +export type Emoji = CustomEmoji | UnicodeEmoji; + +export interface CustomEmoji { + type: 1; + allNamesString: string; + animated: boolean; + available: boolean; + guildId: string; + id: string; + managed: boolean; + name: string; + originalName?: string; + require_colons: boolean; + roles: string[]; +} + +export interface UnicodeEmoji { + type: 0; + diversityChildren: Record<any, any>; + emojiObject: { + names: string[]; + surrogates: string; + unicodeVersion: number; + }; + index: number; + surrogates: string; + uniqueName: string; + useSpriteSheet: boolean; + get allNamesString(): string; + get animated(): boolean; + get defaultDiversityChild(): any; + get hasDiversity(): boolean | undefined; + get hasDiversityParent(): boolean | undefined; + get hasMultiDiversity(): boolean | undefined; + get hasMultiDiversityParent(): boolean | undefined; + get managed(): boolean; + get name(): string; + get names(): string[]; + get optionallyDiverseSequence(): string | undefined; + get unicodeVersion(): number; + get url(): string; +} diff --git a/packages/discord-types/src/common/messages/Message.d.ts b/packages/discord-types/src/common/messages/Message.d.ts new file mode 100644 index 00000000..38010caf --- /dev/null +++ b/packages/discord-types/src/common/messages/Message.d.ts @@ -0,0 +1,191 @@ +import { CommandOption } from './Commands'; +import { User, UserJSON } from '../User'; +import { Embed, EmbedJSON } from './Embed'; +import { DiscordRecord } from "../Record"; + +/** + * TODO: looks like discord has moved over to Date instead of Moment; + */ +export class Message extends DiscordRecord { + constructor(message: object); + activity: unknown; + application: unknown; + applicationId: string | unknown; + attachments: MessageAttachment[]; + author: User; + blocked: boolean; + bot: boolean; + call: { + duration: moment.Duration; + endedTimestamp: moment.Moment; + participants: string[]; + }; + channel_id: string; + /** + * NOTE: not fully typed + */ + codedLinks: { + code?: string; + type: string; + }[]; + colorString: unknown; + components: unknown[]; + content: string; + customRenderedContent: unknown; + editedTimestamp: Date; + embeds: Embed[]; + flags: number; + giftCodes: string[]; + id: string; + interaction: { + id: string; + name: string; + type: number; + user: User; + }[] | undefined; + interactionData: { + application_command: { + application_id: string; + default_member_permissions: unknown; + default_permission: boolean; + description: string; + dm_permission: unknown; + id: string; + name: string; + options: CommandOption[]; + permissions: unknown[]; + type: number; + version: string; + }; + attachments: MessageAttachment[]; + guild_id: string | undefined; + id: string; + name: string; + options: { + focused: unknown; + name: string; + type: number; + value: string; + }[]; + type: number; + version: string; + }[]; + interactionError: unknown[]; + isSearchHit: boolean; + loggingName: unknown; + mentionChannels: string[]; + mentionEveryone: boolean; + mentionRoles: string[]; + mentioned: boolean; + mentions: string[]; + messageReference: { + guild_id?: string; + channel_id: string; + message_id: string; + } | undefined; + nick: unknown; // probably a string + nonce: string | undefined; + pinned: boolean; + reactions: MessageReaction[]; + state: string; + stickerItems: { + format_type: number; + id: string; + name: string; + }[]; + stickers: unknown[]; + timestamp: moment.Moment; + tts: boolean; + type: number; + webhookId: string | undefined; + + /** + * Doesn't actually update the original message; it just returns a new message instance with the added reaction. + */ + addReaction(emoji: ReactionEmoji, fromCurrentUser: boolean): Message; + /** + * Searches each reaction and if the provided string has an index above -1 it'll return the reaction object. + */ + getReaction(name: string): MessageReaction; + /** + * Doesn't actually update the original message; it just returns the message instance without the reaction searched with the provided emoji object. + */ + removeReactionsForEmoji(emoji: ReactionEmoji): Message; + /** + * Doesn't actually update the original message; it just returns the message instance without the reaction. + */ + removeReaction(emoji: ReactionEmoji, fromCurrentUser: boolean): Message; + + getChannelId(): string; + hasFlag(flag: number): boolean; + isCommandType(): boolean; + isEdited(): boolean; + isSystemDM(): boolean; +} + +/** A smaller Message object found in FluxDispatcher and elsewhere. */ +export interface MessageJSON { + attachments: MessageAttachment[]; + author: UserJSON; + channel_id: string; + components: unknown[]; + content: string; + edited_timestamp: string; + embeds: EmbedJSON[]; + flags: number; + guild_id: string | undefined; + id: string; + loggingName: unknown; + member: { + avatar: string | undefined; + communication_disabled_until: string | undefined; + deaf: boolean; + hoisted_role: string | undefined; + is_pending: boolean; + joined_at: string; + mute: boolean; + nick: string | boolean; + pending: boolean; + premium_since: string | undefined; + roles: string[]; + } | undefined; + mention_everyone: boolean; + mention_roles: string[]; + mentions: UserJSON[]; + message_reference: { + guild_id?: string; + channel_id: string; + message_id: string; + } | undefined; + nonce: string | undefined; + pinned: boolean; + referenced_message: MessageJSON | undefined; + state: string; + timestamp: string; + tts: boolean; + type: number; +} + +export interface MessageAttachment { + filename: string; + id: string; + proxy_url: string; + size: number; + spoiler: boolean; + url: string; + content_type?: string; + width?: number; + height?: number; +} + +export interface ReactionEmoji { + id: string | undefined; + name: string; + animated: boolean; +} + +export interface MessageReaction { + count: number; + emoji: ReactionEmoji; + me: boolean; +} diff --git a/packages/discord-types/src/common/messages/index.d.ts b/packages/discord-types/src/common/messages/index.d.ts new file mode 100644 index 00000000..245e971e --- /dev/null +++ b/packages/discord-types/src/common/messages/index.d.ts @@ -0,0 +1,4 @@ +export * from "./Commands"; +export * from "./Message"; +export * from "./Embed"; +export * from "./Emoji"; diff --git a/src/webpack/common/types/components.d.ts b/packages/discord-types/src/components.d.ts similarity index 89% rename from src/webpack/common/types/components.d.ts rename to packages/discord-types/src/components.d.ts index 783663cb..8b2fd1cf 100644 --- a/src/webpack/common/types/components.d.ts +++ b/packages/discord-types/src/components.d.ts @@ -1,25 +1,7 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2023 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - import type { ComponentClass, ComponentPropsWithRef, ComponentType, CSSProperties, FunctionComponent, HtmlHTMLAttributes, HTMLProps, JSX, KeyboardEvent, MouseEvent, PointerEvent, PropsWithChildren, ReactNode, Ref, RefObject } from "react"; - -export type TextVariant = "heading-sm/normal" | "heading-sm/medium" | "heading-sm/semibold" | "heading-sm/bold" | "heading-md/normal" | "heading-md/medium" | "heading-md/semibold" | "heading-md/bold" | "heading-lg/normal" | "heading-lg/medium" | "heading-lg/semibold" | "heading-lg/bold" | "heading-xl/normal" | "heading-xl/medium" | "heading-xl/bold" | "heading-xxl/normal" | "heading-xxl/medium" | "heading-xxl/bold" | "eyebrow" | "heading-deprecated-14/normal" | "heading-deprecated-14/medium" | "heading-deprecated-14/bold" | "text-xxs/normal" | "text-xxs/medium" | "text-xxs/semibold" | "text-xxs/bold" | "text-xs/normal" | "text-xs/medium" | "text-xs/semibold" | "text-xs/bold" | "text-sm/normal" | "text-sm/medium" | "text-sm/semibold" | "text-sm/bold" | "text-md/normal" | "text-md/medium" | "text-md/semibold" | "text-md/bold" | "text-lg/normal" | "text-lg/medium" | "text-lg/semibold" | "text-lg/bold" | "display-sm" | "display-md" | "display-lg" | "code"; +// copy(find(m => Array.isArray(m) && m.includes("heading-sm/normal")).map(JSON.stringify).join("|")) +export type TextVariant = "heading-sm/normal" | "heading-sm/medium" | "heading-sm/semibold" | "heading-sm/bold" | "heading-sm/extrabold" | "heading-md/normal" | "heading-md/medium" | "heading-md/semibold" | "heading-md/bold" | "heading-md/extrabold" | "heading-lg/normal" | "heading-lg/medium" | "heading-lg/semibold" | "heading-lg/bold" | "heading-lg/extrabold" | "heading-xl/normal" | "heading-xl/medium" | "heading-xl/semibold" | "heading-xl/bold" | "heading-xl/extrabold" | "heading-xxl/normal" | "heading-xxl/medium" | "heading-xxl/semibold" | "heading-xxl/bold" | "heading-xxl/extrabold" | "eyebrow" | "heading-deprecated-12/normal" | "heading-deprecated-12/medium" | "heading-deprecated-12/semibold" | "heading-deprecated-12/bold" | "heading-deprecated-12/extrabold" | "redesign/heading-18/bold" | "text-xxs/normal" | "text-xxs/medium" | "text-xxs/semibold" | "text-xxs/bold" | "text-xs/normal" | "text-xs/medium" | "text-xs/semibold" | "text-xs/bold" | "text-sm/normal" | "text-sm/medium" | "text-sm/semibold" | "text-sm/bold" | "text-md/normal" | "text-md/medium" | "text-md/semibold" | "text-md/bold" | "text-lg/normal" | "text-lg/medium" | "text-lg/semibold" | "text-lg/bold" | "redesign/message-preview/normal" | "redesign/message-preview/medium" | "redesign/message-preview/semibold" | "redesign/message-preview/bold" | "redesign/channel-title/normal" | "redesign/channel-title/medium" | "redesign/channel-title/semibold" | "redesign/channel-title/bold" | "display-sm" | "display-md" | "display-lg" | "code"; export type FormTextTypes = Record<"DEFAULT" | "INPUT_PLACEHOLDER" | "DESCRIPTION" | "LABEL_BOLD" | "LABEL_SELECTED" | "LABEL_DESCRIPTOR" | "ERROR" | "SUCCESS", string>; export type HeadingTag = `h${1 | 2 | 3 | 4 | 5 | 6}`; diff --git a/packages/discord-types/src/flux.d.ts b/packages/discord-types/src/flux.d.ts new file mode 100644 index 00000000..bb5600dd --- /dev/null +++ b/packages/discord-types/src/flux.d.ts @@ -0,0 +1,30 @@ +import { FluxStore } from "./stores/FluxStore"; + +export class FluxEmitter { + constructor(); + + changeSentinel: number; + changedStores: Set<FluxStore>; + isBatchEmitting: boolean; + isDispatching: boolean; + isPaused: boolean; + pauseTimer: NodeJS.Timeout | null; + reactChangedStores: Set<FluxStore>; + + batched(batch: (...args: any[]) => void): void; + destroy(): void; + emit(): void; + emitNonReactOnce(): void; + emitReactOnce(): void; + getChangeSentinel(): number; + getIsPaused(): boolean; + injectBatchEmitChanges(batch: (...args: any[]) => void): void; + markChanged(store: FluxStore): void; + pause(): void; + resume(): void; +} + +export interface Flux { + Store: typeof FluxStore; + Emitter: FluxEmitter; +} diff --git a/packages/discord-types/src/fluxEvents.d.ts b/packages/discord-types/src/fluxEvents.d.ts new file mode 100644 index 00000000..c210f4b9 --- /dev/null +++ b/packages/discord-types/src/fluxEvents.d.ts @@ -0,0 +1,22 @@ +/* +function makeFluxEventList() { + // prefill MESSAGE_CREATE so that typescript infers this is a String Set + // without explicitly typing so that this function is also valid javascript + const events = new Set(["MESSAGE_CREATE"]); + + const { nodes } = Vencord.Webpack.Common.FluxDispatcher._actionHandlers._dependencyGraph; + for (const nodeId in nodes) { + for (const event in nodes[nodeId].actionHandler) { + events.add(event); + } + } + for (const event in Vencord.Webpack.Common.FluxDispatcher._subscriptions) { + events.add(event); + } + + return Array.from(events, e => JSON.stringify(e)).sort().join("|"); +} +copy(makeFluxEventList()) +*/ + +export type FluxEvents = "ACCESSIBILITY_COLORBLIND_TOGGLE" | "ACCESSIBILITY_DARK_SIDEBAR_TOGGLE" | "ACCESSIBILITY_DESATURATE_ROLES_TOGGLE" | "ACCESSIBILITY_FORCED_COLORS_MODAL_SEEN" | "ACCESSIBILITY_KEYBOARD_MODE_DISABLE" | "ACCESSIBILITY_KEYBOARD_MODE_ENABLE" | "ACCESSIBILITY_LOW_CONTRAST_TOGGLE" | "ACCESSIBILITY_RESET_TO_DEFAULT" | "ACCESSIBILITY_SET_ALWAYS_SHOW_LINK_DECORATIONS" | "ACCESSIBILITY_SET_CONTRAST" | "ACCESSIBILITY_SET_FONT_SIZE" | "ACCESSIBILITY_SET_MESSAGE_GROUP_SPACING" | "ACCESSIBILITY_SET_PREFERS_REDUCED_MOTION" | "ACCESSIBILITY_SET_ROLE_STYLE" | "ACCESSIBILITY_SET_SATURATION" | "ACCESSIBILITY_SET_SYNC_FORCED_COLORS" | "ACCESSIBILITY_SET_ZOOM" | "ACCESSIBILITY_SUBMIT_BUTTON_TOGGLE" | "ACCESSIBILITY_SYNC_PROFILE_THEME_WITH_USER_THEME_TOGGLE" | "ACCESSIBILITY_SYSTEM_COLOR_PREFERENCES_CHANGED" | "ACCESSIBILITY_SYSTEM_PREFERS_CONTRAST_CHANGED" | "ACCESSIBILITY_SYSTEM_PREFERS_CROSSFADES_CHANGED" | "ACCESSIBILITY_SYSTEM_PREFERS_REDUCED_MOTION_CHANGED" | "ACKNOWLEDGE_CHANNEL_SAFETY_WARNING_TOOLTIP" | "ACK_APPROVED_GUILD_JOIN_REQUEST" | "ACTIVE_AV_ERRORS_CHANGED" | "ACTIVE_BOGO_PROMOTION_FETCH" | "ACTIVE_BOGO_PROMOTION_FETCH_FAIL" | "ACTIVE_BOGO_PROMOTION_FETCH_SUCCESS" | "ACTIVE_CHANNELS_FETCH_FAILURE" | "ACTIVE_CHANNELS_FETCH_START" | "ACTIVE_CHANNELS_FETCH_SUCCESS" | "ACTIVE_OUTBOUND_PROMOTIONS_FETCH" | "ACTIVE_OUTBOUND_PROMOTIONS_FETCH_FAIL" | "ACTIVE_OUTBOUND_PROMOTIONS_FETCH_SUCCESS" | "ACTIVITY_INVITE_EDUCATION_DISMISS" | "ACTIVITY_INVITE_MODAL_CLOSE" | "ACTIVITY_INVITE_MODAL_OPEN" | "ACTIVITY_INVITE_MODAL_QUERY" | "ACTIVITY_INVITE_MODAL_SEND" | "ACTIVITY_JOIN" | "ACTIVITY_JOIN_FAILED" | "ACTIVITY_JOIN_LOADING" | "ACTIVITY_LAUNCH_FAIL" | "ACTIVITY_LAYOUT_MODE_UPDATE" | "ACTIVITY_METADATA_UPDATE" | "ACTIVITY_PLAY" | "ACTIVITY_POPOUT_WINDOW_OPEN" | "ACTIVITY_SCREEN_ORIENTATION_UPDATE" | "ACTIVITY_START" | "ACTIVITY_SYNC" | "ACTIVITY_SYNC_STOP" | "ACTIVITY_UPDATE_FAIL" | "ACTIVITY_UPDATE_START" | "ACTIVITY_UPDATE_SUCCESS" | "ADD_STICKER_PREVIEW" | "ADMIN_ONBOARDING_GUIDE_HIDE" | "ADYEN_CASH_APP_PAY_SUBMIT_SUCCESS" | "ADYEN_CREATE_CASH_APP_PAY_COMPONENT_SUCCESS" | "ADYEN_CREATE_CLIENT_SUCCESS" | "ADYEN_TEARDOWN_CLIENT" | "AFK" | "AGE_GATE_FAILURE_MODAL_OPEN" | "AGE_GATE_LOGOUT_UNDERAGE_NEW_USER" | "AGE_GATE_MODAL_CLOSE" | "AGE_GATE_MODAL_OPEN" | "AGE_GATE_SUCCESS_MODAL_OPEN" | "APEX_EXPERIMENT_CLEAR_SERVER_ASSIGNMENTS" | "APEX_EXPERIMENT_OVERRIDE_CLEAR" | "APEX_EXPERIMENT_OVERRIDE_CREATE" | "APEX_EXPERIMENT_OVERRIDE_DELETE" | "APPLICATIONS_FETCH" | "APPLICATIONS_FETCH_FAIL" | "APPLICATIONS_FETCH_SUCCESS" | "APPLICATION_ACTIVITY_STATISTICS_FETCH_FAIL" | "APPLICATION_ACTIVITY_STATISTICS_FETCH_START" | "APPLICATION_ACTIVITY_STATISTICS_FETCH_SUCCESS" | "APPLICATION_ASSETS_FETCH" | "APPLICATION_ASSETS_FETCH_SUCCESS" | "APPLICATION_ASSETS_UPDATE" | "APPLICATION_BRANCHES_FETCH_FAIL" | "APPLICATION_BRANCHES_FETCH_SUCCESS" | "APPLICATION_BUILD_FETCH_START" | "APPLICATION_BUILD_FETCH_SUCCESS" | "APPLICATION_BUILD_NOT_FOUND" | "APPLICATION_BUILD_SIZE_FETCH_FAIL" | "APPLICATION_BUILD_SIZE_FETCH_START" | "APPLICATION_BUILD_SIZE_FETCH_SUCCESS" | "APPLICATION_COMMAND_AUTOCOMPLETE_REQUEST" | "APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE" | "APPLICATION_COMMAND_EXECUTE_BAD_VERSION" | "APPLICATION_COMMAND_INDEX_FETCH_FAILURE" | "APPLICATION_COMMAND_INDEX_FETCH_REQUEST" | "APPLICATION_COMMAND_INDEX_FETCH_SUCCESS" | "APPLICATION_COMMAND_SET_ACTIVE_COMMAND" | "APPLICATION_COMMAND_SET_PREFERRED_COMMAND" | "APPLICATION_COMMAND_UPDATE_CHANNEL_STATE" | "APPLICATION_COMMAND_UPDATE_OPTIONS" | "APPLICATION_COMMAND_USED" | "APPLICATION_DIRECTORY_FETCH_APPLICATION" | "APPLICATION_DIRECTORY_FETCH_APPLICATION_FAILURE" | "APPLICATION_DIRECTORY_FETCH_APPLICATION_SUCCESS" | "APPLICATION_DIRECTORY_FETCH_CATEGORIES_SUCCESS" | "APPLICATION_DIRECTORY_FETCH_COLLECTIONS" | "APPLICATION_DIRECTORY_FETCH_COLLECTIONS_FAILURE" | "APPLICATION_DIRECTORY_FETCH_COLLECTIONS_SUCCESS" | "APPLICATION_DIRECTORY_FETCH_SEARCH" | "APPLICATION_DIRECTORY_FETCH_SEARCH_FAILURE" | "APPLICATION_DIRECTORY_FETCH_SEARCH_SUCCESS" | "APPLICATION_DIRECTORY_FETCH_SIMILAR_APPLICATIONS" | "APPLICATION_DIRECTORY_FETCH_SIMILAR_APPLICATIONS_FAILURE" | "APPLICATION_DIRECTORY_FETCH_SIMILAR_APPLICATIONS_SUCCESS" | "APPLICATION_FETCH" | "APPLICATION_FETCH_FAIL" | "APPLICATION_FETCH_SUCCESS" | "APPLICATION_STORE_ACCEPT_EULA" | "APPLICATION_STORE_ACCEPT_STORE_TERMS" | "APPLICATION_STORE_CLEAR_DATA" | "APPLICATION_STORE_DIRECTORY_LAYOUT_FETCHING" | "APPLICATION_STORE_DIRECTORY_LAYOUT_FETCH_FAILED" | "APPLICATION_STORE_DIRECTORY_LAYOUT_FETCH_SUCCESS" | "APPLICATION_STORE_LOCATION_CHANGE" | "APPLICATION_STORE_MATURE_AGREE" | "APPLICATION_STORE_RESET_NAVIGATION" | "APPLICATION_SUBSCRIPTIONS_CHANNEL_NOTICE_DISMISSED" | "APPLICATION_SUBSCRIPTIONS_FETCH_ENTITLEMENTS" | "APPLICATION_SUBSCRIPTIONS_FETCH_ENTITLEMENTS_FAILURE" | "APPLICATION_SUBSCRIPTIONS_FETCH_ENTITLEMENTS_SUCCESS" | "APPLICATION_SUBSCRIPTIONS_FETCH_LISTINGS" | "APPLICATION_SUBSCRIPTIONS_FETCH_LISTINGS_FAILURE" | "APPLICATION_SUBSCRIPTIONS_FETCH_LISTINGS_SUCCESS" | "APPLICATION_SUBSCRIPTIONS_FETCH_LISTING_FOR_PLAN_SUCCESS" | "APPLICATION_UPDATE" | "APPLIED_BOOSTS_COOLDOWN_FETCH_SUCCESS" | "APPLIED_GUILD_BOOST_COUNT_RESET" | "APPLIED_GUILD_BOOST_COUNT_UPDATE" | "APP_DM_OPEN" | "APP_ICON_EDITOR_RESET" | "APP_ICON_TRACK_IMPRESSION" | "APP_ICON_UPDATED" | "APP_LAUNCHER_ADD_FAILED_APP_DM_LOAD" | "APP_LAUNCHER_DISMISS" | "APP_LAUNCHER_REMOVE_FAILED_APP_DM_LOAD" | "APP_LAUNCHER_SET_ACTIVE_COMMAND" | "APP_LAUNCHER_SHOW" | "APP_RECOMMENDATIONS_FETCH_RECOMMENDATIONS" | "APP_RECOMMENDATIONS_FETCH_RECOMMENDATIONS_FAILURE" | "APP_RECOMMENDATIONS_FETCH_RECOMMENDATIONS_SUCCESS" | "APP_STATE_UPDATE" | "APP_VIEW_SET_HOME_LINK" | "AUDIO_INPUT_DETECTED" | "AUDIO_RESET" | "AUDIO_SET_ACTIVE_INPUT_PROFILE" | "AUDIO_SET_ATTENUATION" | "AUDIO_SET_AUTOMATIC_GAIN_CONTROL" | "AUDIO_SET_BYPASS_SYSTEM_INPUT_PROCESSING" | "AUDIO_SET_DEBUG_LOGGING" | "AUDIO_SET_DISPLAY_SILENCE_WARNING" | "AUDIO_SET_ECHO_CANCELLATION" | "AUDIO_SET_INPUT_DEVICE" | "AUDIO_SET_INPUT_VOLUME" | "AUDIO_SET_KRISP_MODEL_OVERRIDE" | "AUDIO_SET_KRISP_SUPPRESSION_LEVEL" | "AUDIO_SET_LOCAL_PAN" | "AUDIO_SET_LOCAL_VIDEO_DISABLED" | "AUDIO_SET_LOCAL_VOLUME" | "AUDIO_SET_LOOPBACK" | "AUDIO_SET_MODE" | "AUDIO_SET_NOISE_CANCELLATION" | "AUDIO_SET_NOISE_SUPPRESSION" | "AUDIO_SET_OUTPUT_DEVICE" | "AUDIO_SET_OUTPUT_VOLUME" | "AUDIO_SET_QOS" | "AUDIO_SET_SELF_MUTE" | "AUDIO_SET_SIDECHAIN_COMPRESSION" | "AUDIO_SET_SIDECHAIN_COMPRESSION_STRENGTH" | "AUDIO_SET_SUBSYSTEM" | "AUDIO_SET_TEMPORARY_SELF_MUTE" | "AUDIO_TOGGLE_LOCAL_MUTE" | "AUDIO_TOGGLE_LOCAL_SOUNDBOARD_MUTE" | "AUDIO_TOGGLE_SELF_DEAF" | "AUDIO_TOGGLE_SELF_MUTE" | "AUDIO_VOLUME_CHANGE" | "AUDIT_LOG_FETCH_FAIL" | "AUDIT_LOG_FETCH_NEXT_PAGE_FAIL" | "AUDIT_LOG_FETCH_NEXT_PAGE_START" | "AUDIT_LOG_FETCH_NEXT_PAGE_SUCCESS" | "AUDIT_LOG_FETCH_START" | "AUDIT_LOG_FETCH_SUCCESS" | "AUDIT_LOG_FILTER_BY_ACTION" | "AUDIT_LOG_FILTER_BY_TARGET" | "AUDIT_LOG_FILTER_BY_USER" | "AUTHENTICATOR_CREATE" | "AUTHENTICATOR_DELETE" | "AUTHENTICATOR_UPDATE" | "AUTH_INVITE_UPDATE" | "AUTH_SESSION_CHANGE" | "AUTO_MODERATION_MENTION_RAID_DETECTION" | "AUTO_MODERATION_MENTION_RAID_NOTICE_DISMISS" | "AUTO_UPDATER_QUIT_AND_INSTALL" | "BACKGROUND_SYNC" | "BACKGROUND_SYNC_CHANNEL_MESSAGES" | "BASIC_GUILD_FETCH" | "BASIC_GUILD_FETCH_FAILURE" | "BASIC_GUILD_FETCH_SUCCESS" | "BILLING_CREATE_REFERRAL_SUCCESS" | "BILLING_IP_COUNTRY_CODE_FAILURE" | "BILLING_IP_COUNTRY_CODE_FETCH_START" | "BILLING_IP_LOCATION_FAILURE" | "BILLING_IP_LOCATION_FETCH_START" | "BILLING_LOCALIZED_PRICING_PROMO_FAILURE" | "BILLING_MOST_RECENT_SUBSCRIPTION_FETCH_SUCCESS" | "BILLING_NITRO_AFFINITY_FETCHED" | "BILLING_NITRO_AFFINITY_FETCH_SUCCEEDED" | "BILLING_PAYMENTS_FETCH_SUCCESS" | "BILLING_PAYMENT_FETCH_SUCCESS" | "BILLING_PAYMENT_SOURCES_FETCH_FAIL" | "BILLING_PAYMENT_SOURCES_FETCH_START" | "BILLING_PAYMENT_SOURCES_FETCH_SUCCESS" | "BILLING_PAYMENT_SOURCE_CREATE_FAIL" | "BILLING_PAYMENT_SOURCE_CREATE_START" | "BILLING_PAYMENT_SOURCE_CREATE_SUCCESS" | "BILLING_PAYMENT_SOURCE_FETCH_SUCCESS" | "BILLING_PAYMENT_SOURCE_REMOVE_CLEAR_ERROR" | "BILLING_PAYMENT_SOURCE_REMOVE_FAIL" | "BILLING_PAYMENT_SOURCE_REMOVE_START" | "BILLING_PAYMENT_SOURCE_REMOVE_SUCCESS" | "BILLING_PAYMENT_SOURCE_UPDATE_CLEAR_ERROR" | "BILLING_PAYMENT_SOURCE_UPDATE_FAIL" | "BILLING_PAYMENT_SOURCE_UPDATE_START" | "BILLING_PAYMENT_SOURCE_UPDATE_SUCCESS" | "BILLING_POPUP_BRIDGE_CALLBACK" | "BILLING_POPUP_BRIDGE_STATE_UPDATE" | "BILLING_PREVIOUS_PREMIUM_SUBSCRIPTION_FETCH_SUCCESS" | "BILLING_PURCHASE_TOKEN_AUTH_CLEAR_STATE" | "BILLING_REFERRALS_REMAINING_FETCH_FAIL" | "BILLING_REFERRALS_REMAINING_FETCH_START" | "BILLING_REFERRALS_REMAINING_FETCH_SUCCESS" | "BILLING_REFERRAL_RESOLVE_FAIL" | "BILLING_REFERRAL_RESOLVE_SUCCESS" | "BILLING_REFERRAL_TRIAL_OFFER_UPDATE" | "BILLING_SET_IP_COUNTRY_CODE" | "BILLING_SET_IP_LOCATION" | "BILLING_SET_LOCALIZED_PRICING_PROMO" | "BILLING_SUBSCRIPTION_CANCEL_FAIL" | "BILLING_SUBSCRIPTION_CANCEL_START" | "BILLING_SUBSCRIPTION_CANCEL_SUCCESS" | "BILLING_SUBSCRIPTION_FETCH_FAIL" | "BILLING_SUBSCRIPTION_FETCH_START" | "BILLING_SUBSCRIPTION_FETCH_SUCCESS" | "BILLING_SUBSCRIPTION_RESET" | "BILLING_SUBSCRIPTION_REWARD_ELIGIBILITY_FETCH_FAILURE" | "BILLING_SUBSCRIPTION_REWARD_ELIGIBILITY_FETCH_START" | "BILLING_SUBSCRIPTION_REWARD_ELIGIBILITY_FETCH_SUCCESS" | "BILLING_SUBSCRIPTION_UPDATE_FAIL" | "BILLING_SUBSCRIPTION_UPDATE_START" | "BILLING_SUBSCRIPTION_UPDATE_SUCCESS" | "BILLING_USER_OFFER_ACKNOWLEDGED_SUCCESS" | "BILLING_USER_OFFER_FETCH_FAIL" | "BILLING_USER_OFFER_FETCH_START" | "BILLING_USER_OFFER_FETCH_SUCCESS" | "BILLING_USER_TRIAL_OFFER_ACKNOWLEDGED_SUCCESS" | "BILLING_USER_TRIAL_OFFER_FETCH_SUCCESS" | "BOOSTED_GUILD_GRACE_PERIOD_NOTICE_DISMISS" | "BRAINTREE_CREATE_CLIENT_SUCCESS" | "BRAINTREE_CREATE_PAYPAL_CLIENT_SUCCESS" | "BRAINTREE_CREATE_VENMO_CLIENT_SUCCESS" | "BRAINTREE_TEARDOWN_PAYPAL_CLIENT" | "BRAINTREE_TEARDOWN_VENMO_CLIENT" | "BRAINTREE_TOKENIZE_PAYPAL_FAIL" | "BRAINTREE_TOKENIZE_PAYPAL_START" | "BRAINTREE_TOKENIZE_PAYPAL_SUCCESS" | "BRAINTREE_TOKENIZE_VENMO_FAIL" | "BRAINTREE_TOKENIZE_VENMO_START" | "BRAINTREE_TOKENIZE_VENMO_SUCCESS" | "BROWSER_HANDOFF_BEGIN" | "BROWSER_HANDOFF_FROM_APP" | "BROWSER_HANDOFF_SET_USER" | "BROWSER_HANDOFF_UNAVAILABLE" | "BUILD_OVERRIDE_RESOLVED" | "BULK_ACK" | "BULK_CLEAR_RECENTS" | "BURST_REACTION_ANIMATION_ADD" | "BURST_REACTION_EFFECT_CLEAR" | "BURST_REACTION_EFFECT_PLAY" | "BURST_REACTION_PICKER_ANIMATION_ADD" | "BURST_REACTION_PICKER_ANIMATION_CLEAR" | "CACHED_EMOJIS_LOADED" | "CACHED_STICKERS_LOADED" | "CACHE_LOADED" | "CACHE_LOADED_LAZY" | "CACHE_LOADED_LAZY_NO_CACHE" | "CALL_CHAT_TOASTS_SET_ENABLED" | "CALL_CONNECT" | "CALL_CONNECT_MULTIPLE" | "CALL_CREATE" | "CALL_DELETE" | "CALL_ENQUEUE_RING" | "CALL_UPDATE" | "CANDIDATE_GAMES_CHANGE" | "CATEGORY_COLLAPSE" | "CATEGORY_COLLAPSE_ALL" | "CATEGORY_EXPAND" | "CATEGORY_EXPAND_ALL" | "CERTIFIED_DEVICES_SET" | "CHANGE_LOG_FETCH_FAILED" | "CHANGE_LOG_FETCH_SUCCESS" | "CHANGE_LOG_LOCK" | "CHANGE_LOG_MARK_SEEN" | "CHANGE_LOG_RESOLVED" | "CHANGE_LOG_SET_CONFIG" | "CHANGE_LOG_SET_OVERRIDE" | "CHANGE_LOG_UNLOCK" | "CHANNEL_ACK" | "CHANNEL_CALL_POPOUT_WINDOW_OPEN" | "CHANNEL_COLLAPSE" | "CHANNEL_CREATE" | "CHANNEL_DELETE" | "CHANNEL_FOLLOWER_CREATED" | "CHANNEL_FOLLOWER_STATS_FETCH_FAILURE" | "CHANNEL_FOLLOWER_STATS_FETCH_SUCCESS" | "CHANNEL_FOLLOWING_PUBLISH_BUMP_DISMISSED" | "CHANNEL_FOLLOWING_PUBLISH_BUMP_HIDE_PERMANENTLY" | "CHANNEL_LOCAL_ACK" | "CHANNEL_MEMBER_COUNT_UPDATE" | "CHANNEL_MUTE_EXPIRED" | "CHANNEL_PERMISSIONS_DELETE_OVERWRITE_SUCCESS" | "CHANNEL_PERMISSIONS_PUT_OVERWRITE_SUCCESS" | "CHANNEL_PINS_ACK" | "CHANNEL_PINS_UPDATE" | "CHANNEL_PRELOAD" | "CHANNEL_RECIPIENT_ADD" | "CHANNEL_RECIPIENT_REMOVE" | "CHANNEL_RTC_ACTIVE_CHANNELS" | "CHANNEL_RTC_JUMP_TO_VOICE_CHANNEL_MESSAGE" | "CHANNEL_RTC_SELECT_PARTICIPANT" | "CHANNEL_RTC_UPDATE_CHAT_OPEN" | "CHANNEL_RTC_UPDATE_LAYOUT" | "CHANNEL_RTC_UPDATE_PARTCIPANTS_LIST_OPEN" | "CHANNEL_RTC_UPDATE_PARTICIPANTS_OPEN" | "CHANNEL_RTC_UPDATE_STAGE_STREAM_SIZE" | "CHANNEL_RTC_UPDATE_STAGE_VIDEO_LIMIT_BOOST_UPSELL_DISMISSED" | "CHANNEL_RTC_UPDATE_VOICE_PARTICIPANTS_HIDDEN" | "CHANNEL_SAFETY_WARNING_FEEDBACK" | "CHANNEL_SELECT" | "CHANNEL_SETTINGS_CLOSE" | "CHANNEL_SETTINGS_INIT" | "CHANNEL_SETTINGS_LOADED_INVITES" | "CHANNEL_SETTINGS_OVERWRITE_SELECT" | "CHANNEL_SETTINGS_PERMISSIONS_INIT" | "CHANNEL_SETTINGS_PERMISSIONS_SAVE_SUCCESS" | "CHANNEL_SETTINGS_PERMISSIONS_SELECT_PERMISSION" | "CHANNEL_SETTINGS_PERMISSIONS_SET_ADVANCED_MODE" | "CHANNEL_SETTINGS_PERMISSIONS_SUBMITTING" | "CHANNEL_SETTINGS_PERMISSIONS_UPDATE_PERMISSION" | "CHANNEL_SETTINGS_SET_SECTION" | "CHANNEL_SETTINGS_SUBMIT" | "CHANNEL_SETTINGS_SUBMIT_FAILURE" | "CHANNEL_SETTINGS_SUBMIT_SUCCESS" | "CHANNEL_SETTINGS_UPDATE" | "CHANNEL_STATUSES" | "CHANNEL_TOGGLE_MEMBERS_SECTION" | "CHANNEL_TOGGLE_SUMMARIES_SECTION" | "CHANNEL_UPDATES" | "CHECKING_FOR_UPDATES" | "CHECKOUT_RECOVERY_STATUS_FETCH" | "CHECKOUT_RECOVERY_STATUS_FETCH_FAILURE" | "CHECKOUT_RECOVERY_STATUS_FETCH_SUCCESS" | "CHECK_LAUNCHABLE_GAME" | "CLEAR_CACHES" | "CLEAR_CHANNEL_SAFETY_WARNINGS" | "CLEAR_CONSUMED_ENTITLEMENT" | "CLEAR_CONVERSATION_SUMMARIES" | "CLEAR_INTERACTION_MODAL_STATE" | "CLEAR_LAST_SESSION_VOICE_CHANNEL_ID" | "CLEAR_MENTIONS" | "CLEAR_MESSAGES" | "CLEAR_OLDEST_UNREAD_MESSAGE" | "CLEAR_PENDING_CHANNEL_AND_ROLE_UPDATES" | "CLEAR_REMOTE_DISCONNECT_VOICE_CHANNEL_ID" | "CLEAR_STICKER_PREVIEW" | "CLEAR_THEME_OVERRIDE" | "CLEAR_VIDEO_STREAM_READY_TIMEOUT" | "CLICKER_GAME_ADD_POINTS" | "CLICKER_GAME_PURCHASE_ITEM" | "CLICKER_GAME_PURCHASE_ITEM_UPGRADE" | "CLICKER_GAME_REDEEM_PRIZE_FAIL" | "CLICKER_GAME_REDEEM_PRIZE_START" | "CLICKER_GAME_REDEEM_PRIZE_SUCCESS" | "CLICKER_GAME_RESET" | "CLICKER_GAME_SET_MUTED" | "CLICKER_GAME_SET_VOLUME" | "CLICKER_GAME_UNLOCK_ACHIEVEMENT" | "CLICKER_GAME_UPDATE_ITEM_METADATA" | "CLIENT_THEMES_EDITOR_CLOSE" | "CLIPS_ALLOW_VOICE_RECORDING_UPDATE" | "CLIPS_CLASSIFY_HARDWARE" | "CLIPS_CLEAR_CLIPS_SESSION" | "CLIPS_CLEAR_NEW_CLIP_IDS" | "CLIPS_DELETE_CLIP" | "CLIPS_DISMISS_EDUCATION" | "CLIPS_INIT" | "CLIPS_INIT_FAILURE" | "CLIPS_LOAD_DIRECTORY_SUCCESS" | "CLIPS_RESTART" | "CLIPS_SAVE_ANIMATION_END" | "CLIPS_SAVE_CLIP" | "CLIPS_SAVE_CLIP_ERROR" | "CLIPS_SAVE_CLIP_PLACEHOLDER" | "CLIPS_SAVE_CLIP_PLACEHOLDER_ERROR" | "CLIPS_SAVE_CLIP_START" | "CLIPS_SETTINGS_UPDATE" | "CLIPS_SHOW_CALL_WARNING" | "CLIPS_UPDATE_METADATA" | "CLOSE_AGE_VERIFICATION_MODAL" | "CLOSE_SUSPENDED_USER" | "COLLECTIBLES_CATEGORIES_FETCH" | "COLLECTIBLES_CATEGORIES_FETCH_FAILURE" | "COLLECTIBLES_CATEGORIES_FETCH_SUCCESS" | "COLLECTIBLES_CLAIM" | "COLLECTIBLES_CLAIM_FAILURE" | "COLLECTIBLES_CLAIM_SUCCESS" | "COLLECTIBLES_MARKETING_FETCH" | "COLLECTIBLES_MARKETING_FETCH_SUCCESS" | "COLLECTIBLES_PRODUCT_DETAILS_OPEN" | "COLLECTIBLES_PRODUCT_FETCH" | "COLLECTIBLES_PRODUCT_FETCH_FAILURE" | "COLLECTIBLES_PRODUCT_FETCH_SUCCESS" | "COLLECTIBLES_PURCHASES_FETCH" | "COLLECTIBLES_PURCHASES_FETCH_FAILURE" | "COLLECTIBLES_PURCHASES_FETCH_SUCCESS" | "COLLECTIBLES_SET_SHOP_HOME_CONFIG_OVERRIDE" | "COLLECTIBLES_SHOP_CLOSE" | "COLLECTIBLES_SHOP_HOME_FETCH" | "COLLECTIBLES_SHOP_HOME_FETCH_FAILURE" | "COLLECTIBLES_SHOP_HOME_FETCH_SUCCESS" | "COLLECTIBLES_SHOP_OPEN" | "COLLECTIBLES_SKIP_NUM_CATEGORIES" | "COMMANDS_MIGRATION_NOTICE_DISMISSED" | "COMMANDS_MIGRATION_OVERVIEW_TOOLTIP_DISMISSED" | "COMMANDS_MIGRATION_TOGGLE_TOOLTIP_DISMISSED" | "COMMANDS_MIGRATION_UPDATE_SUCCESS" | "COMPLETE_NEW_MEMBER_ACTION" | "CONNECTED_DEVICE_DONT_SWITCH" | "CONNECTED_DEVICE_IGNORE" | "CONNECTED_DEVICE_NEVER_SHOW_MODAL" | "CONNECTED_DEVICE_SWITCH" | "CONNECTIONS_GRID_MODAL_HIDE" | "CONNECTIONS_GRID_MODAL_SHOW" | "CONNECTION_CLOSED" | "CONNECTION_OPEN" | "CONNECTION_OPEN_STATE_UPDATE" | "CONNECTION_OPEN_SUPPLEMENTAL" | "CONNECTION_RESUMED" | "CONSOLE_COMMAND_UPDATE" | "CONSUMABLES_CLEAR_ERROR" | "CONSUMABLES_ENTITLEMENT_FETCH_COMPLETED" | "CONSUMABLES_ENTITLEMENT_FETCH_FAILED" | "CONSUMABLES_ENTITLEMENT_FETCH_STARTED" | "CONSUMABLES_PRICE_FETCH_FAILED" | "CONSUMABLES_PRICE_FETCH_STARTED" | "CONSUMABLES_PRICE_FETCH_SUCCEEDED" | "CONTENT_INVENTORY_CLEAR_DELETE_HISTORY_ERROR" | "CONTENT_INVENTORY_CLEAR_FEED" | "CONTENT_INVENTORY_DEBUG_CLEAR_IMPRESSIONS" | "CONTENT_INVENTORY_DEBUG_LOG_IMPRESSIONS" | "CONTENT_INVENTORY_DEBUG_TOGGLE_FAST_IMPRESSION_CAPPING" | "CONTENT_INVENTORY_DEBUG_TOGGLE_IMPRESSION_CAPPING" | "CONTENT_INVENTORY_DELETE_OUTBOX_ENTRY_FAILURE" | "CONTENT_INVENTORY_DELETE_OUTBOX_ENTRY_START" | "CONTENT_INVENTORY_DELETE_OUTBOX_ENTRY_SUCCESS" | "CONTENT_INVENTORY_FETCH_OUTBOX_FAILURE" | "CONTENT_INVENTORY_FETCH_OUTBOX_START" | "CONTENT_INVENTORY_FETCH_OUTBOX_SUCCESS" | "CONTENT_INVENTORY_FORCE_SHOW_GAME_SHARING" | "CONTENT_INVENTORY_INBOX_STALE" | "CONTENT_INVENTORY_MANUAL_REFRESH" | "CONTENT_INVENTORY_SET_FEED" | "CONTENT_INVENTORY_SET_FEED_STATE" | "CONTENT_INVENTORY_SET_FILTERS" | "CONTENT_INVENTORY_TOGGLE_FEED_HIDDEN" | "CONTENT_INVENTORY_TRACK_ITEM_IMPRESSIONS" | "CONTEXT_MENU_CLOSE" | "CONTEXT_MENU_OPEN" | "CONVERSATION_SUMMARY_UPDATE" | "CREATE_PENDING_REPLY" | "CREATE_PENDING_SCHEDULED_MESSAGE" | "CREATE_REFERRALS_SUCCESS" | "CREATE_SHALLOW_PENDING_REPLY" | "CREATOR_MONETIZATION_NAG_ACTIVATE_ELIGIBLITY_FETCH_SUCCESS" | "CREATOR_MONETIZATION_PRICE_TIERS_FETCH" | "CREATOR_MONETIZATION_PRICE_TIERS_FETCH_FAILURE" | "CREATOR_MONETIZATION_PRICE_TIERS_FETCH_SUCCESS" | "CURRENT_BUILD_OVERRIDE_RESOLVED" | "CURRENT_USER_UPDATE" | "CUSTOM_ACTIVITY_LINK_FETCH_SUCCESS" | "DCF_DAILY_CAP_OVERRIDE" | "DCF_EVENT_LOGGED" | "DCF_HANDLE_DC_DISMISSED" | "DCF_HANDLE_DC_SHOWN" | "DCF_NEW_USER_MIN_AGE_REQUIRED_OVERRIDE" | "DCF_OVERRIDE_LAST_DC_DISMISSED" | "DCF_RESET" | "DECAY_READ_STATES" | "DELETED_ENTITY_IDS" | "DELETE_PENDING_REPLY" | "DELETE_PENDING_SCHEDULED_MESSAGE" | "DELETE_SUMMARY" | "DETECTABLE_GAME_SUPPLEMENTAL_FETCH" | "DETECTABLE_GAME_SUPPLEMENTAL_FETCH_FAILURE" | "DETECTABLE_GAME_SUPPLEMENTAL_FETCH_SUCCESS" | "DETECTED_OFF_PLATFORM_PREMIUM_PERKS_DISMISS" | "DEVELOPER_ACTIVITY_SHELF_FETCH_FAIL" | "DEVELOPER_ACTIVITY_SHELF_FETCH_START" | "DEVELOPER_ACTIVITY_SHELF_FETCH_SUCCESS" | "DEVELOPER_ACTIVITY_SHELF_MARK_ACTIVITY_USED" | "DEVELOPER_ACTIVITY_SHELF_SET_ACTIVITY_URL_OVERRIDE" | "DEVELOPER_ACTIVITY_SHELF_TOGGLE_USE_ACTIVITY_URL_OVERRIDE" | "DEVELOPER_ACTIVITY_SHELF_UPDATE_FILTER" | "DEVELOPER_OPTIONS_UPDATE_SETTINGS" | "DEVELOPER_TEST_MODE_AUTHORIZATION_FAIL" | "DEVELOPER_TEST_MODE_AUTHORIZATION_START" | "DEVELOPER_TEST_MODE_AUTHORIZATION_SUCCESS" | "DEVELOPER_TEST_MODE_RESET" | "DEVELOPER_TEST_MODE_RESET_ERROR" | "DEV_TOOLS_DESIGN_TOGGLE_SET" | "DEV_TOOLS_DESIGN_TOGGLE_WEB_SET" | "DEV_TOOLS_DEV_SETTING_SET" | "DEV_TOOLS_FRIENDS_LIST_GIFT_INTENTS_SHOWN_RESET" | "DEV_TOOLS_FRIENDS_TAB_BADGE_COOLDOWN_RESET" | "DEV_TOOLS_GIFT_MESSAGE_COOLDOWN_RESET" | "DEV_TOOLS_SETTINGS_UPDATE" | "DEV_TOOLS_SET_FRIEND_ANNIVERSARY_COUNT" | "DISABLE_AUTOMATIC_ACK" | "DISCOVER_CHECKLIST_FETCH_FAILURE" | "DISCOVER_CHECKLIST_FETCH_START" | "DISCOVER_CHECKLIST_FETCH_SUCCESS" | "DISMISS_CHANNEL_SAFETY_WARNINGS" | "DISMISS_FAVORITE_SUGGESTION" | "DISMISS_MEDIA_POST_SHARE_PROMPT" | "DISPATCH_APPLICATION_ADD_TO_INSTALLATIONS" | "DISPATCH_APPLICATION_CANCEL" | "DISPATCH_APPLICATION_ERROR" | "DISPATCH_APPLICATION_INSTALL" | "DISPATCH_APPLICATION_INSTALL_SCRIPTS_PROGRESS_UPDATE" | "DISPATCH_APPLICATION_LAUNCH_SETUP_COMPLETE" | "DISPATCH_APPLICATION_LAUNCH_SETUP_START" | "DISPATCH_APPLICATION_MOVE_UP" | "DISPATCH_APPLICATION_REMOVE_FINISHED" | "DISPATCH_APPLICATION_REPAIR" | "DISPATCH_APPLICATION_STATE_UPDATE" | "DISPATCH_APPLICATION_UNINSTALL" | "DISPATCH_APPLICATION_UPDATE" | "DISPLAYED_INVITE_SHOW" | "DOMAIN_MIGRATION_FAILURE" | "DOMAIN_MIGRATION_SKIP" | "DOMAIN_MIGRATION_START" | "DRAFT_CHANGE" | "DRAFT_CLEAR" | "DRAFT_SAVE" | "EMAIL_SETTINGS_FETCH_SUCCESS" | "EMAIL_SETTINGS_UPDATE" | "EMAIL_SETTINGS_UPDATE_SUCCESS" | "EMBEDDED_ACTIVITY_CLOSE" | "EMBEDDED_ACTIVITY_DEFERRED_OPEN" | "EMBEDDED_ACTIVITY_FETCH_SHELF" | "EMBEDDED_ACTIVITY_FETCH_SHELF_FAIL" | "EMBEDDED_ACTIVITY_FETCH_SHELF_SUCCESS" | "EMBEDDED_ACTIVITY_LAUNCH_FAIL" | "EMBEDDED_ACTIVITY_LAUNCH_START" | "EMBEDDED_ACTIVITY_LAUNCH_SUCCESS" | "EMBEDDED_ACTIVITY_OPEN" | "EMBEDDED_ACTIVITY_SET_CONFIG" | "EMBEDDED_ACTIVITY_SET_FOCUSED_LAYOUT" | "EMBEDDED_ACTIVITY_SET_ORIENTATION_LOCK_STATE" | "EMBEDDED_ACTIVITY_SET_PANEL_MODE" | "EMBEDDED_ACTIVITY_UPDATE" | "EMBEDDED_ACTIVITY_UPDATE_POPOUT_WINDOW_LAYOUT" | "EMBEDDED_ACTIVITY_UPDATE_V2" | "EMOJI_AUTOSUGGESTION_UPDATE" | "EMOJI_DELETE" | "EMOJI_FETCH_FAILURE" | "EMOJI_FETCH_SUCCESS" | "EMOJI_INTERACTION_INITIATED" | "EMOJI_TRACK_USAGE" | "EMOJI_UPLOAD_START" | "EMOJI_UPLOAD_STOP" | "ENABLE_AUTOMATIC_ACK" | "ENTITLEMENTS_FETCH_FOR_USER_FAIL" | "ENTITLEMENTS_FETCH_FOR_USER_START" | "ENTITLEMENTS_FETCH_FOR_USER_SUCCESS" | "ENTITLEMENTS_GIFTABLE_FETCH_SUCCESS" | "ENTITLEMENT_CREATE" | "ENTITLEMENT_DELETE" | "ENTITLEMENT_FETCH_APPLICATION_FAIL" | "ENTITLEMENT_FETCH_APPLICATION_START" | "ENTITLEMENT_FETCH_APPLICATION_SUCCESS" | "ENTITLEMENT_UPDATE" | "EVENT_DIRECTORY_FETCH_FAILURE" | "EVENT_DIRECTORY_FETCH_START" | "EVENT_DIRECTORY_FETCH_SUCCESS" | "EXPERIMENTS_FETCH" | "EXPERIMENTS_FETCH_FAILURE" | "EXPERIMENTS_FETCH_SUCCESS" | "EXPERIMENT_OVERRIDE_BUCKET" | "FAMILY_CENTER_FETCH_START" | "FAMILY_CENTER_HANDLE_TAB_SELECT" | "FAMILY_CENTER_INITIAL_LOAD" | "FAMILY_CENTER_LINKED_USERS_FETCH_SUCCESS" | "FAMILY_CENTER_LINK_CODE_FETCH_SUCCESS" | "FAMILY_CENTER_REQUEST_LINK_REMOVE_SUCCESS" | "FAMILY_CENTER_REQUEST_LINK_SUCCESS" | "FAMILY_CENTER_REQUEST_LINK_UPDATE_SUCCESS" | "FAMILY_CENTER_TEEN_ACTIVITY_FETCH_SUCCESS" | "FAMILY_CENTER_TEEN_ACTIVITY_MORE_FETCH_SUCCESS" | "FEEDBACK_OVERRIDE_CLEAR" | "FEEDBACK_OVERRIDE_SET" | "FETCH_AUTH_SESSIONS_SUCCESS" | "FETCH_CHAT_WALLPAPERS_FAILURE" | "FETCH_CHAT_WALLPAPERS_START" | "FETCH_CHAT_WALLPAPERS_SUCCESS" | "FETCH_GUILD_EVENT" | "FETCH_GUILD_EVENTS_FOR_GUILD" | "FETCH_GUILD_MEMBER_SUPPLEMENTAL_SUCCESS" | "FETCH_INTEGRATION_APPLICATION_IDS_FOR_MY_GUILDS" | "FETCH_INTEGRATION_APPLICATION_IDS_FOR_MY_GUILDS_FAILURE" | "FETCH_INTEGRATION_APPLICATION_IDS_FOR_MY_GUILDS_SUCCESS" | "FETCH_SCHEDULED_MESSAGES" | "FETCH_SCHEDULED_MESSAGES_FAILURE" | "FETCH_SCHEDULED_MESSAGES_SUCCESS" | "FINGERPRINT" | "FORCE_INVISIBLE" | "FORGOT_PASSWORD_REQUEST" | "FORGOT_PASSWORD_SENT" | "FORUM_SEARCH_CLEAR" | "FORUM_SEARCH_FAILURE" | "FORUM_SEARCH_QUERY_UPDATED" | "FORUM_SEARCH_START" | "FORUM_SEARCH_SUCCESS" | "FORUM_UNREADS" | "FRIENDS_LIST_GIFT_INTENTS_SHOWN" | "FRIENDS_SET_INITIAL_SECTION" | "FRIENDS_SET_SECTION" | "FRIENDS_TAB_BADGE_DISMISS" | "FRIEND_INVITES_FETCH_REQUEST" | "FRIEND_INVITES_FETCH_RESPONSE" | "FRIEND_INVITE_CREATE_FAILURE" | "FRIEND_INVITE_CREATE_REQUEST" | "FRIEND_INVITE_CREATE_SUCCESS" | "FRIEND_INVITE_REVOKE_REQUEST" | "FRIEND_INVITE_REVOKE_SUCCESS" | "FRIEND_SUGGESTION_CREATE" | "FRIEND_SUGGESTION_DELETE" | "GAMES_DATABASE_FETCH" | "GAMES_DATABASE_FETCH_FAIL" | "GAMES_DATABASE_UPDATE" | "GAME_CLOUD_SYNC_COMPLETE" | "GAME_CLOUD_SYNC_CONFLICT" | "GAME_CLOUD_SYNC_ERROR" | "GAME_CLOUD_SYNC_START" | "GAME_CLOUD_SYNC_UPDATE" | "GAME_CONSOLE_FETCH_DEVICES_FAIL" | "GAME_CONSOLE_FETCH_DEVICES_START" | "GAME_CONSOLE_FETCH_DEVICES_SUCCESS" | "GAME_CONSOLE_SELECT_DEVICE" | "GAME_DETECTION_DEBUGGING_START" | "GAME_DETECTION_DEBUGGING_STOP" | "GAME_DETECTION_DEBUGGING_TICK" | "GAME_DETECTION_WATCH_CANDIDATE_GAMES_START" | "GAME_ICON_UPDATE" | "GAME_INVITE_CLEAR_UNSEEN" | "GAME_INVITE_CREATE" | "GAME_INVITE_DELETE" | "GAME_INVITE_DELETE_MANY" | "GAME_INVITE_UPDATE_STATUS" | "GAME_LAUNCHABLE_UPDATE" | "GAME_LAUNCH_FAIL" | "GAME_LAUNCH_START" | "GAME_LAUNCH_SUCCESS" | "GAME_PROFILE_OPEN" | "GAME_RELATIONSHIP_ADD" | "GAME_RELATIONSHIP_REMOVE" | "GENERIC_PUSH_NOTIFICATION_SENT" | "GIFT_CODES_FETCH" | "GIFT_CODES_FETCH_FAILURE" | "GIFT_CODES_FETCH_SUCCESS" | "GIFT_CODE_CREATE" | "GIFT_CODE_CREATE_SUCCESS" | "GIFT_CODE_REDEEM" | "GIFT_CODE_REDEEM_FAILURE" | "GIFT_CODE_REDEEM_SUCCESS" | "GIFT_CODE_RESOLVE" | "GIFT_CODE_RESOLVE_FAILURE" | "GIFT_CODE_RESOLVE_SUCCESS" | "GIFT_CODE_REVOKE_SUCCESS" | "GIFT_CODE_UPDATE" | "GIFT_INTENT_FLOW_PURCHASED_GIFT" | "GIF_PICKER_INITIALIZE" | "GIF_PICKER_QUERY" | "GIF_PICKER_QUERY_FAILURE" | "GIF_PICKER_QUERY_SUCCESS" | "GIF_PICKER_SUGGESTIONS_SUCCESS" | "GIF_PICKER_TRENDING_FETCH_SUCCESS" | "GIF_PICKER_TRENDING_SEARCH_TERMS_SUCCESS" | "GLOBAL_DISCOVERY_SERVERS_SEARCH_CLEAR" | "GLOBAL_DISCOVERY_SERVERS_SEARCH_COUNT_FAILURE" | "GLOBAL_DISCOVERY_SERVERS_SEARCH_COUNT_START" | "GLOBAL_DISCOVERY_SERVERS_SEARCH_COUNT_SUCCESS" | "GLOBAL_DISCOVERY_SERVERS_SEARCH_FAILURE" | "GLOBAL_DISCOVERY_SERVERS_SEARCH_LAYOUT_RESET" | "GLOBAL_DISCOVERY_SERVERS_SEARCH_START" | "GLOBAL_DISCOVERY_SERVERS_SEARCH_SUCCESS" | "GUILD_ACK" | "GUILD_ANALYTICS_ENGAGEMENT_OVERVIEW_FETCH_FAILURE" | "GUILD_ANALYTICS_ENGAGEMENT_OVERVIEW_FETCH_SUCCESS" | "GUILD_ANALYTICS_GROWTH_ACTIVATION_OVERVIEW_FETCH_FAILURE" | "GUILD_ANALYTICS_GROWTH_ACTIVATION_OVERVIEW_FETCH_SUCCESS" | "GUILD_ANALYTICS_GROWTH_ACTIVATION_RETENTION_FETCH_FAILURE" | "GUILD_ANALYTICS_GROWTH_ACTIVATION_RETENTION_FETCH_SUCCESS" | "GUILD_APPLICATIONS_FETCH_SUCCESS" | "GUILD_APPLICATION_COMMAND_INDEX_UPDATE" | "GUILD_APPLIED_BOOSTS_FETCH_SUCCESS" | "GUILD_APPLIED_BOOSTS_UPDATE" | "GUILD_APPLY_BOOST_FAIL" | "GUILD_APPLY_BOOST_START" | "GUILD_APPLY_BOOST_SUCCESS" | "GUILD_BAN_ADD" | "GUILD_BAN_REMOVE" | "GUILD_BOOST_SLOTS_FETCH" | "GUILD_BOOST_SLOTS_FETCH_SUCCESS" | "GUILD_BOOST_SLOT_CREATE" | "GUILD_BOOST_SLOT_UPDATE" | "GUILD_BOOST_SLOT_UPDATE_SUCCESS" | "GUILD_CREATE" | "GUILD_DELETE" | "GUILD_DIRECTORY_ADMIN_ENTRIES_FETCH_SUCCESS" | "GUILD_DIRECTORY_CACHED_SEARCH" | "GUILD_DIRECTORY_CATEGORY_SELECT" | "GUILD_DIRECTORY_COUNTS_FETCH_SUCCESS" | "GUILD_DIRECTORY_ENTRY_CREATE" | "GUILD_DIRECTORY_ENTRY_DELETE" | "GUILD_DIRECTORY_ENTRY_UPDATE" | "GUILD_DIRECTORY_FETCH_FAILURE" | "GUILD_DIRECTORY_FETCH_START" | "GUILD_DIRECTORY_FETCH_SUCCESS" | "GUILD_DIRECTORY_SEARCH_CLEAR" | "GUILD_DIRECTORY_SEARCH_FAILURE" | "GUILD_DIRECTORY_SEARCH_START" | "GUILD_DIRECTORY_SEARCH_SUCCESS" | "GUILD_DISCOVERY_CATEGORY_ADD" | "GUILD_DISCOVERY_CATEGORY_DELETE" | "GUILD_DISCOVERY_CATEGORY_FETCH_SUCCESS" | "GUILD_DISCOVERY_CATEGORY_UPDATE_FAIL" | "GUILD_DISCOVERY_METADATA_FETCH_FAIL" | "GUILD_DISCOVERY_SLUG_FETCH_FAIL" | "GUILD_DISCOVERY_SLUG_FETCH_SUCCESS" | "GUILD_EMOJIS_UPDATE" | "GUILD_FEATURE_ACK" | "GUILD_FOLDER_COLLAPSE" | "GUILD_FOLDER_CREATE_LOCAL" | "GUILD_FOLDER_DELETE_LOCAL" | "GUILD_FOLDER_EDIT_LOCAL" | "GUILD_GEO_RESTRICTED" | "GUILD_HOME_SETTINGS_FETCH_FAIL" | "GUILD_HOME_SETTINGS_FETCH_START" | "GUILD_HOME_SETTINGS_FETCH_SUCCESS" | "GUILD_HOME_SETTINGS_TOGGLE_ENABLED" | "GUILD_HOME_SETTINGS_UPDATE_FAIL" | "GUILD_HOME_SETTINGS_UPDATE_START" | "GUILD_HOME_SETTINGS_UPDATE_SUCCESS" | "GUILD_IDENTITY_SETTINGS_CLEAR_ERRORS" | "GUILD_IDENTITY_SETTINGS_INIT" | "GUILD_IDENTITY_SETTINGS_RESET_ALL_PENDING" | "GUILD_IDENTITY_SETTINGS_RESET_AND_CLOSE_FORM" | "GUILD_IDENTITY_SETTINGS_RESET_PENDING_MEMBER_CHANGES" | "GUILD_IDENTITY_SETTINGS_RESET_PENDING_PROFILE_CHANGES" | "GUILD_IDENTITY_SETTINGS_SET_GUILD" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_AVATAR" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_AVATAR_DECORATION" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_BANNER" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_BIO" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_NICKNAME" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_PROFILE_EFFECT_ID" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_PRONOUNS" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_THEME_COLORS" | "GUILD_IDENTITY_SETTINGS_SUBMIT" | "GUILD_IDENTITY_SETTINGS_SUBMIT_FAILURE" | "GUILD_IDENTITY_SETTINGS_SUBMIT_SUCCESS" | "GUILD_INTEGRATIONS_UPDATE" | "GUILD_JOIN" | "GUILD_JOIN_REQUESTS_BULK_ACTION" | "GUILD_JOIN_REQUESTS_FETCH_FAILURE" | "GUILD_JOIN_REQUESTS_FETCH_START" | "GUILD_JOIN_REQUESTS_FETCH_SUCCESS" | "GUILD_JOIN_REQUESTS_SET_APPLICATION_TAB" | "GUILD_JOIN_REQUESTS_SET_SELECTED" | "GUILD_JOIN_REQUESTS_SET_SORT_ORDER" | "GUILD_JOIN_REQUEST_BY_ID_FETCH_SUCCESS" | "GUILD_JOIN_REQUEST_CREATE" | "GUILD_JOIN_REQUEST_DELETE" | "GUILD_JOIN_REQUEST_UPDATE" | "GUILD_LOCAL_RING_START" | "GUILD_MEMBERS_CHUNK_BATCH" | "GUILD_MEMBERS_REQUEST" | "GUILD_MEMBER_ADD" | "GUILD_MEMBER_LIST_UPDATE" | "GUILD_MEMBER_PROFILE_UPDATE" | "GUILD_MEMBER_REMOVE" | "GUILD_MEMBER_REMOVE_LOCAL" | "GUILD_MEMBER_UPDATE" | "GUILD_MEMBER_UPDATE_LOCAL" | "GUILD_MOVE_BY_ID" | "GUILD_MUTE_EXPIRED" | "GUILD_NEW_MEMBER_ACTIONS_DELETE_SUCCESS" | "GUILD_NEW_MEMBER_ACTIONS_FETCH_FAIL" | "GUILD_NEW_MEMBER_ACTIONS_FETCH_START" | "GUILD_NEW_MEMBER_ACTIONS_FETCH_SUCCESS" | "GUILD_NEW_MEMBER_ACTION_UPDATE_SUCCESS" | "GUILD_NSFW_AGREE" | "GUILD_ONBOARDING_COMPLETE" | "GUILD_ONBOARDING_PROMPTS_FETCH_FAILURE" | "GUILD_ONBOARDING_PROMPTS_FETCH_START" | "GUILD_ONBOARDING_PROMPTS_FETCH_SUCCESS" | "GUILD_ONBOARDING_PROMPTS_LOCAL_UPDATE" | "GUILD_ONBOARDING_SELECT_OPTION" | "GUILD_ONBOARDING_SET_STEP" | "GUILD_ONBOARDING_START" | "GUILD_ONBOARDING_UPDATE_RESPONSES_SUCCESS" | "GUILD_POWERUPS_ACK_NOTIFICATION" | "GUILD_POWERUPS_RESET_NOTIFICATIONS" | "GUILD_POWERUP_CATALOG_FETCH_SUCCESS" | "GUILD_POWERUP_ENTITLEMENTS_CREATE" | "GUILD_POWERUP_ENTITLEMENTS_DELETE" | "GUILD_PRODUCTS_FETCH" | "GUILD_PRODUCTS_FETCH_FAILURE" | "GUILD_PRODUCTS_FETCH_SUCCESS" | "GUILD_PRODUCT_CREATE" | "GUILD_PRODUCT_DELETE" | "GUILD_PRODUCT_FETCH" | "GUILD_PRODUCT_FETCH_FAILURE" | "GUILD_PRODUCT_FETCH_SUCCESS" | "GUILD_PRODUCT_UPDATE" | "GUILD_PROFILE_FETCH" | "GUILD_PROFILE_FETCH_FAILURE" | "GUILD_PROFILE_FETCH_SUCCESS" | "GUILD_PROFILE_UPDATE" | "GUILD_PROFILE_UPDATE_FAILURE" | "GUILD_PROFILE_UPDATE_SUCCESS" | "GUILD_PROFILE_UPDATE_VISIBILITY" | "GUILD_PROFILE_UPDATE_VISIBILITY_FAILURE" | "GUILD_PROFILE_UPDATE_VISIBILITY_SUCCESS" | "GUILD_PROGRESS_COMPLETED_SEEN" | "GUILD_PROGRESS_DISMISS" | "GUILD_PROGRESS_INITIALIZE" | "GUILD_PROMPT_VIEWED" | "GUILD_RESOURCE_CHANNEL_UPDATE_SUCCESS" | "GUILD_RING_START" | "GUILD_RING_STOP" | "GUILD_ROLE_CONNECTIONS_CONFIGURATIONS_FETCH_SUCCESS" | "GUILD_ROLE_CONNECTIONS_MODAL_SHOW" | "GUILD_ROLE_CONNECTION_ELIGIBILITY_FETCH_SUCCESS" | "GUILD_ROLE_CREATE" | "GUILD_ROLE_DELETE" | "GUILD_ROLE_MEMBER_ADD" | "GUILD_ROLE_MEMBER_BULK_ADD" | "GUILD_ROLE_MEMBER_COUNT_FETCH_SUCCESS" | "GUILD_ROLE_MEMBER_COUNT_UPDATE" | "GUILD_ROLE_MEMBER_REMOVE" | "GUILD_ROLE_SUBSCRIPTIONS_CREATE_LISTING" | "GUILD_ROLE_SUBSCRIPTIONS_DELETE_GROUP_LISTING" | "GUILD_ROLE_SUBSCRIPTIONS_DELETE_LISTING" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_LISTINGS" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_LISTINGS_FAILURE" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_LISTINGS_SUCCESS" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_LISTING_FOR_PLAN" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_LISTING_FOR_PLAN_SUCCESS" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_RESTRICTIONS" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_RESTRICTIONS_ABORTED" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_RESTRICTIONS_FAILURE" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_RESTRICTIONS_SUCCESS" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_TEMPLATES" | "GUILD_ROLE_SUBSCRIPTIONS_STASH_TEMPLATE_CHANNELS" | "GUILD_ROLE_SUBSCRIPTIONS_UPDATE_GROUP_LISTING" | "GUILD_ROLE_SUBSCRIPTIONS_UPDATE_LISTING" | "GUILD_ROLE_SUBSCRIPTIONS_UPDATE_SUBSCRIPTIONS_SETTINGS" | "GUILD_ROLE_SUBSCRIPTIONS_UPDATE_SUBSCRIPTION_TRIAL" | "GUILD_ROLE_UPDATE" | "GUILD_SCHEDULED_EVENT_CREATE" | "GUILD_SCHEDULED_EVENT_DELETE" | "GUILD_SCHEDULED_EVENT_EXCEPTIONS_DELETE" | "GUILD_SCHEDULED_EVENT_EXCEPTION_CREATE" | "GUILD_SCHEDULED_EVENT_EXCEPTION_DELETE" | "GUILD_SCHEDULED_EVENT_EXCEPTION_UPDATE" | "GUILD_SCHEDULED_EVENT_RSVPS_FETCH_SUCESS" | "GUILD_SCHEDULED_EVENT_UPDATE" | "GUILD_SCHEDULED_EVENT_USERS_FETCH_SUCCESS" | "GUILD_SCHEDULED_EVENT_USER_ADD" | "GUILD_SCHEDULED_EVENT_USER_COUNTS_FETCH_SUCCESS" | "GUILD_SCHEDULED_EVENT_USER_REMOVE" | "GUILD_SEARCH_RECENT_MEMBERS" | "GUILD_SETTINGS_CANCEL_CHANGES" | "GUILD_SETTINGS_CLOSE" | "GUILD_SETTINGS_DEFAULT_CHANNELS_RESET" | "GUILD_SETTINGS_DEFAULT_CHANNELS_SAVE_FAILED" | "GUILD_SETTINGS_DEFAULT_CHANNELS_SAVE_SUCCESS" | "GUILD_SETTINGS_DEFAULT_CHANNELS_SUBMIT" | "GUILD_SETTINGS_DEFAULT_CHANNELS_TOGGLE" | "GUILD_SETTINGS_INIT" | "GUILD_SETTINGS_JOIN_RULES_APPLY_SET_PENDING_FORM_FIELDS" | "GUILD_SETTINGS_JOIN_RULES_INVITE_SET_PENDING_RULES" | "GUILD_SETTINGS_JOIN_RULES_SET_CONTENT_LEVEL" | "GUILD_SETTINGS_JOIN_RULES_SET_SELECTED_TYPE" | "GUILD_SETTINGS_LOADED_BANS" | "GUILD_SETTINGS_LOADED_BANS_BATCH" | "GUILD_SETTINGS_LOADED_INTEGRATIONS" | "GUILD_SETTINGS_LOADED_INVITES" | "GUILD_SETTINGS_ONBOARDING_ADD_NEW_MEMBER_ACTION" | "GUILD_SETTINGS_ONBOARDING_ADD_RESOURCE_CHANNEL" | "GUILD_SETTINGS_ONBOARDING_DELETE_NEW_MEMBER_ACTION" | "GUILD_SETTINGS_ONBOARDING_DELETE_RESOURCE_CHANNEL" | "GUILD_SETTINGS_ONBOARDING_DISMISS_RESOURCE_CHANNEL_SUGGESTION" | "GUILD_SETTINGS_ONBOARDING_EDUCATION_UPSELL_DISMISSED" | "GUILD_SETTINGS_ONBOARDING_HOME_SETTINGS_RESET" | "GUILD_SETTINGS_ONBOARDING_PROMPTS_EDIT" | "GUILD_SETTINGS_ONBOARDING_PROMPTS_ERRORS" | "GUILD_SETTINGS_ONBOARDING_PROMPTS_RESET" | "GUILD_SETTINGS_ONBOARDING_PROMPTS_SAVE_FAILED" | "GUILD_SETTINGS_ONBOARDING_PROMPTS_SAVE_SUCCESS" | "GUILD_SETTINGS_ONBOARDING_PROMPTS_SUBMIT" | "GUILD_SETTINGS_ONBOARDING_REORDER_NEW_MEMBER_ACTION" | "GUILD_SETTINGS_ONBOARDING_REORDER_RESOURCE_CHANNEL" | "GUILD_SETTINGS_ONBOARDING_SET_MODE" | "GUILD_SETTINGS_ONBOARDING_STEP" | "GUILD_SETTINGS_ONBOARDING_UPDATE_NEW_MEMBER_ACTION" | "GUILD_SETTINGS_ONBOARDING_UPDATE_RESOURCE_CHANNEL" | "GUILD_SETTINGS_ONBOARDING_UPDATE_WELCOME_MESSAGE" | "GUILD_SETTINGS_OPEN" | "GUILD_SETTINGS_PROFILE_UPDATE" | "GUILD_SETTINGS_ROLES_CLEAR_PERMISSIONS" | "GUILD_SETTINGS_ROLES_INIT" | "GUILD_SETTINGS_ROLES_ROLE_STYLE_UPDATE" | "GUILD_SETTINGS_ROLES_SAVE_FAIL" | "GUILD_SETTINGS_ROLES_SAVE_SUCCESS" | "GUILD_SETTINGS_ROLES_SORT_UPDATE" | "GUILD_SETTINGS_ROLES_SUBMITTING" | "GUILD_SETTINGS_ROLES_UPDATE_COLOR" | "GUILD_SETTINGS_ROLES_UPDATE_COLORS" | "GUILD_SETTINGS_ROLES_UPDATE_DESCRIPTION" | "GUILD_SETTINGS_ROLES_UPDATE_NAME" | "GUILD_SETTINGS_ROLES_UPDATE_PERMISSIONS" | "GUILD_SETTINGS_ROLES_UPDATE_PERMISSION_SET" | "GUILD_SETTINGS_ROLES_UPDATE_ROLE_CONNECTION_CONFIGURATIONS" | "GUILD_SETTINGS_ROLES_UPDATE_ROLE_ICON" | "GUILD_SETTINGS_ROLES_UPDATE_SETTINGS" | "GUILD_SETTINGS_ROLE_SELECT" | "GUILD_SETTINGS_SAFETY_PAGE" | "GUILD_SETTINGS_SAFETY_SET_SUBSECTION" | "GUILD_SETTINGS_SAVE_ROUTE_STACK" | "GUILD_SETTINGS_SET_MFA_SUCCESS" | "GUILD_SETTINGS_SET_SEARCH_QUERY" | "GUILD_SETTINGS_SET_SECTION" | "GUILD_SETTINGS_SET_VANITY_URL" | "GUILD_SETTINGS_SET_WIDGET" | "GUILD_SETTINGS_SUBMIT" | "GUILD_SETTINGS_SUBMIT_FAILURE" | "GUILD_SETTINGS_SUBMIT_SUCCESS" | "GUILD_SETTINGS_UPDATE" | "GUILD_SETTINGS_VANITY_URL_ERROR" | "GUILD_SETTINGS_VANITY_URL_RESET" | "GUILD_SETTINGS_VANITY_URL_SET" | "GUILD_SETTINGS_WIDGET_UPDATE" | "GUILD_SOUNDBOARD_FETCH" | "GUILD_SOUNDBOARD_SOUNDS_UPDATE" | "GUILD_SOUNDBOARD_SOUND_CREATE" | "GUILD_SOUNDBOARD_SOUND_DELETE" | "GUILD_SOUNDBOARD_SOUND_PLAY_END" | "GUILD_SOUNDBOARD_SOUND_PLAY_LOCALLY" | "GUILD_SOUNDBOARD_SOUND_PLAY_START" | "GUILD_SOUNDBOARD_SOUND_UPDATE" | "GUILD_STICKERS_CREATE_SUCCESS" | "GUILD_STICKERS_FETCH_SUCCESS" | "GUILD_STICKERS_UPDATE" | "GUILD_STOP_LURKING" | "GUILD_STOP_LURKING_FAILURE" | "GUILD_SUBSCRIPTIONS" | "GUILD_SUBSCRIPTIONS_ADD_MEMBER_UPDATES" | "GUILD_SUBSCRIPTIONS_CHANNEL" | "GUILD_SUBSCRIPTIONS_FLUSH" | "GUILD_SUBSCRIPTIONS_MEMBERS_ADD" | "GUILD_SUBSCRIPTIONS_MEMBERS_REMOVE" | "GUILD_SUBSCRIPTIONS_REMOVE_MEMBER_UPDATES" | "GUILD_TAG_CHANGED_COACHMARK_SEEN" | "GUILD_TEMPLATE_ACCEPT" | "GUILD_TEMPLATE_ACCEPT_FAILURE" | "GUILD_TEMPLATE_ACCEPT_SUCCESS" | "GUILD_TEMPLATE_CREATE_SUCCESS" | "GUILD_TEMPLATE_DELETE_SUCCESS" | "GUILD_TEMPLATE_DIRTY_TOOLTIP_HIDE" | "GUILD_TEMPLATE_DIRTY_TOOLTIP_REFRESH" | "GUILD_TEMPLATE_LOAD_FOR_GUILD_SUCCESS" | "GUILD_TEMPLATE_MODAL_HIDE" | "GUILD_TEMPLATE_MODAL_SHOW" | "GUILD_TEMPLATE_PROMOTION_TOOLTIP_HIDE" | "GUILD_TEMPLATE_RESOLVE" | "GUILD_TEMPLATE_RESOLVE_FAILURE" | "GUILD_TEMPLATE_RESOLVE_SUCCESS" | "GUILD_TEMPLATE_SYNC_SUCCESS" | "GUILD_TOGGLE_COLLAPSE_MUTED" | "GUILD_TOP_READ_CHANNELS_FETCH_SUCCESS" | "GUILD_UNAPPLY_BOOST_FAIL" | "GUILD_UNAPPLY_BOOST_START" | "GUILD_UNAPPLY_BOOST_SUCCESS" | "GUILD_UNAVAILABLE" | "GUILD_UNLOCKED_POWERUPS_FETCH_SUCCESS" | "GUILD_UPDATE" | "GUILD_UPDATE_DISCOVERY_METADATA" | "GUILD_UPDATE_DISCOVERY_METADATA_FAIL" | "GUILD_UPDATE_DISCOVERY_METADATA_FROM_SERVER" | "GUILD_VERIFICATION_CHECK" | "HABITUAL_DND_CLEAR" | "HIDE_ACTION_SHEET" | "HIDE_ACTION_SHEET_QUICK_SWITCHER" | "HIDE_KEYBOARD_SHORTCUTS" | "HIGH_FIVE_COMPLETE" | "HIGH_FIVE_COMPLETE_CLEAR" | "HIGH_FIVE_QUEUE" | "HIGH_FIVE_REMOVE" | "HIGH_FIVE_SET_ENABLED" | "HOTSPOT_HIDE" | "HOTSPOT_OVERRIDE_CLEAR" | "HOTSPOT_OVERRIDE_SET" | "HYPESQUAD_ONLINE_MEMBERSHIP_JOIN_SUCCESS" | "HYPESQUAD_ONLINE_MEMBERSHIP_LEAVE_SUCCESS" | "IDLE" | "IMPERSONATE_STOP" | "IMPERSONATE_UPDATE" | "INBOX_OPEN" | "INCOMING_CALL_MOVE" | "INITIALIZE_MEMBER_SAFETY_STORE" | "INITIATE_AGE_VERIFICATION" | "INSTALLATION_LOCATION_ADD" | "INSTALLATION_LOCATION_FETCH_METADATA" | "INSTALLATION_LOCATION_REMOVE" | "INSTALLATION_LOCATION_UPDATE" | "INSTANT_INVITE_CLEAR" | "INSTANT_INVITE_CREATE" | "INSTANT_INVITE_CREATE_FAILURE" | "INSTANT_INVITE_CREATE_SUCCESS" | "INSTANT_INVITE_REVOKE_SUCCESS" | "INTEGRATION_CREATE" | "INTEGRATION_DELETE" | "INTEGRATION_PERMISSION_SETTINGS_APPLICATION_PERMISSIONS_FETCH_FAILURE" | "INTEGRATION_PERMISSION_SETTINGS_CLEAR" | "INTEGRATION_PERMISSION_SETTINGS_COMMANDS_FETCH_FAILURE" | "INTEGRATION_PERMISSION_SETTINGS_COMMANDS_FETCH_SUCCESS" | "INTEGRATION_PERMISSION_SETTINGS_COMMAND_UPDATE" | "INTEGRATION_PERMISSION_SETTINGS_EDIT" | "INTEGRATION_PERMISSION_SETTINGS_INIT" | "INTEGRATION_PERMISSION_SETTINGS_RESET" | "INTEGRATION_QUERY" | "INTEGRATION_QUERY_FAILURE" | "INTEGRATION_QUERY_SUCCESS" | "INTEGRATION_SETTINGS_INIT" | "INTEGRATION_SETTINGS_SAVE_FAILURE" | "INTEGRATION_SETTINGS_SAVE_SUCCESS" | "INTEGRATION_SETTINGS_SET_SECTION" | "INTEGRATION_SETTINGS_START_EDITING_COMMAND" | "INTEGRATION_SETTINGS_START_EDITING_INTEGRATION" | "INTEGRATION_SETTINGS_START_EDITING_WEBHOOK" | "INTEGRATION_SETTINGS_STOP_EDITING_COMMAND" | "INTEGRATION_SETTINGS_STOP_EDITING_INTEGRATION" | "INTEGRATION_SETTINGS_STOP_EDITING_WEBHOOK" | "INTEGRATION_SETTINGS_SUBMITTING" | "INTEGRATION_SETTINGS_UPDATE_INTEGRATION" | "INTEGRATION_SETTINGS_UPDATE_WEBHOOK" | "INTERACTION_CREATE" | "INTERACTION_FAILURE" | "INTERACTION_IFRAME_MODAL_CLOSE" | "INTERACTION_IFRAME_MODAL_CREATE" | "INTERACTION_IFRAME_MODAL_KEY_CREATE" | "INTERACTION_MODAL_CREATE" | "INTERACTION_QUEUE" | "INTERACTION_SUCCESS" | "INVITE_ACCEPT" | "INVITE_ACCEPT_FAILURE" | "INVITE_ACCEPT_SUCCESS" | "INVITE_APP_NOT_OPENED" | "INVITE_APP_OPENED" | "INVITE_APP_OPENING" | "INVITE_MODAL_CLOSE" | "INVITE_MODAL_ERROR" | "INVITE_MODAL_OPEN" | "INVITE_RESOLVE" | "INVITE_RESOLVE_FAILURE" | "INVITE_RESOLVE_SUCCESS" | "INVITE_SUGGESTIONS_SEARCH" | "KEYBINDS_ADD_KEYBIND" | "KEYBINDS_DELETE_KEYBIND" | "KEYBINDS_ENABLE_ALL_KEYBINDS" | "KEYBINDS_REGISTER_GLOBAL_KEYBIND_ACTIONS" | "KEYBINDS_SET_KEYBIND" | "KEYBOARD_NAVIGATION_EXPLAINER_MODAL_SEEN" | "LAB_FEATURE_TOGGLE" | "LAYER_POP" | "LAYER_POP_ALL" | "LAYER_PUSH" | "LAYOUT_CREATE" | "LAYOUT_CREATE_WIDGETS" | "LAYOUT_DELETE_ALL_WIDGETS" | "LAYOUT_DELETE_WIDGET" | "LAYOUT_SET_PINNED" | "LAYOUT_SET_TOP_WIDGET" | "LAYOUT_SET_WIDGET_META" | "LAYOUT_UPDATE_WIDGET" | "LIBRARY_APPLICATIONS_TEST_MODE_ENABLED" | "LIBRARY_APPLICATION_ACTIVE_BRANCH_UPDATE" | "LIBRARY_APPLICATION_ACTIVE_LAUNCH_OPTION_UPDATE" | "LIBRARY_APPLICATION_FILTER_UPDATE" | "LIBRARY_APPLICATION_FLAGS_UPDATE_START" | "LIBRARY_APPLICATION_FLAGS_UPDATE_SUCCESS" | "LIBRARY_APPLICATION_UPDATE" | "LIBRARY_FETCH_SUCCESS" | "LIBRARY_TABLE_ACTIVE_ROW_ID_UPDATE" | "LIBRARY_TABLE_SORT_UPDATE" | "LIVE_CHANNEL_NOTICE_HIDE" | "LOAD_ARCHIVED_THREADS" | "LOAD_ARCHIVED_THREADS_FAIL" | "LOAD_ARCHIVED_THREADS_SUCCESS" | "LOAD_CHANNELS" | "LOAD_DATA_HARVEST_TYPE_FAILURE" | "LOAD_DATA_HARVEST_TYPE_START" | "LOAD_FORUM_POSTS" | "LOAD_FRIEND_SUGGESTIONS_FAILURE" | "LOAD_FRIEND_SUGGESTIONS_SUCCESS" | "LOAD_GUILD_AFFINITIES_SUCCESS" | "LOAD_ICYMI_HYDRATED" | "LOAD_INVITE_SUGGESTIONS" | "LOAD_MESSAGES" | "LOAD_MESSAGES_AROUND_SUCCESS" | "LOAD_MESSAGES_FAILURE" | "LOAD_MESSAGES_SUCCESS" | "LOAD_MESSAGES_SUCCESS_CACHED" | "LOAD_MESSAGE_INTERACTION_DATA_SUCCESS" | "LOAD_MESSAGE_REQUESTS_SUPPLEMENTAL_DATA_ERROR" | "LOAD_MESSAGE_REQUESTS_SUPPLEMENTAL_DATA_SUCCESS" | "LOAD_NOTIFICATION_CENTER_ITEMS" | "LOAD_NOTIFICATION_CENTER_ITEMS_FAILURE" | "LOAD_NOTIFICATION_CENTER_ITEMS_SUCCESS" | "LOAD_PINNED_MESSAGES" | "LOAD_PINNED_MESSAGES_FAILURE" | "LOAD_PINNED_MESSAGES_SUCCESS" | "LOAD_RECENT_MENTIONS" | "LOAD_RECENT_MENTIONS_FAILURE" | "LOAD_RECENT_MENTIONS_SUCCESS" | "LOAD_REGIONS" | "LOAD_RELATIONSHIPS_FAILURE" | "LOAD_RELATIONSHIPS_SUCCESS" | "LOAD_THREADS_SUCCESS" | "LOAD_USER_AFFINITIES_V2" | "LOAD_USER_AFFINITIES_V2_FAILURE" | "LOAD_USER_AFFINITIES_V2_SUCCESS" | "LOCAL_ACTIVITY_UPDATE" | "LOCAL_MESSAGES_LOADED" | "LOCAL_MESSAGE_CREATE" | "LOGIN" | "LOGIN_ACCOUNT_DISABLED" | "LOGIN_ACCOUNT_SCHEDULED_FOR_DELETION" | "LOGIN_ATTEMPTED" | "LOGIN_FAILURE" | "LOGIN_MFA" | "LOGIN_MFA_STEP" | "LOGIN_PASSWORD_RECOVERY_PHONE_VERIFICATION" | "LOGIN_PHONE_IP_AUTHORIZATION_REQUIRED" | "LOGIN_RESET" | "LOGIN_STATUS_RESET" | "LOGIN_SUCCESS" | "LOGIN_SUSPENDED_USER" | "LOGOUT" | "LOGOUT_AUTH_SESSIONS_SUCCESS" | "MASKED_LINK_ADD_TRUSTED_DOMAIN" | "MASKED_LINK_ADD_TRUSTED_PROTOCOL" | "MAX_MEMBER_COUNT_NOTICE_DISMISS" | "MEDIA_ENGINE_APPLY_MEDIA_FILTER_SETTINGS" | "MEDIA_ENGINE_APPLY_MEDIA_FILTER_SETTINGS_ERROR" | "MEDIA_ENGINE_APPLY_MEDIA_FILTER_SETTINGS_START" | "MEDIA_ENGINE_CONNECTION_STATS" | "MEDIA_ENGINE_CONNECTION_STATS_HISTORY_RESET" | "MEDIA_ENGINE_DEVICES" | "MEDIA_ENGINE_INTERACTION_REQUIRED" | "MEDIA_ENGINE_NOISE_CANCELLATION_ERROR" | "MEDIA_ENGINE_NOISE_CANCELLATION_ERROR_RESET" | "MEDIA_ENGINE_PERMISSION" | "MEDIA_ENGINE_SET_AEC_DUMP" | "MEDIA_ENGINE_SET_AUDIO_ENABLED" | "MEDIA_ENGINE_SET_ENABLE_HARDWARE_MUTE_NOTICE" | "MEDIA_ENGINE_SET_EXPERIMENTAL_ENCODERS" | "MEDIA_ENGINE_SET_EXPERIMENTAL_SOUNDSHARE" | "MEDIA_ENGINE_SET_GO_LIVE_SOURCE" | "MEDIA_ENGINE_SET_HARDWARE_ENCODING" | "MEDIA_ENGINE_SET_OPEN_H264" | "MEDIA_ENGINE_SET_USE_SYSTEM_SCREENSHARE_PICKER" | "MEDIA_ENGINE_SET_VIDEO_DEVICE" | "MEDIA_ENGINE_SET_VIDEO_ENABLED" | "MEDIA_ENGINE_SET_VIDEO_HOOK" | "MEDIA_ENGINE_SOUNDSHARE_FAILED" | "MEDIA_ENGINE_SOUNDSHARE_TRANSMITTING" | "MEDIA_ENGINE_VIDEO_SOURCE_QUALITY_CHANGED" | "MEDIA_ENGINE_VIDEO_STATE_CHANGED" | "MEDIA_ENGINE_VOICE_ACTIVITY_DETECTION_ERROR" | "MEDIA_PLAYBACK_POSITION_UPDATE" | "MEDIA_PLAYBACK_RATE_UPDATE" | "MEDIA_POST_EMBED_FETCH" | "MEDIA_POST_EMBED_FETCH_FAILURE" | "MEDIA_POST_EMBED_FETCH_SUCCESS" | "MEDIA_SESSION_JOINED" | "MEMBER_SAFETY_GUILD_MEMBER_SEARCH_SUCCESS" | "MEMBER_SAFETY_GUILD_MEMBER_UPDATE_BATCH" | "MEMBER_SAFETY_NEW_MEMBER_TIMESTAMP_REFRESH" | "MEMBER_SAFETY_PAGINATION_TOKEN_UPDATE" | "MEMBER_SAFETY_PAGINATION_UPDATE" | "MEMBER_SAFETY_SEARCH_STATE_UPDATE" | "MEMBER_VERIFICATION_FORM_FETCH_FAIL" | "MEMBER_VERIFICATION_FORM_UPDATE" | "MESSAGE_ACK" | "MESSAGE_ACKED" | "MESSAGE_CREATE" | "MESSAGE_DELETE" | "MESSAGE_DELETE_BULK" | "MESSAGE_EDIT_FAILED_AUTOMOD" | "MESSAGE_END_EDIT" | "MESSAGE_EXPLICIT_CONTENT_FP_CREATE" | "MESSAGE_EXPLICIT_CONTENT_FP_SUBMIT" | "MESSAGE_EXPLICIT_CONTENT_SCAN_TIMEOUT" | "MESSAGE_GIFT_INTENT_SHOWN" | "MESSAGE_LENGTH_UPSELL" | "MESSAGE_NOTIFICATION_SHOWN" | "MESSAGE_PREVIEWS_LOADED" | "MESSAGE_PREVIEWS_LOCALLY_LOADED" | "MESSAGE_REACTION_ADD" | "MESSAGE_REACTION_ADD_MANY" | "MESSAGE_REACTION_ADD_USERS" | "MESSAGE_REACTION_REMOVE" | "MESSAGE_REACTION_REMOVE_ALL" | "MESSAGE_REACTION_REMOVE_EMOJI" | "MESSAGE_REMINDER_DUE" | "MESSAGE_REQUEST_ACCEPT_OPTIMISTIC" | "MESSAGE_REQUEST_ACK" | "MESSAGE_REQUEST_CLEAR_ACK" | "MESSAGE_REVEAL" | "MESSAGE_SEND_FAILED" | "MESSAGE_SEND_FAILED_AUTOMOD" | "MESSAGE_START_EDIT" | "MESSAGE_UPDATE" | "MESSAGE_UPDATE_EDIT" | "MFA_CLEAR_BACKUP_CODES" | "MFA_DISABLE_SUCCESS" | "MFA_ENABLE_SUCCESS" | "MFA_SEEN_BACKUP_CODE_PROMPT" | "MFA_SEND_VERIFICATION_KEY" | "MFA_SMS_TOGGLE" | "MFA_SMS_TOGGLE_COMPLETE" | "MFA_VIEW_BACKUP_CODES" | "MFA_WEBAUTHN_CREDENTIALS_LOADED" | "MOBILE_NATIVE_UPDATE_CHECK_FINISHED" | "MOBILE_WEB_SIDEBAR_CLOSE" | "MOBILE_WEB_SIDEBAR_OPEN" | "MODAL_POP" | "MODAL_PUSH" | "MOD_VIEW_SEARCH_FINISH" | "MULTI_ACCOUNT_INVALIDATE_PUSH_SYNC_TOKENS" | "MULTI_ACCOUNT_MOBILE_EXPERIMENT_UPDATE" | "MULTI_ACCOUNT_MOVE_ACCOUNT" | "MULTI_ACCOUNT_REMOVE_ACCOUNT" | "MULTI_ACCOUNT_UPDATE_PUSH_SYNC_TOKEN" | "MULTI_ACCOUNT_VALIDATE_TOKEN_FAILURE" | "MULTI_ACCOUNT_VALIDATE_TOKEN_REQUEST" | "MULTI_ACCOUNT_VALIDATE_TOKEN_SUCCESS" | "MUTUAL_FRIENDS_FETCH_FAILURE" | "MUTUAL_FRIENDS_FETCH_START" | "MUTUAL_FRIENDS_FETCH_SUCCESS" | "NATIVE_APP_MODAL_OPENED" | "NATIVE_APP_MODAL_OPENING" | "NATIVE_APP_MODAL_OPEN_FAILED" | "NATIVE_SCREEN_SHARE_PICKER_CANCEL" | "NATIVE_SCREEN_SHARE_PICKER_ERROR" | "NATIVE_SCREEN_SHARE_PICKER_PRESENT" | "NATIVE_SCREEN_SHARE_PICKER_RELEASE" | "NATIVE_SCREEN_SHARE_PICKER_UPDATE" | "NEWLY_ADDED_EMOJI_SEEN_ACKNOWLEDGED" | "NEWLY_ADDED_EMOJI_SEEN_PENDING" | "NEWLY_ADDED_EMOJI_SEEN_UPDATED" | "NEW_PAYMENT_SOURCE_ADDRESS_INFO_UPDATE" | "NEW_PAYMENT_SOURCE_CARD_INFO_UPDATE" | "NEW_PAYMENT_SOURCE_CLEAR_ERROR" | "NEW_PAYMENT_SOURCE_STRIPE_PAYMENT_REQUEST_UPDATE" | "NOTICE_DISABLE" | "NOTICE_DISMISS" | "NOTICE_SHOW" | "NOTIFICATIONS_SET_DESKTOP_TYPE" | "NOTIFICATIONS_SET_DISABLED_SOUNDS" | "NOTIFICATIONS_SET_DISABLE_UNREAD_BADGE" | "NOTIFICATIONS_SET_NOTIFY_MESSAGES_IN_SELECTED_CHANNEL" | "NOTIFICATIONS_SET_PERMISSION_STATE" | "NOTIFICATIONS_SET_TASKBAR_FLASH" | "NOTIFICATIONS_SET_TTS_TYPE" | "NOTIFICATIONS_TOGGLE_ALL_DISABLED" | "NOTIFICATION_CENTER_CLEAR_GUILD_MENTIONS" | "NOTIFICATION_CENTER_ITEMS_ACK" | "NOTIFICATION_CENTER_ITEMS_ACK_FAILURE" | "NOTIFICATION_CENTER_ITEMS_LOCAL_ACK" | "NOTIFICATION_CENTER_ITEM_COMPLETED" | "NOTIFICATION_CENTER_ITEM_CREATE" | "NOTIFICATION_CENTER_ITEM_DELETE" | "NOTIFICATION_CENTER_ITEM_DELETE_FAILURE" | "NOTIFICATION_CENTER_REFRESH" | "NOTIFICATION_CENTER_SET_ACTIVE" | "NOTIFICATION_CENTER_SET_TAB" | "NOTIFICATION_CENTER_TAB_FOCUSED" | "NOTIFICATION_CLICK" | "NOTIFICATION_CREATE" | "NOTIFICATION_SETTINGS_UPDATE" | "NOW_PLAYING_MOUNTED" | "NOW_PLAYING_UNMOUNTED" | "NUF_COMPLETE" | "NUF_NEW_USER" | "OAUTH2_TOKEN_REVOKE" | "ONLINE_GUILD_MEMBER_COUNT_UPDATE" | "OUTBOUND_PROMOTIONS_SEEN" | "OUTBOUND_PROMOTION_NOTICE_DISMISS" | "OVERLAY_ACTIVATE_REGION" | "OVERLAY_CALL_PRIVATE_CHANNEL" | "OVERLAY_CRASHED" | "OVERLAY_DEACTIVATE_ALL_REGIONS" | "OVERLAY_DISABLE_EXTERNAL_LINK_ALERT" | "OVERLAY_FOCUSED" | "OVERLAY_FORCE_RENDER_MODE" | "OVERLAY_INCOMPATIBLE_APP" | "OVERLAY_INITIALIZE" | "OVERLAY_JOIN_GAME" | "OVERLAY_MESSAGE_EVENT_ACTION" | "OVERLAY_NOTIFICATION_EVENT" | "OVERLAY_READY" | "OVERLAY_RELOAD" | "OVERLAY_RENDER_DEBUG_CLEAR_TRACKED_PIDS" | "OVERLAY_RENDER_DEBUG_MODE" | "OVERLAY_SELECT_CALL" | "OVERLAY_SELECT_CHANNEL" | "OVERLAY_SET_ASSOCIATED_GAME" | "OVERLAY_SET_AVATAR_SIZE_MODE" | "OVERLAY_SET_CLICK_ZONES" | "OVERLAY_SET_DISABLE_CLICKABLE_REGIONS" | "OVERLAY_SET_DISPLAY_NAME_MODE" | "OVERLAY_SET_DISPLAY_USER_MODE" | "OVERLAY_SET_ENABLED" | "OVERLAY_SET_GAME_INVITE_NOTIFICATION" | "OVERLAY_SET_GPU_BOOST_REQUESTED" | "OVERLAY_SET_INPUT_LOCKED" | "OVERLAY_SET_INVITE_MESSAGE" | "OVERLAY_SET_LIMITED_INTERACTION_OVERRIDE" | "OVERLAY_SET_NOTIFICATION_DISABLED_SETTING" | "OVERLAY_SET_NOTIFICATION_POSITION_MODE" | "OVERLAY_SET_NOT_IDLE" | "OVERLAY_SET_PREVIEW_IN_GAME_MODE" | "OVERLAY_SET_SHOW_KEYBIND_INDICATORS" | "OVERLAY_SET_TEXT_WIDGET_OPACITY" | "OVERLAY_SOUNDBOARD_SOUNDS_FETCH_REQUEST" | "OVERLAY_START_SESSION" | "OVERLAY_SUCCESSFULLY_SHOWN" | "OVERLAY_UPDATE_OVERLAY_METHOD" | "OVERLAY_UPDATE_OVERLAY_STATE" | "OVERLAY_WIDGET_CHANGED" | "PASSIVE_UPDATE_V2" | "PASSWORDLESS_FAILURE" | "PASSWORDLESS_START" | "PASSWORD_UPDATED" | "PAYMENT_AUTHENTICATION_CLEAR_ERROR" | "PAYMENT_AUTHENTICATION_ERROR" | "PAYMENT_UPDATE" | "PERMISSION_CLEAR_ELEVATED_PROCESS" | "PERMISSION_CLEAR_PTT_ADMIN_WARNING" | "PERMISSION_CLEAR_SUPPRESS_WARNING" | "PERMISSION_CLEAR_VAD_WARNING" | "PERMISSION_CONTINUE_NONELEVATED_PROCESS" | "PERMISSION_REQUEST_ELEVATED_PROCESS" | "PHONE_SET_COUNTRY_CODE" | "PICTURE_IN_PICTURE_CLOSE" | "PICTURE_IN_PICTURE_HIDE" | "PICTURE_IN_PICTURE_MOVE" | "PICTURE_IN_PICTURE_OPEN" | "PICTURE_IN_PICTURE_RESIZE" | "PICTURE_IN_PICTURE_SHOW" | "PICTURE_IN_PICTURE_UPDATE_RECT" | "PICTURE_IN_PICTURE_UPDATE_SELECTED_WINDOW" | "POGGERMODE_ACHIEVEMENT_UNLOCK" | "POGGERMODE_SETTINGS_UPDATE" | "POGGERMODE_TEMPORARILY_DISABLED" | "POGGERMODE_UPDATE_COMBO" | "POGGERMODE_UPDATE_MESSAGE_COMBO" | "POPOUT_WINDOW_ADD_STYLESHEET" | "POPOUT_WINDOW_CLOSE" | "POPOUT_WINDOW_OPEN" | "POPOUT_WINDOW_SET_ALWAYS_ON_TOP" | "POST_CONNECTION_OPEN" | "POTIONS_SET_CONFETTI_MODE" | "POTIONS_TRIGGER_MESSAGE_CONFETTI" | "PREMIUM_MARKETING_DATA_READY" | "PREMIUM_MARKETING_PREVIEW" | "PREMIUM_PAYMENT_ERROR_CLEAR" | "PREMIUM_PAYMENT_MODAL_CLOSE" | "PREMIUM_PAYMENT_MODAL_OPEN" | "PREMIUM_PAYMENT_SUBSCRIBE_FAIL" | "PREMIUM_PAYMENT_SUBSCRIBE_START" | "PREMIUM_PAYMENT_SUBSCRIBE_SUCCESS" | "PREMIUM_PAYMENT_UPDATE_FAIL" | "PREMIUM_PAYMENT_UPDATE_SUCCESS" | "PREMIUM_REQUIRED_MODAL_CLOSE" | "PREMIUM_REQUIRED_MODAL_OPEN" | "PRESENCES_REPLACE" | "PRESENCE_SUBSCRIPTIONS_ADD" | "PRESENCE_UPDATES" | "PRIVATE_CHANNEL_RECIPIENTS_ADD_USER" | "PRIVATE_CHANNEL_RECIPIENTS_INVITE_CLOSE" | "PRIVATE_CHANNEL_RECIPIENTS_INVITE_OPEN" | "PRIVATE_CHANNEL_RECIPIENTS_INVITE_QUERY" | "PRIVATE_CHANNEL_RECIPIENTS_INVITE_SELECT" | "PRIVATE_CHANNEL_RECIPIENTS_REMOVE_USER" | "PROFILE_CUSTOMIZATION_OPEN_PREVIEW_MODAL" | "PROFILE_EFFECTS_SET_TRY_IT_OUT" | "PROXY_BLOCKED_REQUEST" | "PUBLIC_UPSELL_NOTICE_DISMISS" | "PURCHASED_ITEMS_FESTIVITY_FETCH_WOW_MOMENT_MEDIA_FAILURE" | "PURCHASED_ITEMS_FESTIVITY_FETCH_WOW_MOMENT_MEDIA_SUCCESS" | "PURCHASED_ITEMS_FESTIVITY_IS_FETCHING_WOW_MOMENT_MEDIA" | "PURCHASED_ITEMS_FESTIVITY_SET_CAN_PLAY_WOW_MOMENT" | "PUSH_NOTIFICATION_CLICK" | "QUESTS_CLAIM_REWARD_BEGIN" | "QUESTS_CLAIM_REWARD_FAILURE" | "QUESTS_CLAIM_REWARD_SUCCESS" | "QUESTS_DELIVERY_OVERRIDE" | "QUESTS_DISMISS_CONTENT_BEGIN" | "QUESTS_DISMISS_CONTENT_FAILURE" | "QUESTS_DISMISS_CONTENT_SUCCESS" | "QUESTS_DISMISS_PROGRESS_TRACKING_FAILURE_NOTICE" | "QUESTS_ENROLL_BEGIN" | "QUESTS_ENROLL_FAILURE" | "QUESTS_ENROLL_SUCCESS" | "QUESTS_FETCH_CLAIMED_QUESTS_BEGIN" | "QUESTS_FETCH_CLAIMED_QUESTS_FAILURE" | "QUESTS_FETCH_CLAIMED_QUESTS_SUCCESS" | "QUESTS_FETCH_CURRENT_QUESTS_BEGIN" | "QUESTS_FETCH_CURRENT_QUESTS_FAILURE" | "QUESTS_FETCH_CURRENT_QUESTS_SUCCESS" | "QUESTS_FETCH_QUEST_TO_DELIVER_BEGIN" | "QUESTS_FETCH_QUEST_TO_DELIVER_FAILURE" | "QUESTS_FETCH_QUEST_TO_DELIVER_SUCCESS" | "QUESTS_FETCH_REWARD_CODE_BEGIN" | "QUESTS_FETCH_REWARD_CODE_FAILURE" | "QUESTS_FETCH_REWARD_CODE_SUCCESS" | "QUESTS_PREVIEW_UPDATE_SUCCESS" | "QUESTS_SELECT_TASK_PLATFORM" | "QUESTS_SEND_HEARTBEAT_FAILURE" | "QUESTS_SEND_HEARTBEAT_SUCCESS" | "QUESTS_UPDATE_OPTIMISTIC_PROGRESS" | "QUESTS_USER_COMPLETION_UPDATE" | "QUESTS_USER_STATUS_UPDATE" | "QUEUE_INTERACTION_COMPONENT_STATE" | "QUICKSWITCHER_HIDE" | "QUICKSWITCHER_SEARCH" | "QUICKSWITCHER_SELECT" | "QUICKSWITCHER_SHOW" | "QUICKSWITCHER_SWITCH_TO" | "RECEIVE_CHANNEL_AFFINITIES" | "RECEIVE_CHANNEL_SUMMARIES" | "RECEIVE_CHANNEL_SUMMARIES_BULK" | "RECEIVE_CHANNEL_SUMMARY" | "RECENT_MENTION_DELETE" | "RECOMPUTE_READ_STATES" | "REFERRALS_FETCH_ELIGIBLE_USER_FAIL" | "REFERRALS_FETCH_ELIGIBLE_USER_START" | "REFERRALS_FETCH_ELIGIBLE_USER_SUCCESS" | "REGISTER" | "REGISTER_SUCCESS" | "RELATIONSHIP_ADD" | "RELATIONSHIP_IGNORE_USER_SUCCESS" | "RELATIONSHIP_PENDING_INCOMING_REMOVED" | "RELATIONSHIP_REMOVE" | "RELATIONSHIP_UPDATE" | "REMOTE_COMMAND" | "REMOTE_SESSION_CONNECT" | "REMOTE_SESSION_DISCONNECT" | "REMOVE_AUTOMOD_MESSAGE_NOTICE" | "REPORT_AV_ERROR" | "REPORT_TO_MOD_REPORT_MESSAGE_SUCCESS" | "REQUEST_CHANNEL_AFFINITIES" | "REQUEST_CHANNEL_SUMMARIES" | "REQUEST_CHANNEL_SUMMARIES_BULK" | "REQUEST_CHANNEL_SUMMARY" | "REQUEST_FORUM_UNREADS" | "REQUEST_SOUNDBOARD_SOUNDS" | "RESET_NOTIFICATION_CENTER" | "RESET_PAYMENT_ID" | "RESET_PREVIEW_CLIENT_THEME" | "RESET_SOCKET" | "RESORT_THREADS" | "RPC_APP_AUTHENTICATED" | "RPC_APP_CONNECTED" | "RPC_APP_DISCONNECTED" | "RPC_NOTIFICATION_CREATE" | "RPC_SERVER_READY" | "RTC_CONNECTION_CLIENT_CONNECT" | "RTC_CONNECTION_CLIENT_DISCONNECT" | "RTC_CONNECTION_FLAGS" | "RTC_CONNECTION_LOSS_RATE" | "RTC_CONNECTION_PING" | "RTC_CONNECTION_PLATFORM" | "RTC_CONNECTION_REMOTE_VIDEO_SINK_WANTS" | "RTC_CONNECTION_ROSTER_MAP_UPDATE" | "RTC_CONNECTION_SECURE_FRAMES_UPDATE" | "RTC_CONNECTION_STATE" | "RTC_CONNECTION_UPDATE_ID" | "RTC_CONNECTION_USERS_MERGED" | "RTC_CONNECTION_VIDEO" | "RTC_DEBUG_MODAL_CLOSE" | "RTC_DEBUG_MODAL_OPEN" | "RTC_DEBUG_MODAL_OPEN_REPLAY" | "RTC_DEBUG_MODAL_OPEN_REPLAY_AT_PATH" | "RTC_DEBUG_MODAL_SET_SECTION" | "RTC_DEBUG_MODAL_UPDATE_VIDEO_OUTPUT" | "RTC_DEBUG_POPOUT_WINDOW_OPEN" | "RTC_DEBUG_SET_RECORDING_FLAG" | "RTC_DEBUG_SET_SIMULCAST_OVERRIDE" | "RTC_LATENCY_TEST_COMPLETE" | "RUNNING_GAMES_CHANGE" | "RUNNING_GAME_ADD_OVERRIDE" | "RUNNING_GAME_DELETE_ENTRY" | "RUNNING_GAME_EDIT_NAME" | "RUNNING_GAME_TOGGLE_DETECTION" | "RUNNING_GAME_TOGGLE_OVERLAY" | "RUNNING_STREAMER_TOOLS_CHANGE" | "SAFETY_HUB_APPEAL_CLOSE" | "SAFETY_HUB_APPEAL_OPEN" | "SAFETY_HUB_APPEAL_SIGNAL_CUSTOM_INPUT_CHANGE" | "SAFETY_HUB_APPEAL_SIGNAL_SELECT" | "SAFETY_HUB_AUTOMATED_UNDERAGE_APPEAL_MODAL_CLOSE" | "SAFETY_HUB_AUTOMATED_UNDERAGE_APPEAL_MODAL_OPEN" | "SAFETY_HUB_AUTOMATED_UNDERAGE_APPEAL_START_POLL" | "SAFETY_HUB_AUTOMATED_UNDERAGE_APPEAL_SUBMIT_SUCCESS" | "SAFETY_HUB_CHECK_AUTOMATED_UNDERAGE_APPEAL_FAILURE" | "SAFETY_HUB_CHECK_AUTOMATED_UNDERAGE_APPEAL_START" | "SAFETY_HUB_CHECK_AUTOMATED_UNDERAGE_APPEAL_SUCCESS" | "SAFETY_HUB_FETCH_CLASSIFICATION_FAILURE" | "SAFETY_HUB_FETCH_CLASSIFICATION_START" | "SAFETY_HUB_FETCH_CLASSIFICATION_SUCCESS" | "SAFETY_HUB_FETCH_FAILURE" | "SAFETY_HUB_FETCH_START" | "SAFETY_HUB_FETCH_SUCCESS" | "SAFETY_HUB_REQUEST_AUTOMATED_UNDERAGE_APPEAL_FAILURE" | "SAFETY_HUB_REQUEST_AUTOMATED_UNDERAGE_APPEAL_START" | "SAFETY_HUB_REQUEST_AUTOMATED_UNDERAGE_APPEAL_SUCCESS" | "SAFETY_HUB_REQUEST_REVIEW_FAILURE" | "SAFETY_HUB_REQUEST_REVIEW_START" | "SAFETY_HUB_REQUEST_REVIEW_SUCCESS" | "SAVED_MESSAGES_UPDATE" | "SAVED_MESSAGE_CREATE" | "SAVED_MESSAGE_DELETE" | "SAVE_LAST_NON_VOICE_ROUTE" | "SAVE_LAST_ROUTE" | "SCHEDULED_MESSAGES_CREATE_SUCCESS" | "SCHEDULED_MESSAGES_DELETE_FAILURE" | "SCHEDULED_MESSAGES_DELETE_START" | "SCHEDULED_MESSAGES_DELETE_SUCCESS" | "SEARCH_ADD_HISTORY" | "SEARCH_AUTOCOMPLETE_QUERY_UPDATE" | "SEARCH_CLEAR_HISTORY" | "SEARCH_EDITOR_STATE_CHANGE" | "SEARCH_EDITOR_STATE_CLEAR" | "SEARCH_ENSURE_SEARCH_STATE" | "SEARCH_FINISH" | "SEARCH_INDEXING" | "SEARCH_MESSAGES_CLEAR_ALL" | "SEARCH_MESSAGES_FAILURE" | "SEARCH_MESSAGES_INDEXING" | "SEARCH_MESSAGES_START" | "SEARCH_MESSAGES_SUCCESS" | "SEARCH_RECENT_MESSAGES_CLEAR" | "SEARCH_REMOVE_HISTORY" | "SEARCH_RESULTS_QUERY_UPDATE" | "SEARCH_SCREEN_OPEN" | "SEARCH_SET_SHOW_BLOCKED_RESULTS" | "SEARCH_SET_SHOW_NO_RESULTS_ALT" | "SEARCH_START" | "SECURE_FRAMES_SETTINGS_UPDATE" | "SECURE_FRAMES_TRANSIENT_KEY_CREATE" | "SECURE_FRAMES_TRANSIENT_KEY_DELETE" | "SECURE_FRAMES_UPLOADED_KEY_VERSION_ADD" | "SECURE_FRAMES_UPLOADED_KEY_VERSION_CLEAR" | "SECURE_FRAMES_USER_VERIFIED_KEYS_DELETE" | "SECURE_FRAMES_VERIFIED_KEY_CREATE" | "SECURE_FRAMES_VERIFIED_KEY_DELETE" | "SELECTIVELY_SYNCED_USER_SETTINGS_UPDATE" | "SELECT_HOME_RESOURCE_CHANNEL" | "SELECT_NEW_MEMBER_ACTION_CHANNEL" | "SELF_PRESENCE_STORE_UPDATE" | "SESSIONS_REPLACE" | "SET_CHANNEL_BITRATE" | "SET_CHANNEL_VIDEO_QUALITY_MODE" | "SET_CONSENT_REQUIRED" | "SET_CREATED_AT_OVERRIDE" | "SET_GUILD_FOLDER_EXPANDED" | "SET_GUILD_LEADERBOARD" | "SET_HIGHLIGHTED_SUMMARY" | "SET_INTERACTION_COMPONENT_STATE" | "SET_LOCATION_METADATA" | "SET_NATIVE_PERMISSION" | "SET_PENDING_REPLY_SHOULD_MENTION" | "SET_PREMIUM_TYPE_OVERRIDE" | "SET_PREVIOUS_GO_LIVE_SETTINGS" | "SET_RECENTLY_ACTIVE_COLLAPSED" | "SET_RECENT_MENTIONS_FILTER" | "SET_RECENT_MENTIONS_STALE" | "SET_RPC_NOTIFICATION_SETTINGS" | "SET_SELECTED_SUMMARY" | "SET_SOUNDPACK" | "SET_STREAM_APP_INTENT" | "SET_SUMMARY_FEEDBACK" | "SET_THEME_OVERRIDE" | "SET_TTS_SPEECH_RATE" | "SET_USER_LEADERBOARD_LAST_UPDATE_REQUESTED" | "SET_VAD_PERMISSION" | "SHARED_CANVAS_CLEAR_DRAWABLES" | "SHARED_CANVAS_DRAW_LINE_POINT" | "SHARED_CANVAS_SET_DRAW_MODE" | "SHARED_CANVAS_UPDATE_EMOJI_HOSE" | "SHARED_CANVAS_UPDATE_LINE_POINTS" | "SHOW_ACTION_SHEET" | "SHOW_ACTION_SHEET_QUICK_SWITCHER" | "SHOW_KEYBOARD_SHORTCUTS" | "SIDEBAR_CLOSE" | "SIDEBAR_CLOSE_GUILD" | "SIDEBAR_CREATE_THREAD" | "SIDEBAR_VIEW_CHANNEL" | "SIDEBAR_VIEW_GUILD" | "SKUS_FETCH_SUCCESS" | "SKU_FETCH_FAIL" | "SKU_FETCH_START" | "SKU_FETCH_SUCCESS" | "SKU_PURCHASE_AWAIT_CONFIRMATION" | "SKU_PURCHASE_CLEAR_ERROR" | "SKU_PURCHASE_FAIL" | "SKU_PURCHASE_MODAL_CLOSE" | "SKU_PURCHASE_MODAL_OPEN" | "SKU_PURCHASE_PREVIEW_FETCH" | "SKU_PURCHASE_PREVIEW_FETCH_FAILURE" | "SKU_PURCHASE_PREVIEW_FETCH_SUCCESS" | "SKU_PURCHASE_SHOW_CONFIRMATION_STEP" | "SKU_PURCHASE_START" | "SKU_PURCHASE_SUCCESS" | "SKU_PURCHASE_UPDATE_IS_GIFT" | "SLOWMODE_RESET_COOLDOWN" | "SLOWMODE_SET_COOLDOWN" | "SOUNDBOARD_FETCH_DEFAULT_SOUNDS" | "SOUNDBOARD_FETCH_DEFAULT_SOUNDS_SUCCESS" | "SOUNDBOARD_MUTE_JOIN_SOUND" | "SOUNDBOARD_SET_OVERLAY_ENABLED" | "SOUNDBOARD_SOUNDS_RECEIVED" | "SPEAKING" | "SPEAKING_MESSAGE" | "SPEAK_MESSAGE" | "SPEAK_TEXT" | "SPELLCHECK_LEARN_WORD" | "SPELLCHECK_TOGGLE" | "SPELLCHECK_UNLEARN_WORD" | "SPOTIFY_ACCOUNT_ACCESS_TOKEN" | "SPOTIFY_ACCOUNT_ACCESS_TOKEN_REVOKE" | "SPOTIFY_NEW_TRACK" | "SPOTIFY_PLAYER_PAUSE" | "SPOTIFY_PLAYER_PLAY" | "SPOTIFY_PLAYER_STATE" | "SPOTIFY_PROFILE_UPDATE" | "SPOTIFY_SET_ACTIVE_DEVICE" | "SPOTIFY_SET_DEVICES" | "SPOTIFY_SET_PROTOCOL_REGISTERED" | "STAGE_INSTANCE_CREATE" | "STAGE_INSTANCE_DELETE" | "STAGE_INSTANCE_UPDATE" | "STAGE_MUSIC_MUTE" | "STAGE_MUSIC_PLAY" | "START_SESSION" | "STATUS_PAGE_INCIDENT" | "STATUS_PAGE_SCHEDULED_MAINTENANCE" | "STATUS_PAGE_SCHEDULED_MAINTENANCE_ACK" | "STICKER_FETCH_SUCCESS" | "STICKER_PACKS_FETCH_START" | "STICKER_PACKS_FETCH_SUCCESS" | "STICKER_PACK_FETCH_SUCCESS" | "STICKER_TRACK_USAGE" | "STOP_SPEAKING" | "STORE_LISTINGS_FETCH_FAIL" | "STORE_LISTINGS_FETCH_START" | "STORE_LISTINGS_FETCH_SUCCESS" | "STORE_LISTING_FETCH_SUCCESS" | "STREAMER_MODE_UPDATE" | "STREAMING_UPDATE" | "STREAM_CLOSE" | "STREAM_CREATE" | "STREAM_DELETE" | "STREAM_LAYOUT_UPDATE" | "STREAM_PREVIEW_FETCH_FAIL" | "STREAM_PREVIEW_FETCH_START" | "STREAM_PREVIEW_FETCH_SUCCESS" | "STREAM_SERVER_UPDATE" | "STREAM_SET_PAUSED" | "STREAM_START" | "STREAM_STOP" | "STREAM_TIMED_OUT" | "STREAM_UPDATE" | "STREAM_UPDATE_SELF_HIDDEN" | "STREAM_UPDATE_SETTINGS" | "STREAM_WATCH" | "STRIPE_TOKEN_FAILURE" | "SUBSCRIPTION_PLANS_FETCH" | "SUBSCRIPTION_PLANS_FETCH_FAILURE" | "SUBSCRIPTION_PLANS_FETCH_SUCCESS" | "SUBSCRIPTION_PLANS_RESET" | "SURVEY_FETCHED" | "SURVEY_HIDE" | "SURVEY_OVERRIDE" | "SURVEY_SEEN" | "SYSTEM_THEME_CHANGE" | "THERMAL_STATE_CHANGE" | "THREAD_CREATE" | "THREAD_CREATE_LOCAL" | "THREAD_DELETE" | "THREAD_LIST_SYNC" | "THREAD_MEMBERS_UPDATE" | "THREAD_MEMBER_LIST_UPDATE" | "THREAD_MEMBER_LOCAL_UPDATE" | "THREAD_MEMBER_UPDATE" | "THREAD_SETTINGS_DRAFT_CHANGE" | "THREAD_UPDATE" | "TOGGLE_GUILD_EXPANDED_STATE" | "TOGGLE_GUILD_FOLDER_EXPAND" | "TOGGLE_OVERLAY_CANVAS" | "TOGGLE_TOPICS_BAR" | "TOP_EMOJIS_FETCH" | "TOP_EMOJIS_FETCH_SUCCESS" | "TRUNCATE_MENTIONS" | "TRUNCATE_MESSAGES" | "TRY_ACK" | "TUTORIAL_INDICATOR_DISMISS" | "TUTORIAL_INDICATOR_HIDE" | "TUTORIAL_INDICATOR_SHOW" | "TUTORIAL_INDICATOR_SUPPRESS_ALL" | "TYPING_START" | "TYPING_START_LOCAL" | "TYPING_STOP" | "TYPING_STOP_LOCAL" | "UNSYNCED_USER_SETTINGS_UPDATE" | "UNVERIFIED_GAME_UPDATE" | "UPCOMING_GUILD_EVENT_NOTICE_HIDE" | "UPCOMING_GUILD_EVENT_NOTICE_SEEN" | "UPDATE_AVAILABLE" | "UPDATE_BACKGROUND_GRADIENT_PRESET" | "UPDATE_CHANNEL_DIMENSIONS" | "UPDATE_CHANNEL_LIST_DIMENSIONS" | "UPDATE_CHANNEL_LIST_SUBTITLES" | "UPDATE_CHAT_WALLPAPER_FLAG_COMPLETE" | "UPDATE_CHAT_WALLPAPER_FLAG_START" | "UPDATE_CHAT_WALLPAPER_OVERRIDES" | "UPDATE_CLIENT_PREMIUM_TYPE" | "UPDATE_CONSENTS" | "UPDATE_DATA_HARVEST_TYPE" | "UPDATE_DOWNLOADED" | "UPDATE_ERROR" | "UPDATE_GUILD_LIST_DIMENSIONS" | "UPDATE_MANUALLY" | "UPDATE_MOBILE_PENDING_THEME_INDEX" | "UPDATE_NOT_AVAILABLE" | "UPDATE_STRANGER_STATUS" | "UPDATE_THEME_PREFERENCES" | "UPDATE_TOKEN" | "UPDATE_VISIBLE_MESSAGES" | "UPLOAD_ATTACHMENT_ADD_FILES" | "UPLOAD_ATTACHMENT_CLEAR_ALL_FILES" | "UPLOAD_ATTACHMENT_POP_FILE" | "UPLOAD_ATTACHMENT_REMOVE_FILE" | "UPLOAD_ATTACHMENT_REMOVE_FILES" | "UPLOAD_ATTACHMENT_SET_FILE" | "UPLOAD_ATTACHMENT_SET_UPLOADS" | "UPLOAD_ATTACHMENT_UPDATE_FILE" | "UPLOAD_CANCEL_REQUEST" | "UPLOAD_COMPLETE" | "UPLOAD_COMPRESSION_PROGRESS" | "UPLOAD_FAIL" | "UPLOAD_FILE_UPDATE" | "UPLOAD_ITEM_CANCEL_REQUEST" | "UPLOAD_PROGRESS" | "UPLOAD_RESTORE_FAILED_UPLOAD" | "UPLOAD_START" | "USER_ACTIVITY_STATISTICS_FETCH_SUCCESS" | "USER_APPLICATION_REMOVE" | "USER_APPLICATION_UPDATE" | "USER_APPLIED_BOOSTS_FETCH_START" | "USER_APPLIED_BOOSTS_FETCH_SUCCESS" | "USER_AUTHORIZED_APPS_REQUEST" | "USER_AUTHORIZED_APPS_UPDATE" | "USER_CONNECTIONS_CALLBACK" | "USER_CONNECTIONS_INTEGRATION_JOINING" | "USER_CONNECTIONS_INTEGRATION_JOINING_ERROR" | "USER_CONNECTIONS_UPDATE" | "USER_CONNECTION_UPDATE" | "USER_GUILD_JOIN_REQUEST_COACHMARK_CLEAR" | "USER_GUILD_JOIN_REQUEST_COACHMARK_SHOW" | "USER_GUILD_JOIN_REQUEST_COOLDOWN_FETCH" | "USER_GUILD_JOIN_REQUEST_UPDATE" | "USER_GUILD_SETTINGS_CHANNEL_UPDATE" | "USER_GUILD_SETTINGS_CHANNEL_UPDATE_BULK" | "USER_GUILD_SETTINGS_FULL_UPDATE" | "USER_GUILD_SETTINGS_GUILD_AND_CHANNELS_UPDATE" | "USER_GUILD_SETTINGS_GUILD_UPDATE" | "USER_GUILD_SETTINGS_REMOVE_PENDING_CHANNEL_UPDATES" | "USER_JOIN_REQUEST_GUILDS_FETCH" | "USER_NON_CHANNEL_ACK" | "USER_NOTE_LOAD_START" | "USER_NOTE_UPDATE" | "USER_PAYMENT_BROWSER_CHECKOUT_DONE" | "USER_PAYMENT_BROWSER_CHECKOUT_STARTED" | "USER_PAYMENT_CLIENT_ADD" | "USER_PROFILE_EFFECTS_FETCH" | "USER_PROFILE_EFFECTS_FETCH_FAILURE" | "USER_PROFILE_EFFECTS_FETCH_SUCCESS" | "USER_PROFILE_FETCH_FAILURE" | "USER_PROFILE_FETCH_START" | "USER_PROFILE_FETCH_SUCCESS" | "USER_PROFILE_MODAL_CLOSE" | "USER_PROFILE_MODAL_OPEN" | "USER_PROFILE_PIN_BADGES_ON_CLIENT" | "USER_PROFILE_SIDEBAR_TOGGLE_SECTION" | "USER_PROFILE_UPDATE_FAILURE" | "USER_PROFILE_UPDATE_START" | "USER_PROFILE_UPDATE_SUCCESS" | "USER_REQUIRED_ACTION_UPDATE" | "USER_SETTINGS_ACCOUNT_CLOSE" | "USER_SETTINGS_ACCOUNT_INIT" | "USER_SETTINGS_ACCOUNT_RESET_AND_CLOSE_FORM" | "USER_SETTINGS_ACCOUNT_RESET_PENDING_LEGACY_USERNAME_DISABLED" | "USER_SETTINGS_ACCOUNT_SET_PENDING_ACCENT_COLOR" | "USER_SETTINGS_ACCOUNT_SET_PENDING_AVATAR" | "USER_SETTINGS_ACCOUNT_SET_PENDING_AVATAR_DECORATION" | "USER_SETTINGS_ACCOUNT_SET_PENDING_BANNER" | "USER_SETTINGS_ACCOUNT_SET_PENDING_BIO" | "USER_SETTINGS_ACCOUNT_SET_PENDING_GLOBAL_NAME" | "USER_SETTINGS_ACCOUNT_SET_PENDING_LEGACY_USERNAME_DISABLED" | "USER_SETTINGS_ACCOUNT_SET_PENDING_NAMEPLATE" | "USER_SETTINGS_ACCOUNT_SET_PENDING_PROFILE_EFFECT_ID" | "USER_SETTINGS_ACCOUNT_SET_PENDING_PRONOUNS" | "USER_SETTINGS_ACCOUNT_SET_PENDING_THEME_COLORS" | "USER_SETTINGS_ACCOUNT_SET_SINGLE_TRY_IT_OUT_COLLECTIBLES_ITEM" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_AVATAR" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_AVATAR_DECORATION" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_BANNER" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_PRESET" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_PROFILE_EFFECT_ID" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_THEME_COLORS" | "USER_SETTINGS_ACCOUNT_SUBMIT" | "USER_SETTINGS_ACCOUNT_SUBMIT_FAILURE" | "USER_SETTINGS_ACCOUNT_SUBMIT_SUCCESS" | "USER_SETTINGS_CLEAR_ERRORS" | "USER_SETTINGS_LOCALE_OVERRIDE" | "USER_SETTINGS_MODAL_CLEAR_SCROLL_POSITION" | "USER_SETTINGS_MODAL_CLEAR_SUBSECTION" | "USER_SETTINGS_MODAL_CLOSE" | "USER_SETTINGS_MODAL_INIT" | "USER_SETTINGS_MODAL_OPEN" | "USER_SETTINGS_MODAL_RESET" | "USER_SETTINGS_MODAL_SET_SECTION" | "USER_SETTINGS_MODAL_SUBMIT" | "USER_SETTINGS_MODAL_SUBMIT_COMPLETE" | "USER_SETTINGS_MODAL_SUBMIT_FAILURE" | "USER_SETTINGS_MODAL_UPDATE_ACCOUNT" | "USER_SETTINGS_OVERRIDE_APPLY" | "USER_SETTINGS_OVERRIDE_CLEAR" | "USER_SETTINGS_PROTO_ENQUEUE_UPDATE" | "USER_SETTINGS_PROTO_LOAD_IF_NECESSARY" | "USER_SETTINGS_PROTO_UPDATE" | "USER_SETTINGS_PROTO_UPDATE_EDIT_INFO" | "USER_SETTINGS_RESET_ALL_PENDING" | "USER_SETTINGS_RESET_ALL_TRY_IT_OUT" | "USER_SETTINGS_RESET_PENDING_ACCOUNT_CHANGES" | "USER_SETTINGS_RESET_PENDING_AVATAR_DECORATION" | "USER_SETTINGS_RESET_PENDING_PRIMARY_GUILD_CHANGES" | "USER_SETTINGS_RESET_PENDING_PROFILE_CHANGES" | "USER_SETTINGS_SET_PENDING_PRIMARY_GUILD_ID" | "USER_SOUNDBOARD_SET_VOLUME" | "USER_UPDATE" | "VIDEO_FILTER_ASSETS_FETCH_SUCCESS" | "VIDEO_FILTER_ASSET_DELETE_SUCCESS" | "VIDEO_FILTER_ASSET_UPLOAD_SUCCESS" | "VIDEO_SAVE_LAST_USED_BACKGROUND_OPTION" | "VIDEO_SIZE_UPDATE" | "VIDEO_STREAM_READY_TIMEOUT" | "VIEW_HISTORY_MARK_VIEW" | "VIRTUAL_CURRENCY_BALANCE_FETCH" | "VIRTUAL_CURRENCY_BALANCE_FETCH_FAIL" | "VIRTUAL_CURRENCY_BALANCE_FETCH_SUCCESS" | "VIRTUAL_CURRENCY_BALANCE_UPDATE" | "VIRTUAL_CURRENCY_EARNED_ORBS_COACHMARK_CLOSE" | "VIRTUAL_CURRENCY_EARNED_ORBS_COACHMARK_OPEN" | "VIRTUAL_CURRENCY_ONBOARDING_MODAL_OPEN" | "VIRTUAL_CURRENCY_ONBOARDING_MODAL_RESET" | "VIRTUAL_CURRENCY_REDEEM_FAIL" | "VIRTUAL_CURRENCY_REDEEM_START" | "VIRTUAL_CURRENCY_REDEEM_SUCCESS" | "VIRTUAL_CURRENCY_SET_BALANCE_PILL_OVERLAY" | "VOICE_CATEGORY_COLLAPSE" | "VOICE_CATEGORY_EXPAND" | "VOICE_CHANNEL_EFFECT_CLEAR" | "VOICE_CHANNEL_EFFECT_RECENT_EMOJI" | "VOICE_CHANNEL_EFFECT_SEND" | "VOICE_CHANNEL_EFFECT_SENT_LOCAL" | "VOICE_CHANNEL_EFFECT_TOGGLE_ANIMATION_TYPE" | "VOICE_CHANNEL_EFFECT_UPDATE_TIME_STAMP" | "VOICE_CHANNEL_SELECT" | "VOICE_CHANNEL_STATUS_UPDATE" | "VOICE_FILTER_APPLIED" | "VOICE_FILTER_APPLY_FAILED" | "VOICE_FILTER_CATALOG_FETCH_FAILED" | "VOICE_FILTER_CATALOG_FETCH_SUCCESS" | "VOICE_FILTER_DEV_TOOLS_SET_UPDATE_TIME" | "VOICE_FILTER_DOWNLOAD_FAILED" | "VOICE_FILTER_DOWNLOAD_PROGRESS" | "VOICE_FILTER_DOWNLOAD_STARTED" | "VOICE_FILTER_FILE_READY" | "VOICE_FILTER_LAGGING" | "VOICE_FILTER_LOOPBACK_TOGGLE" | "VOICE_FILTER_NATIVE_MODULE_STATE_CHANGE" | "VOICE_FILTER_REQUEST_SWITCH" | "VOICE_FILTER_UPDATE_LIMITED_TIME_VOICES" | "VOICE_SERVER_UPDATE" | "VOICE_STATE_UPDATES" | "WAIT_FOR_REMOTE_SESSION" | "WEBHOOKS_FETCHING" | "WEBHOOKS_UPDATE" | "WEBHOOK_CREATE" | "WEBHOOK_DELETE" | "WEBHOOK_UPDATE" | "WELCOME_SCREEN_FETCH_FAIL" | "WELCOME_SCREEN_FETCH_START" | "WELCOME_SCREEN_FETCH_SUCCESS" | "WELCOME_SCREEN_SETTINGS_CLEAR" | "WELCOME_SCREEN_SETTINGS_RESET" | "WELCOME_SCREEN_SETTINGS_UPDATE" | "WELCOME_SCREEN_SUBMIT" | "WELCOME_SCREEN_SUBMIT_FAILURE" | "WELCOME_SCREEN_SUBMIT_SUCCESS" | "WELCOME_SCREEN_UPDATE" | "WELCOME_SCREEN_VIEW" | "WINDOW_FOCUS" | "WINDOW_FULLSCREEN_CHANGE" | "WINDOW_HIDDEN" | "WINDOW_INIT" | "WINDOW_RESIZED" | "WINDOW_UNLOAD" | "WINDOW_VISIBILITY_CHANGE" | "WRITE_CACHES"; diff --git a/packages/discord-types/src/index.d.ts b/packages/discord-types/src/index.d.ts new file mode 100644 index 00000000..6d9356b4 --- /dev/null +++ b/packages/discord-types/src/index.d.ts @@ -0,0 +1,9 @@ +export * from "./common"; +export * from "./classes"; +export * from "./components"; +export * from "./flux"; +export * from "./fluxEvents"; +export * from "./menu"; +export * from "./stores"; +export * from "./utils"; +export * as Webpack from "../webpack"; diff --git a/src/webpack/common/types/menu.d.ts b/packages/discord-types/src/menu.d.ts similarity index 71% rename from src/webpack/common/types/menu.d.ts rename to packages/discord-types/src/menu.d.ts index 5ae9062c..0866e1c3 100644 --- a/src/webpack/common/types/menu.d.ts +++ b/packages/discord-types/src/menu.d.ts @@ -1,21 +1,3 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2023 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - import type { ComponentType, CSSProperties, MouseEvent, PropsWithChildren, ReactNode, UIEvent } from "react"; type RC<C> = ComponentType<PropsWithChildren<C & Record<string, any>>>; @@ -73,7 +55,7 @@ export interface Menu { renderValue?(value: number): string, }>; MenuSearchControl: RC<{ - query: string + query: string; onChange(query: string): void; placeholder?: string; }>; diff --git a/packages/discord-types/src/stores/ChannelStore.d.ts b/packages/discord-types/src/stores/ChannelStore.d.ts new file mode 100644 index 00000000..1507ba5e --- /dev/null +++ b/packages/discord-types/src/stores/ChannelStore.d.ts @@ -0,0 +1,24 @@ +import { Channel, FluxStore } from ".."; + +export class ChannelStore extends FluxStore { + getChannel(channelId: string): Channel; + getBasicChannel(channelId: string): Channel | undefined; + hasChannel(channelId: string): boolean; + + getChannelIds(guildId?: string | null): string[]; + getMutableBasicGuildChannelsForGuild(guildId: string): Record<string, Channel>; + getMutableGuildChannelsForGuild(guildId: string): Record<string, Channel>; + getAllThreadsForGuild(guildId: string): Channel[]; + getAllThreadsForParent(channelId: string): Channel[]; + + getDMFromUserId(userId: string): string; + getDMChannelFromUserId(userId: string): Channel | undefined; + getDMUserIds(): string[]; + getMutableDMsByUserIds(): Record<string, string>; + getMutablePrivateChannels(): Record<string, Channel>; + getSortedPrivateChannels(): Channel[]; + + getGuildChannelsVersion(guildId: string): number; + getPrivateChannelsVersion(): number; + getInitialOverlayState(): Record<string, Channel>; +} diff --git a/packages/discord-types/src/stores/DraftStore.d.ts b/packages/discord-types/src/stores/DraftStore.d.ts new file mode 100644 index 00000000..98b34cdf --- /dev/null +++ b/packages/discord-types/src/stores/DraftStore.d.ts @@ -0,0 +1,43 @@ +import { FluxStore } from ".."; + +export enum DraftType { + ChannelMessage = 0, + ThreadSettings = 1, + FirstThreadMessage = 2, + ApplicationLauncherCommand = 3, + Poll = 4, + SlashCommand = 5, + ForwardContextMessage = 6 +} + +export interface Draft { + timestamp: number; + draft: string; +} + +export interface ThreadSettingsDraft { + timestamp: number; + parentMessageId?: string; + name?: string; + isPrivate?: boolean; + parentChannelId?: string; + location?: string; +} + +export type ChannelDrafts = { + [DraftType.ThreadSettings]: ThreadSettingsDraft; +} & { + [key in Exclude<DraftType, DraftType.ThreadSettings>]: Draft; +}; + +export type UserDrafts = Partial<Record<string, ChannelDrafts>>; +export type DraftState = Partial<Record<string, UserDrafts>>; + +export class DraftStore extends FluxStore { + getState(): DraftState; + getRecentlyEditedDrafts(type: DraftType): Array<Draft & { channelId: string; }>; + getDraft(channelId: string, type: DraftType): string; + + getThreadSettings(channelId: string): ThreadSettingsDraft | null | undefined; + getThreadDraftWithParentMessageId(parentMessageId: string): ThreadSettingsDraft | null | undefined; +} diff --git a/packages/discord-types/src/stores/EmojiStore.d.ts b/packages/discord-types/src/stores/EmojiStore.d.ts new file mode 100644 index 00000000..93161b2f --- /dev/null +++ b/packages/discord-types/src/stores/EmojiStore.d.ts @@ -0,0 +1,57 @@ +import { Channel, CustomEmoji, Emoji, FluxStore } from ".."; + +export class EmojiStore extends FluxStore { + getCustomEmojiById(id?: string | null): CustomEmoji | undefined; + getUsableCustomEmojiById(id?: string | null): CustomEmoji | undefined; + getGuilds(): Record<string, { + id: string; + get emojis(): CustomEmoji[]; + get rawEmojis(): CustomEmoji[]; + get usableEmojis(): CustomEmoji[]; + get emoticons(): any[]; + getEmoji(id: string): CustomEmoji | undefined; + isUsable(emoji: CustomEmoji): boolean; + }>; + getGuildEmoji(guildId?: string | null): CustomEmoji[]; + getNewlyAddedEmoji(guildId?: string | null): CustomEmoji[]; + getTopEmoji(guildId?: string | null): CustomEmoji[]; + getTopEmojisMetadata(guildId?: string | null): { + emojiIds: string[]; + topEmojisTTL: number; + }; + hasPendingUsage(): boolean; + hasUsableEmojiInAnyGuild(): boolean; + searchWithoutFetchingLatest(data: any): any; + getSearchResultsOrder(...args: any[]): any; + getState(): { + pendingUsages: { key: string, timestamp: number; }[]; + }; + searchWithoutFetchingLatest(data: { + channel: Channel; + query: string; + count?: number; + intention: number; + includeExternalGuilds?: boolean; + matchComparator?(name: string): boolean; + }): Record<"locked" | "unlocked", Emoji[]>; + + getDisambiguatedEmojiContext(): { + backfillTopEmojis: Record<any, any>; + customEmojis: Record<string, CustomEmoji>; + emojisById: Record<string, CustomEmoji>; + emojisByName: Record<string, CustomEmoji>; + emoticonRegex: RegExp | null; + emoticonsByName: Record<string, any>; + escapedEmoticonNames: string; + favoriteNamesAndIds?: any; + favorites?: any; + frequentlyUsed?: any; + groupedCustomEmojis: Record<string, CustomEmoji[]>; + guildId?: string; + isFavoriteEmojiWithoutFetchingLatest(e: Emoji): boolean; + newlyAddedEmoji: Record<string, CustomEmoji[]>; + topEmojis?: any; + unicodeAliases: Record<string, string>; + get favoriteEmojisWithoutFetchingLatest(): Emoji[]; + }; +} diff --git a/packages/discord-types/src/stores/FluxStore.d.ts b/packages/discord-types/src/stores/FluxStore.d.ts new file mode 100644 index 00000000..da55ac0b --- /dev/null +++ b/packages/discord-types/src/stores/FluxStore.d.ts @@ -0,0 +1,44 @@ +import { FluxDispatcher, FluxEvents } from ".."; + +type Callback = () => void; + +/* + For some reason, this causes type errors when you try to destructure it: + ```ts + interface FluxEvent { + type: FluxEvents; + [key: string]: any; + } + ``` + */ +export type FluxEvent = any; + +export type ActionHandler = (event: FluxEvent) => void; +export type ActionHandlers = Partial<Record<FluxEvents, ActionHandler>>; + +export class FluxStore { + constructor(dispatcher: FluxDispatcher, actionHandlers?: ActionHandlers); + + getName(): string; + + addChangeListener(callback: Callback): void; + /** Listener will be removed once the callback returns false. */ + addConditionalChangeListener(callback: () => boolean, preemptive?: boolean): void; + addReactChangeListener(callback: Callback): void; + removeChangeListener(callback: Callback): void; + removeReactChangeListener(callback: Callback): void; + + doEmitChanges(event: FluxEvent): void; + emitChange(): void; + + getDispatchToken(): string; + initialize(): void; + initializeIfNeeded(): void; + /** this is a setter */ + mustEmitChanges(actionHandler: ActionHandler | undefined): void; + registerActionHandlers(actionHandlers: ActionHandlers): void; + syncWith(stores: FluxStore[], callback: Callback, timeout?: number): void; + waitFor(...stores: FluxStore[]): void; + + static getAll(): FluxStore[]; +} diff --git a/packages/discord-types/src/stores/GuildMemberStore.d.ts b/packages/discord-types/src/stores/GuildMemberStore.d.ts new file mode 100644 index 00000000..9dec139a --- /dev/null +++ b/packages/discord-types/src/stores/GuildMemberStore.d.ts @@ -0,0 +1,27 @@ +import { FluxStore, GuildMember } from ".."; + +export class GuildMemberStore extends FluxStore { + /** @returns Format: [guildId-userId: Timestamp (string)] */ + getCommunicationDisabledUserMap(): Record<string, string>; + getCommunicationDisabledVersion(): number; + + getMutableAllGuildsAndMembers(): Record<string, Record<string, GuildMember>>; + + getMember(guildId: string, userId: string): GuildMember | null; + getTrueMember(guildId: string, userId: string): GuildMember | null; + getMemberIds(guildId: string): string[]; + getMembers(guildId: string): GuildMember[]; + + getCachedSelfMember(guildId: string): GuildMember | null; + getSelfMember(guildId: string): GuildMember | null; + getSelfMemberJoinedAt(guildId: string): Date | null; + + getNick(guildId: string, userId: string): string | null; + getNicknameGuildsMapping(userId: string): Record<string, string[]>; + getNicknames(userId: string): string[]; + + isMember(guildId: string, userId: string): boolean; + isMember(guildId: string, userId: string): boolean; + isGuestOrLurker(guildId: string, userId: string): boolean; + isCurrentUserGuest(guildId: string): boolean; +} diff --git a/packages/discord-types/src/stores/GuildRoleStore.d.ts b/packages/discord-types/src/stores/GuildRoleStore.d.ts new file mode 100644 index 00000000..bf0d4042 --- /dev/null +++ b/packages/discord-types/src/stores/GuildRoleStore.d.ts @@ -0,0 +1,7 @@ +import { FluxStore, Role } from ".."; + +export class GuildRoleStore extends FluxStore { + getRole(guildId: string, roleId: string): Role; + getRoles(guildId: string): Record<string, Role>; + getAllGuildRoles(): Record<string, Record<string, Role>>; +} diff --git a/packages/discord-types/src/stores/GuildStore.d.ts b/packages/discord-types/src/stores/GuildStore.d.ts new file mode 100644 index 00000000..d1a3b9b3 --- /dev/null +++ b/packages/discord-types/src/stores/GuildStore.d.ts @@ -0,0 +1,8 @@ +import { Guild, FluxStore } from ".."; + +export class GuildStore extends FluxStore { + getGuild(guildId: string): Guild; + getGuildCount(): number; + getGuilds(): Record<string, Guild>; + getGuildIds(): string[]; +} diff --git a/packages/discord-types/src/stores/MessageStore.d.ts b/packages/discord-types/src/stores/MessageStore.d.ts new file mode 100644 index 00000000..d4823fc8 --- /dev/null +++ b/packages/discord-types/src/stores/MessageStore.d.ts @@ -0,0 +1,13 @@ +import { MessageJSON, FluxStore, Message } from ".."; + +export class MessageStore extends FluxStore { + getMessage(channelId: string, messageId: string): Message; + /** @returns This return object is fucking huge; I'll type it later. */ + getMessages(channelId: string): unknown; + getRawMessages(channelId: string): Record<string | number, MessageJSON>; + hasCurrentUserSentMessage(channelId: string): boolean; + hasPresent(channelId: string): boolean; + isLoadingMessages(channelId: string): boolean; + jumpedMessageId(channelId: string): string | undefined; + whenReady(channelId: string, callback: () => void): void; +} diff --git a/packages/discord-types/src/stores/RelationshipStore.d.ts b/packages/discord-types/src/stores/RelationshipStore.d.ts new file mode 100644 index 00000000..5d1a08af --- /dev/null +++ b/packages/discord-types/src/stores/RelationshipStore.d.ts @@ -0,0 +1,21 @@ +import { FluxStore } from ".."; + +export class RelationshipStore extends FluxStore { + getFriendIDs(): string[]; + getIgnoredIDs(): string[]; + getBlockedIDs(): string[]; + + getPendingCount(): number; + getRelationshipCount(): number; + + /** Related to friend nicknames. */ + getNickname(userId: string): string; + /** @returns Enum value from constants.RelationshipTypes */ + getRelationshipType(userId: string): number; + isFriend(userId: string): boolean; + isBlocked(userId: string): boolean; + isIgnored(userId: string): boolean; + getSince(userId: string): string; + + getMutableRelationships(): Map<string, number>; +} diff --git a/packages/discord-types/src/stores/SelectedChannelStore.d.ts b/packages/discord-types/src/stores/SelectedChannelStore.d.ts new file mode 100644 index 00000000..13ac98ac --- /dev/null +++ b/packages/discord-types/src/stores/SelectedChannelStore.d.ts @@ -0,0 +1,14 @@ +import { FluxStore } from ".."; + +export class SelectedChannelStore extends FluxStore { + getChannelId(guildId?: string | null): string; + getVoiceChannelId(): string | undefined; + getCurrentlySelectedChannelId(guildId?: string): string | undefined; + getMostRecentSelectedTextChannelId(guildId: string): string | undefined; + getLastSelectedChannelId(guildId?: string): string; + // yes this returns a string + getLastSelectedChannels(guildId?: string): string; + + /** If you follow an announcement channel, this will return whichever channel you chose as destination */ + getLastChannelFollowingDestination(): { guildId?: string; channelId?: string; } | undefined; +} diff --git a/packages/discord-types/src/stores/SelectedGuildStore.d.ts b/packages/discord-types/src/stores/SelectedGuildStore.d.ts new file mode 100644 index 00000000..0ee9c207 --- /dev/null +++ b/packages/discord-types/src/stores/SelectedGuildStore.d.ts @@ -0,0 +1,14 @@ +import { FluxStore } from ".."; + +export interface SelectedGuildState { + selectedGuildTimestampMillis: Record<string | number, number>; + selectedGuildId: string | null; + lastSelectedGuildId: string | null; +} + +export class SelectedGuildStore extends FluxStore { + getGuildId(): string | null; + getLastSelectedGuildId(): string | null; + getLastSelectedTimestamp(guildId: string): number | null; + getState(): SelectedGuildState | undefined; +} diff --git a/packages/discord-types/src/stores/ThemeStore.d.ts b/packages/discord-types/src/stores/ThemeStore.d.ts new file mode 100644 index 00000000..2900f7f6 --- /dev/null +++ b/packages/discord-types/src/stores/ThemeStore.d.ts @@ -0,0 +1,18 @@ +import { FluxStore } from ".."; + +export type ThemePreference = "dark" | "light" | "unknown"; +export type SystemTheme = "dark" | "light"; +export type Theme = "light" | "dark" | "darker" | "midnight"; + +export interface ThemeState { + theme: Theme; + status: 0 | 1; + preferences: Record<ThemePreference, Theme>; +} +export class ThemeStore extends FluxStore { + get theme(): Theme; + get darkSidebar(): boolean; + get systemTheme(): SystemTheme; + themePreferenceForSystemTheme(preference: ThemePreference): Theme; + getState(): ThemeState; +} diff --git a/packages/discord-types/src/stores/UserStore.d.ts b/packages/discord-types/src/stores/UserStore.d.ts new file mode 100644 index 00000000..323a1df0 --- /dev/null +++ b/packages/discord-types/src/stores/UserStore.d.ts @@ -0,0 +1,10 @@ +import { FluxStore, User } from ".."; + +export class UserStore extends FluxStore { + filter(filter: (user: User) => boolean, sort?: boolean): Record<string, User>; + findByTag(username: string, discriminator: string): User; + forEach(action: (user: User) => void): void; + getCurrentUser(): User; + getUser(userId: string): User; + getUsers(): Record<string, User>; +} diff --git a/packages/discord-types/src/stores/WindowStore.d.ts b/packages/discord-types/src/stores/WindowStore.d.ts new file mode 100644 index 00000000..53a40e96 --- /dev/null +++ b/packages/discord-types/src/stores/WindowStore.d.ts @@ -0,0 +1,7 @@ +import { FluxStore } from ".."; + +export class WindowStore extends FluxStore { + isElementFullScreen(): boolean; + isFocused(): boolean; + windowSize(): Record<"width" | "height", number>; +} diff --git a/packages/discord-types/src/stores/index.d.ts b/packages/discord-types/src/stores/index.d.ts new file mode 100644 index 00000000..b6254844 --- /dev/null +++ b/packages/discord-types/src/stores/index.d.ts @@ -0,0 +1,32 @@ +// please keep in alphabetical order +export * from "./ChannelStore"; +export * from "./DraftStore"; +export * from "./EmojiStore"; +export * from "./FluxStore"; +export * from "./GuildMemberStore"; +export * from "./GuildRoleStore"; +export * from "./GuildStore"; +export * from "./MessageStore"; +export * from "./RelationshipStore"; +export * from "./SelectedChannelStore"; +export * from "./SelectedGuildStore"; +export * from "./ThemeStore"; +export * from "./UserStore"; +export * from "./WindowStore"; + +/** + * React hook that returns stateful data for one or more stores + * You might need a custom comparator (4th argument) if your store data is an object + * @param stores The stores to listen to + * @param mapper A function that returns the data you need + * @param dependencies An array of reactive values which the hook depends on. Use this if your mapper or equality function depends on the value of another hook + * @param isEqual A custom comparator for the data returned by mapper + * + * @example const user = useStateFromStores([UserStore], () => UserStore.getCurrentUser(), null, (old, current) => old.id === current.id); + */ +export type useStateFromStores = <T>( + stores: any[], + mapper: () => T, + dependencies?: any, + isEqual?: (old: T, newer: T) => boolean +) => T; diff --git a/src/webpack/common/types/utils.d.ts b/packages/discord-types/src/utils.d.ts similarity index 92% rename from src/webpack/common/types/utils.d.ts rename to packages/discord-types/src/utils.d.ts index cfea5d76..77b6f88b 100644 --- a/src/webpack/common/types/utils.d.ts +++ b/packages/discord-types/src/utils.d.ts @@ -1,22 +1,4 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2023 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -import { Channel, Guild, GuildMember, Message, User } from "discord-types/general"; +import { Channel, Guild, GuildMember, Message, User } from "."; import type { ReactNode } from "react"; import { LiteralUnion } from "type-fest"; @@ -335,3 +317,19 @@ export interface DateUtils { dateFormat(date: Date, format: string): string; diffAsUnits(start: Date, end: Date, stopAtOneSecond?: boolean): Record<"days" | "hours" | "minutes" | "seconds", number>; } + +export interface CommandOptions { + type: number; + name: string; + description: string; + required?: boolean; + choices?: { + name: string; + values: string | number; + }[]; + options?: CommandOptions[]; + channel_types?: number[]; + min_value?: number; + max_value?: number; + autocomplete?: boolean; +} diff --git a/src/webpack/wreq.d.ts b/packages/discord-types/webpack/index.d.ts similarity index 90% rename from src/webpack/wreq.d.ts rename to packages/discord-types/webpack/index.d.ts index 2b356f9d..4a0011e8 100644 --- a/src/webpack/wreq.d.ts +++ b/packages/discord-types/webpack/index.d.ts @@ -1,11 +1,9 @@ /* - * Vencord, a Discord client mod + * @vencord/discord-types * Copyright (c) 2024 Vendicated, Nuckyz and contributors - * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-License-Identifier: LGPL-3.0-or-later */ -import { SYM_ORIGINAL_FACTORY, SYM_PATCHED_BY, SYM_PATCHED_SOURCE } from "./patchWebpack"; - export type ModuleExports = any; export type Module = { @@ -215,24 +213,3 @@ export type WebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & { /** rspack unique id */ ruid: string; }; - -// Utility section for Vencord - -export type AnyWebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & Partial<Omit<WebpackRequire, "m">> & { - /** The module factories, where all modules that have been loaded are stored (pre-loaded or loaded by lazy chunks) */ - m: Record<PropertyKey, AnyModuleFactory>; -}; - -/** exports can be anything, however initially it is always an empty object */ -export type AnyModuleFactory = ((this: ModuleExports, module: Module, exports: ModuleExports, require: AnyWebpackRequire) => void) & { - [SYM_PATCHED_SOURCE]?: string; - [SYM_PATCHED_BY]?: Set<string>; -}; - -export type PatchedModuleFactory = AnyModuleFactory & { - [SYM_ORIGINAL_FACTORY]: AnyModuleFactory; - [SYM_PATCHED_SOURCE]?: string; - [SYM_PATCHED_BY]?: Set<string>; -}; - -export type MaybePatchedModuleFactory = PatchedModuleFactory | AnyModuleFactory; diff --git a/packages/vencord-types/package.json b/packages/vencord-types/package.json index b3bbe315..64586919 100644 --- a/packages/vencord-types/package.json +++ b/packages/vencord-types/package.json @@ -21,7 +21,6 @@ "@types/node": "^22.13.4", "@types/react": "18.3.1", "@types/react-dom": "18.3.1", - "discord-types": "^1.3.26", "standalone-electron-types": "^34.2.0", "type-fest": "^4.35.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2e493972..cde57a1f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -65,12 +65,12 @@ importers: '@types/yazl': specifier: ^2.4.5 version: 2.4.6 + '@vencord/discord-types': + specifier: link:packages/discord-types + version: link:packages/discord-types diff: specifier: ^7.0.0 version: 7.0.0 - discord-types: - specifier: ^1.3.26 - version: 1.3.26 esbuild: specifier: ^0.25.1 version: 0.25.1 @@ -141,6 +141,18 @@ importers: specifier: ^0.3.5 version: 0.3.5 + packages/discord-types: + dependencies: + '@types/react': + specifier: ^19.0.10 + version: 19.0.12 + moment: + specifier: ^2.22.2 + version: 2.30.1 + type-fest: + specifier: ^4.41.0 + version: 4.41.0 + packages/vencord-types: dependencies: '@types/lodash': @@ -155,9 +167,6 @@ importers: '@types/react-dom': specifier: 18.3.1 version: 18.3.1 - discord-types: - specifier: ^1.3.26 - version: 1.3.26 standalone-electron-types: specifier: ^34.2.0 version: 34.2.0 @@ -522,9 +531,6 @@ packages: peerDependencies: '@types/react': ^19.0.0 - '@types/react@17.0.2': - resolution: {integrity: sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==} - '@types/react@18.3.1': resolution: {integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==} @@ -956,9 +962,6 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - discord-types@1.3.26: - resolution: {integrity: sha512-ToG51AOCH+JTQf7b+8vuYQe5Iqwz7nZ7StpECAZ/VZcI1ZhQk13pvt9KkRTfRv1xNvwJ2qib4e3+RifQlo8VPQ==} - doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -2328,6 +2331,10 @@ packages: resolution: {integrity: sha512-2dBz5D5ycHIoliLYLi0Q2V7KRaDlH0uWIvmk7TYlAg5slqwiPv1ezJdZm1QEM0xgk29oYWMCbIG7E6gHpvChlg==} engines: {node: '>=16'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -2764,11 +2771,6 @@ snapshots: dependencies: '@types/react': 19.0.12 - '@types/react@17.0.2': - dependencies: - '@types/prop-types': 15.7.14 - csstype: 3.1.3 - '@types/react@18.3.1': dependencies: '@types/prop-types': 15.7.14 @@ -3255,11 +3257,6 @@ snapshots: dependencies: path-type: 4.0.0 - discord-types@1.3.26: - dependencies: - '@types/react': 17.0.2 - moment: 2.30.1 - doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -4923,6 +4920,8 @@ snapshots: type-fest@4.38.0: {} + type-fest@4.41.0: {} + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 diff --git a/scripts/build/build.mjs b/scripts/build/build.mjs index 0ee24a31..db0a1ce0 100755 --- a/scripts/build/build.mjs +++ b/scripts/build/build.mjs @@ -51,7 +51,7 @@ const nodeCommonOpts = { format: "cjs", platform: "node", target: ["esnext"], - // @ts-ignore this is never undefined + // @ts-expect-error this is never undefined external: ["electron", "original-fs", "~pluginNatives", ...commonOpts.external] }; diff --git a/scripts/build/common.mjs b/scripts/build/common.mjs index 5c1732aa..516f6a1b 100644 --- a/scripts/build/common.mjs +++ b/scripts/build/common.mjs @@ -363,6 +363,6 @@ export const commonRendererPlugins = [ banImportPlugin(/^react$/, "Cannot import from react. React and hooks should be imported from @webpack/common"), banImportPlugin(/^electron(\/.*)?$/, "Cannot import electron in browser code. You need to use a native.ts file"), banImportPlugin(/^ts-pattern$/, "Cannot import from ts-pattern. match and P should be imported from @webpack/common"), - // @ts-ignore this is never undefined + // @ts-expect-error this is never undefined ...commonOpts.plugins ]; diff --git a/src/api/ChatButtons.tsx b/src/api/ChatButtons.tsx index 6f4285ff..1cacd06b 100644 --- a/src/api/ChatButtons.tsx +++ b/src/api/ChatButtons.tsx @@ -8,9 +8,9 @@ import "./ChatButton.css"; import ErrorBoundary from "@components/ErrorBoundary"; import { Logger } from "@utils/Logger"; +import { Channel } from "@vencord/discord-types"; import { waitFor } from "@webpack"; import { Button, ButtonWrapperClasses, Tooltip } from "@webpack/common"; -import { Channel } from "discord-types/general"; import { HTMLProps, JSX, MouseEventHandler, ReactNode } from "react"; let ChannelTextAreaClasses: Record<"button" | "buttonContainer", string>; diff --git a/src/api/Commands/commandHelpers.ts b/src/api/Commands/commandHelpers.ts index ac1dafc9..8ec23135 100644 --- a/src/api/Commands/commandHelpers.ts +++ b/src/api/Commands/commandHelpers.ts @@ -17,13 +17,11 @@ */ import { mergeDefaults } from "@utils/mergeDefaults"; +import { CommandArgument, Message } from "@vencord/discord-types"; import { findByCodeLazy } from "@webpack"; import { MessageActions, SnowflakeUtils } from "@webpack/common"; -import { Message } from "discord-types/general"; import type { PartialDeep } from "type-fest"; -import { Argument } from "./types"; - const createBotMessage = findByCodeLazy('username:"Clyde"'); export function generateId() { @@ -51,8 +49,8 @@ export function sendBotMessage(channelId: string, message: PartialDeep<Message>) * @param fallbackValue Fallback value in case this option wasn't passed * @returns Value */ -export function findOption<T>(args: Argument[], name: string): T & {} | undefined; -export function findOption<T>(args: Argument[], name: string, fallbackValue: T): T & {}; -export function findOption(args: Argument[], name: string, fallbackValue?: any) { +export function findOption<T>(args: CommandArgument[], name: string): T & {} | undefined; +export function findOption<T>(args: CommandArgument[], name: string, fallbackValue: T): T & {}; +export function findOption(args: CommandArgument[], name: string, fallbackValue?: any) { return (args.find(a => a.name === name)?.value ?? fallbackValue) as any; } diff --git a/src/api/Commands/index.ts b/src/api/Commands/index.ts index af6a6fdf..231b3daf 100644 --- a/src/api/Commands/index.ts +++ b/src/api/Commands/index.ts @@ -18,38 +18,39 @@ import { Logger } from "@utils/Logger"; import { makeCodeblock } from "@utils/text"; +import { CommandArgument, CommandContext, CommandOption } from "@vencord/discord-types"; import { sendBotMessage } from "./commandHelpers"; -import { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType, Argument, Command, CommandContext, Option } from "./types"; +import { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType, VencordCommand } from "./types"; export * from "./commandHelpers"; export * from "./types"; -export let BUILT_IN: Command[]; -export const commands = {} as Record<string, Command>; +export let BUILT_IN: VencordCommand[]; +export const commands = {} as Record<string, VencordCommand>; // hack for plugins being evaluated before we can grab these from webpack -const OptPlaceholder = Symbol("OptionalMessageOption") as any as Option; -const ReqPlaceholder = Symbol("RequiredMessageOption") as any as Option; +const OptPlaceholder = Symbol("OptionalMessageOption") as any as CommandOption; +const ReqPlaceholder = Symbol("RequiredMessageOption") as any as CommandOption; /** * Optional message option named "message" you can use in commands. * Used in "tableflip" or "shrug" * @see {@link RequiredMessageOption} */ -export let OptionalMessageOption: Option = OptPlaceholder; +export let OptionalMessageOption: CommandOption = OptPlaceholder; /** * Required message option named "message" you can use in commands. * Used in "me" * @see {@link OptionalMessageOption} */ -export let RequiredMessageOption: Option = ReqPlaceholder; +export let RequiredMessageOption: CommandOption = ReqPlaceholder; // Discord's command list has random gaps for some reason, which can cause issues while rendering the commands // Add this offset to every added command to keep them unique let commandIdOffset: number; -export const _init = function (cmds: Command[]) { +export const _init = function (cmds: VencordCommand[]) { try { BUILT_IN = cmds; OptionalMessageOption = cmds.find(c => (c.untranslatedName || c.displayName) === "shrug")!.options![0]; @@ -61,7 +62,7 @@ export const _init = function (cmds: Command[]) { return cmds; } as never; -export const _handleCommand = function (cmd: Command, args: Argument[], ctx: CommandContext) { +export const _handleCommand = function (cmd: VencordCommand, args: CommandArgument[], ctx: CommandContext) { if (!cmd.isVencordCommand) return cmd.execute(args, ctx); @@ -92,7 +93,7 @@ export const _handleCommand = function (cmd: Command, args: Argument[], ctx: Com * Prepare a Command Option for Discord by filling missing fields * @param opt */ -export function prepareOption<O extends Option | Command>(opt: O): O { +export function prepareOption<O extends CommandOption | VencordCommand>(opt: O): O { opt.displayName ||= opt.name; opt.displayDescription ||= opt.description; opt.options?.forEach((opt, i, opts) => { @@ -109,7 +110,7 @@ export function prepareOption<O extends Option | Command>(opt: O): O { // Yes, Discord registers individual commands for each subcommand // TODO: This probably doesn't support nested subcommands. If that is ever needed, // investigate -function registerSubCommands(cmd: Command, plugin: string) { +function registerSubCommands(cmd: VencordCommand, plugin: string) { cmd.options?.forEach(o => { if (o.type !== ApplicationCommandOptionType.SUB_COMMAND) throw new Error("When specifying sub-command options, all options must be sub-commands."); @@ -132,7 +133,7 @@ function registerSubCommands(cmd: Command, plugin: string) { }); } -export function registerCommand<C extends Command>(command: C, plugin: string) { +export function registerCommand<C extends VencordCommand>(command: C, plugin: string) { if (!BUILT_IN) { console.warn( "[CommandsAPI]", diff --git a/src/api/Commands/types.ts b/src/api/Commands/types.ts index 70b73775..c5ecb35e 100644 --- a/src/api/Commands/types.ts +++ b/src/api/Commands/types.ts @@ -1,106 +1,12 @@ /* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ + * Vencord, a Discord client mod + * Copyright (c) 2025 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ -import { Channel, Guild } from "discord-types/general"; -import { Promisable } from "type-fest"; +import { Command } from "@vencord/discord-types"; +export { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType } from "@vencord/discord-types/enums"; -export interface CommandContext { - channel: Channel; - guild?: Guild; -} - -export const enum ApplicationCommandOptionType { - SUB_COMMAND = 1, - SUB_COMMAND_GROUP = 2, - STRING = 3, - INTEGER = 4, - BOOLEAN = 5, - USER = 6, - CHANNEL = 7, - ROLE = 8, - MENTIONABLE = 9, - NUMBER = 10, - ATTACHMENT = 11, -} - -export const enum ApplicationCommandInputType { - BUILT_IN = 0, - BUILT_IN_TEXT = 1, - BUILT_IN_INTEGRATION = 2, - BOT = 3, - PLACEHOLDER = 4, -} - -export interface Option { - name: string; - displayName?: string; - type: ApplicationCommandOptionType; - description: string; - displayDescription?: string; - required?: boolean; - options?: Option[]; - choices?: Array<ChoicesOption>; -} - -export interface ChoicesOption { - label: string; - value: string; - name: string; - displayName?: string; -} - -export const enum ApplicationCommandType { - CHAT_INPUT = 1, - USER = 2, - MESSAGE = 3, -} - -export interface CommandReturnValue { - content: string; - /** TODO: implement */ - cancel?: boolean; -} - -export interface Argument { - type: ApplicationCommandOptionType; - name: string; - value: string; - focused: undefined; - options: Argument[]; -} - -export interface Command { - id?: string; - applicationId?: string; - type?: ApplicationCommandType; - inputType?: ApplicationCommandInputType; - plugin?: string; +export interface VencordCommand extends Command { isVencordCommand?: boolean; - - name: string; - untranslatedName?: string; - displayName?: string; - description: string; - untranslatedDescription?: string; - displayDescription?: string; - - options?: Option[]; - predicate?(ctx: CommandContext): boolean; - - execute(args: Argument[], ctx: CommandContext): Promisable<void | CommandReturnValue>; } diff --git a/src/api/DataStore/index.ts b/src/api/DataStore/index.ts index 47ae39db..80ebb065 100644 --- a/src/api/DataStore/index.ts +++ b/src/api/DataStore/index.ts @@ -22,9 +22,9 @@ export function promisifyRequest<T = undefined>( request: IDBRequest<T> | IDBTransaction, ): Promise<T> { return new Promise<T>((resolve, reject) => { - // @ts-ignore - file size hacks + // @ts-expect-error - file size hacks request.oncomplete = request.onsuccess = () => resolve(request.result); - // @ts-ignore - file size hacks + // @ts-expect-error - file size hacks request.onabort = request.onerror = () => reject(request.error); }); } diff --git a/src/api/MemberListDecorators.tsx b/src/api/MemberListDecorators.tsx index ada60776..2367e4cf 100644 --- a/src/api/MemberListDecorators.tsx +++ b/src/api/MemberListDecorators.tsx @@ -17,7 +17,7 @@ */ import ErrorBoundary from "@components/ErrorBoundary"; -import { Channel, User } from "discord-types/general/index.js"; +import { Channel, User } from "@vencord/discord-types"; import { JSX } from "react"; interface DecoratorProps { diff --git a/src/api/MessageDecorations.tsx b/src/api/MessageDecorations.tsx index 1b94c18d..8cf492c7 100644 --- a/src/api/MessageDecorations.tsx +++ b/src/api/MessageDecorations.tsx @@ -17,7 +17,7 @@ */ import ErrorBoundary from "@components/ErrorBoundary"; -import { Channel, Message } from "discord-types/general/index.js"; +import { Channel, Message } from "@vencord/discord-types"; import { JSX } from "react"; export interface MessageDecorationProps { diff --git a/src/api/MessageEvents.ts b/src/api/MessageEvents.ts index 1b55ff34..8b1d9e78 100644 --- a/src/api/MessageEvents.ts +++ b/src/api/MessageEvents.ts @@ -17,9 +17,8 @@ */ import { Logger } from "@utils/Logger"; +import type { Channel, CustomEmoji, Message } from "@vencord/discord-types"; import { MessageStore } from "@webpack/common"; -import { CustomEmoji } from "@webpack/types"; -import type { Channel, Message } from "discord-types/general"; import type { Promisable } from "type-fest"; const MessageEventsLogger = new Logger("MessageEvents", "#e5c890"); diff --git a/src/api/MessagePopover.tsx b/src/api/MessagePopover.tsx index 71787954..c7b2a090 100644 --- a/src/api/MessagePopover.tsx +++ b/src/api/MessagePopover.tsx @@ -18,7 +18,7 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Logger } from "@utils/Logger"; -import { Channel, Message } from "discord-types/general"; +import { Channel, Message } from "@vencord/discord-types"; import type { ComponentType, MouseEventHandler } from "react"; const logger = new Logger("MessagePopover"); diff --git a/src/api/MessageUpdater.ts b/src/api/MessageUpdater.ts index 284a2088..7c4b3d5c 100644 --- a/src/api/MessageUpdater.ts +++ b/src/api/MessageUpdater.ts @@ -4,9 +4,8 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +import { FluxStore, Message } from "@vencord/discord-types"; import { MessageCache, MessageStore } from "@webpack/common"; -import { FluxStore } from "@webpack/types"; -import { Message } from "discord-types/general"; /** * Update and re-render a message diff --git a/src/api/Settings.ts b/src/api/Settings.ts index 08d2f8ca..5c8965bf 100644 --- a/src/api/Settings.ts +++ b/src/api/Settings.ts @@ -268,7 +268,7 @@ type ResolveUseSettings<T extends object> = { [Key in keyof T]: Key extends string ? T[Key] extends Record<string, unknown> - // @ts-ignore "Type instantiation is excessively deep and possibly infinite" + // @ts-expect-error "Type instantiation is excessively deep and possibly infinite" ? UseSettings<T[Key]> extends string ? `${Key}.${UseSettings<T[Key]>}` : never : Key : never; diff --git a/src/components/DonateButton.tsx b/src/components/DonateButton.tsx index ee2f3ed3..92af9831 100644 --- a/src/components/DonateButton.tsx +++ b/src/components/DonateButton.tsx @@ -16,8 +16,8 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import { ButtonProps } from "@vencord/discord-types"; import { Button } from "@webpack/common"; -import { ButtonProps } from "@webpack/types"; import { Heart } from "./Heart"; diff --git a/src/components/PluginSettings/ContributorModal.tsx b/src/components/PluginSettings/ContributorModal.tsx index fe0e987c..378ee34c 100644 --- a/src/components/PluginSettings/ContributorModal.tsx +++ b/src/components/PluginSettings/ContributorModal.tsx @@ -14,8 +14,8 @@ import { DevsById } from "@utils/constants"; import { fetchUserProfile } from "@utils/discord"; import { classes, pluralise } from "@utils/misc"; import { ModalContent, ModalRoot, openModal } from "@utils/modal"; +import { User } from "@vencord/discord-types"; import { Forms, showToast, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common"; -import { User } from "discord-types/general"; import Plugins from "~plugins"; diff --git a/src/components/PluginSettings/PluginModal.tsx b/src/components/PluginSettings/PluginModal.tsx index 17ab2662..29ce90c9 100644 --- a/src/components/PluginSettings/PluginModal.tsx +++ b/src/components/PluginSettings/PluginModal.tsx @@ -29,9 +29,9 @@ import { Margins } from "@utils/margins"; import { classes, isObjectEmpty } from "@utils/misc"; import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal"; import { OptionType, Plugin } from "@utils/types"; +import { User } from "@vencord/discord-types"; import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; import { Button, Clickable, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "@webpack/common"; -import { User } from "discord-types/general"; import { Constructor } from "type-fest"; import { PluginMeta } from "~plugins"; diff --git a/src/debug/loadLazyChunks.ts b/src/debug/loadLazyChunks.ts index f8c71cae..fcb33d38 100644 --- a/src/debug/loadLazyChunks.ts +++ b/src/debug/loadLazyChunks.ts @@ -6,9 +6,10 @@ import { Logger } from "@utils/Logger"; import { canonicalizeMatch } from "@utils/patches"; +import { ModuleFactory } from "@vencord/discord-types/webpack"; import * as Webpack from "@webpack"; import { wreq } from "@webpack"; -import { AnyModuleFactory, ModuleFactory } from "@webpack/wreq.d"; +import { AnyModuleFactory } from "webpack"; export async function loadLazyChunks() { const LazyChunkLoaderLogger = new Logger("LazyChunkLoader"); diff --git a/src/debug/runReporter.ts b/src/debug/runReporter.ts index 4ee2d394..39071a0c 100644 --- a/src/debug/runReporter.ts +++ b/src/debug/runReporter.ts @@ -28,7 +28,7 @@ async function runReporter() { } }, "Vencord Reporter"); - // @ts-ignore + // @ts-expect-error Vencord.Webpack._initReporter = function () { // initReporter is called in the patched entry point of Discord // setImmediate to only start searching for lazy chunks after Discord initialized the app @@ -83,7 +83,6 @@ async function runReporter() { result = Webpack.mapMangledModule(code, mapper, includeBlacklistedExports); if (Object.keys(result).length !== Object.keys(mapper).length) throw new Error("Webpack Find Fail"); } else { - // @ts-ignore result = Webpack[method](...args); } diff --git a/src/main/patcher.ts b/src/main/patcher.ts index 60b169af..8868caa7 100644 --- a/src/main/patcher.ts +++ b/src/main/patcher.ts @@ -38,7 +38,7 @@ const asarPath = join(dirname(injectorPath), "..", asarName); const discordPkg = require(join(asarPath, "package.json")); require.main!.filename = join(asarPath, discordPkg.main); -// @ts-ignore Untyped method? Dies from cringe +// @ts-expect-error Untyped method? Dies from cringe app.setAppPath(asarPath); if (!IS_VANILLA) { diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx index b00df6b0..8011e331 100644 --- a/src/plugins/_api/badges/index.tsx +++ b/src/plugins/_api/badges/index.tsx @@ -30,8 +30,8 @@ import { Margins } from "@utils/margins"; import { shouldShowContributorBadge } from "@utils/misc"; import { closeModal, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal"; import definePlugin from "@utils/types"; +import { User } from "@vencord/discord-types"; import { Forms, Toasts, UserStore } from "@webpack/common"; -import { User } from "discord-types/general"; const CONTRIBUTOR_BADGE = "https://cdn.discordapp.com/emojis/1092089799109775453.png?size=64"; diff --git a/src/plugins/_core/noTrack.ts b/src/plugins/_core/noTrack.ts index 30920a06..ad1f255b 100644 --- a/src/plugins/_core/noTrack.ts +++ b/src/plugins/_core/noTrack.ts @@ -20,7 +20,7 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import { Logger } from "@utils/Logger"; import definePlugin, { OptionType, StartAt } from "@utils/types"; -import { WebpackRequire } from "@webpack/wreq.d"; +import { WebpackRequire } from "@vencord/discord-types/webpack"; const settings = definePluginSettings({ disableAnalytics: { diff --git a/src/plugins/_core/settings.tsx b/src/plugins/_core/settings.tsx index a9e34f78..0eb8e13c 100644 --- a/src/plugins/_core/settings.tsx +++ b/src/plugins/_core/settings.tsx @@ -213,7 +213,7 @@ export default definePlugin({ get chromiumVersion() { try { return VencordNative.native.getVersions().chrome - // @ts-ignore Typescript will add userAgentData IMMEDIATELY + // @ts-expect-error Typescript will add userAgentData IMMEDIATELY || navigator.userAgentData?.brands?.find(b => b.brand === "Chromium" || b.brand === "Google Chrome")?.version || null; } catch { // inb4 some stupid browser throws unsupported error for navigator.userAgentData, it's only in chromium diff --git a/src/plugins/_core/supportHelper.tsx b/src/plugins/_core/supportHelper.tsx index 825bbc20..956343f6 100644 --- a/src/plugins/_core/supportHelper.tsx +++ b/src/plugins/_core/supportHelper.tsx @@ -32,8 +32,8 @@ import { onlyOnce } from "@utils/onlyOnce"; import { makeCodeblock } from "@utils/text"; import definePlugin from "@utils/types"; import { checkForUpdates, isOutdated, update } from "@utils/updater"; +import { Channel } from "@vencord/discord-types"; import { Alerts, Button, Card, ChannelStore, Forms, GuildMemberStore, Parser, PermissionsBits, PermissionStore, RelationshipStore, showToast, Text, Toasts, UserStore } from "@webpack/common"; -import { Channel } from "discord-types/general"; import { JSX } from "react"; import gitHash from "~git-hash"; @@ -196,7 +196,6 @@ export default definePlugin({ } } - // @ts-ignore outdated type const roles = GuildMemberStore.getSelfMember(VENCORD_GUILD_ID)?.roles; if (!roles || TrustedRolesIds.some(id => roles.includes(id))) return; diff --git a/src/plugins/accountPanelServerProfile/index.tsx b/src/plugins/accountPanelServerProfile/index.tsx index f871b8ee..ce9f6b51 100644 --- a/src/plugins/accountPanelServerProfile/index.tsx +++ b/src/plugins/accountPanelServerProfile/index.tsx @@ -9,9 +9,9 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { getCurrentChannel } from "@utils/discord"; import definePlugin, { OptionType } from "@utils/types"; +import { User } from "@vencord/discord-types"; import { findComponentByCodeLazy } from "@webpack"; import { ContextMenuApi, Menu, useEffect, useRef } from "@webpack/common"; -import { User } from "discord-types/general"; interface UserProfileProps { popoutProps: Record<string, any>; diff --git a/src/plugins/biggerStreamPreview/index.tsx b/src/plugins/biggerStreamPreview/index.tsx index 92b6f57f..e77e3a02 100644 --- a/src/plugins/biggerStreamPreview/index.tsx +++ b/src/plugins/biggerStreamPreview/index.tsx @@ -21,8 +21,8 @@ import { ScreenshareIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; import { openImageModal } from "@utils/discord"; import definePlugin from "@utils/types"; +import { Channel, User } from "@vencord/discord-types"; import { Menu } from "@webpack/common"; -import { Channel, User } from "discord-types/general"; import { ApplicationStreamingStore, ApplicationStreamPreviewStore } from "./webpack/stores"; import { ApplicationStream, Stream } from "./webpack/types/stores"; diff --git a/src/plugins/biggerStreamPreview/webpack/types/stores.ts b/src/plugins/biggerStreamPreview/webpack/types/stores.ts index 0265986f..e11ede50 100644 --- a/src/plugins/biggerStreamPreview/webpack/types/stores.ts +++ b/src/plugins/biggerStreamPreview/webpack/types/stores.ts @@ -16,7 +16,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { FluxStore } from "@webpack/types"; +import { FluxStore } from "@vencord/discord-types"; export interface ApplicationStreamPreviewStore extends FluxStore { getIsPreviewLoading: (guildId: string | bigint | null, channelId: string | bigint, ownerId: string | bigint) => boolean; diff --git a/src/plugins/copyUserURLs/index.tsx b/src/plugins/copyUserURLs/index.tsx index 9e15cc82..744f7cca 100644 --- a/src/plugins/copyUserURLs/index.tsx +++ b/src/plugins/copyUserURLs/index.tsx @@ -21,8 +21,8 @@ import { LinkIcon } from "@components/Icons"; import { copyToClipboard } from "@utils/clipboard"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import type { Channel, User } from "@vencord/discord-types"; import { Menu } from "@webpack/common"; -import type { Channel, User } from "discord-types/general"; interface UserContextProps { channel: Channel; diff --git a/src/plugins/decor/lib/stores/UsersDecorationsStore.ts b/src/plugins/decor/lib/stores/UsersDecorationsStore.ts index f47ccbc5..588bbdf9 100644 --- a/src/plugins/decor/lib/stores/UsersDecorationsStore.ts +++ b/src/plugins/decor/lib/stores/UsersDecorationsStore.ts @@ -6,8 +6,8 @@ import { debounce } from "@shared/debounce"; import { proxyLazy } from "@utils/lazy"; +import { User } from "@vencord/discord-types"; import { useEffect, useState, zustandCreate } from "@webpack/common"; -import { User } from "discord-types/general"; import { AvatarDecoration } from "../../"; import { getUsersDecorations } from "../api"; diff --git a/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx b/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx index a3edc097..56c68410 100644 --- a/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx +++ b/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx @@ -11,9 +11,9 @@ import { Margins } from "@utils/margins"; import { classes, copyWithToast } from "@utils/misc"; import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal"; import { Queue } from "@utils/Queue"; +import { User } from "@vencord/discord-types"; import { findComponentByCodeLazy } from "@webpack"; import { Alerts, Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Parser, Text, Tooltip, useEffect, UserStore, UserUtils, useState } from "@webpack/common"; -import { User } from "discord-types/general"; import { Decoration, getPresets, Preset } from "../../lib/api"; import { GUILD_ID, INVITE_KEY } from "../../lib/constants"; diff --git a/src/plugins/expressionCloner/index.tsx b/src/plugins/expressionCloner/index.tsx index 6f84e7f7..60a95336 100644 --- a/src/plugins/expressionCloner/index.tsx +++ b/src/plugins/expressionCloner/index.tsx @@ -25,9 +25,9 @@ import { Logger } from "@utils/Logger"; import { Margins } from "@utils/margins"; import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal"; import definePlugin from "@utils/types"; +import { Guild } from "@vencord/discord-types"; import { findByCodeLazy, findStoreLazy } from "@webpack"; import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, IconUtils, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common"; -import { Guild } from "discord-types/general"; import { Promisable } from "type-fest"; const StickersStore = findStoreLazy("StickersStore"); diff --git a/src/plugins/fakeNitro/index.tsx b/src/plugins/fakeNitro/index.tsx index b3909595..380147fe 100644 --- a/src/plugins/fakeNitro/index.tsx +++ b/src/plugins/fakeNitro/index.tsx @@ -23,10 +23,9 @@ import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies"; import { getCurrentGuild, getEmojiURL } from "@utils/discord"; import { Logger } from "@utils/Logger"; import definePlugin, { OptionType, Patch } from "@utils/types"; +import type { Emoji, Message } from "@vencord/discord-types"; import { findByCodeLazy, findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack"; import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common"; -import type { Emoji } from "@webpack/types"; -import type { Message } from "discord-types/general"; import { applyPalette, GIFEncoder, quantize } from "gifenc"; import type { ReactElement, ReactNode } from "react"; @@ -813,7 +812,6 @@ export default definePlugin({ let isUsableTwitchSubEmote = false; if (e.managed && e.guildId) { - // @ts-ignore outdated type const myRoles = GuildMemberStore.getSelfMember(e.guildId)?.roles ?? []; isUsableTwitchSubEmote = e.roles.some(r => myRoles.includes(r)); } diff --git a/src/plugins/fakeProfileThemes/index.tsx b/src/plugins/fakeProfileThemes/index.tsx index 61ab1731..a84722c1 100644 --- a/src/plugins/fakeProfileThemes/index.tsx +++ b/src/plugins/fakeProfileThemes/index.tsx @@ -25,16 +25,12 @@ import { Devs } from "@utils/constants"; import { Margins } from "@utils/margins"; import { classes, copyWithToast } from "@utils/misc"; import definePlugin, { OptionType } from "@utils/types"; +import { User } from "@vencord/discord-types"; import { findComponentByCodeLazy } from "@webpack"; import { Button, ColorPicker, Flex, Forms, React, Text, UserProfileStore, UserStore, useState } from "@webpack/common"; -import { User } from "discord-types/general"; import { ReactElement } from "react"; import virtualMerge from "virtual-merge"; -interface UserProfile extends User { - themeColors?: Array<number>; -} - interface Colors { primary: number; accent: number; @@ -220,7 +216,7 @@ export default definePlugin({ </Forms.FormSection>); }, settings, - colorDecodeHook(user: UserProfile) { + colorDecodeHook(user: User) { if (user) { // don't replace colors if already set with nitro if (settings.store.nitroFirst && user.themeColors) return user; diff --git a/src/plugins/favEmojiFirst/index.ts b/src/plugins/favEmojiFirst/index.ts index ebb89f7e..e9a9bc58 100644 --- a/src/plugins/favEmojiFirst/index.ts +++ b/src/plugins/favEmojiFirst/index.ts @@ -18,8 +18,8 @@ import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import { Emoji } from "@vencord/discord-types"; import { EmojiStore } from "@webpack/common"; -import { Emoji } from "@webpack/types"; interface EmojiAutocompleteState { query?: { diff --git a/src/plugins/forceOwnerCrown/index.ts b/src/plugins/forceOwnerCrown/index.ts index bf115c64..f7e4b470 100644 --- a/src/plugins/forceOwnerCrown/index.ts +++ b/src/plugins/forceOwnerCrown/index.ts @@ -18,8 +18,8 @@ import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import { Channel, User } from "@vencord/discord-types"; import { GuildStore } from "@webpack/common"; -import { Channel, User } from "discord-types/general"; export default definePlugin({ name: "ForceOwnerCrown", diff --git a/src/plugins/fullSearchContext/index.tsx b/src/plugins/fullSearchContext/index.tsx index 7c0dbea6..d5b9c8a1 100644 --- a/src/plugins/fullSearchContext/index.tsx +++ b/src/plugins/fullSearchContext/index.tsx @@ -22,9 +22,9 @@ import { Devs } from "@utils/constants"; import { getIntlMessage } from "@utils/discord"; import { NoopComponent } from "@utils/react"; import definePlugin from "@utils/types"; +import { Message } from "@vencord/discord-types"; import { filters, findByCodeLazy, waitFor } from "@webpack"; import { ChannelStore, ContextMenuApi, UserStore } from "@webpack/common"; -import { Message } from "discord-types/general"; const useMessageMenu = findByCodeLazy(".MESSAGE,commandTargetId:"); diff --git a/src/plugins/greetStickerPicker/index.tsx b/src/plugins/greetStickerPicker/index.tsx index 3ab5fca4..b2454f9c 100644 --- a/src/plugins/greetStickerPicker/index.tsx +++ b/src/plugins/greetStickerPicker/index.tsx @@ -19,9 +19,9 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; +import { Channel, Message } from "@vencord/discord-types"; import { findLazy } from "@webpack"; import { ContextMenuApi, FluxDispatcher, Menu, MessageActions } from "@webpack/common"; -import { Channel, Message } from "discord-types/general"; interface Sticker { id: string; diff --git a/src/plugins/hideAttachments/index.tsx b/src/plugins/hideAttachments/index.tsx index fe9e6899..0198a3e1 100644 --- a/src/plugins/hideAttachments/index.tsx +++ b/src/plugins/hideAttachments/index.tsx @@ -25,8 +25,8 @@ import { ImageInvisible, ImageVisible } from "@components/Icons"; import { Devs } from "@utils/constants"; import { classes } from "@utils/misc"; import definePlugin from "@utils/types"; +import { MessageSnapshot } from "@vencord/discord-types"; import { ChannelStore } from "@webpack/common"; -import { MessageSnapshot } from "@webpack/types"; const KEY = "HideAttachments_HiddenIds"; @@ -56,7 +56,7 @@ export default definePlugin({ }], renderMessagePopoverButton(msg) { - // @ts-ignore - discord-types lags behind discord. + // @ts-expect-error - discord-types lags behind discord. const hasAttachmentsInShapshots = msg.messageSnapshots.some( (snapshot: MessageSnapshot) => snapshot?.message.attachments.length ); diff --git a/src/plugins/index.ts b/src/plugins/index.ts index 4a268868..8288935b 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -30,9 +30,9 @@ import { disableStyle, enableStyle } from "@api/Styles"; import { Logger } from "@utils/Logger"; import { canonicalizeFind, canonicalizeReplacement } from "@utils/patches"; import { Patch, Plugin, PluginDef, ReporterTestable, StartAt } from "@utils/types"; +import { FluxEvents } from "@vencord/discord-types"; import { FluxDispatcher } from "@webpack/common"; import { patches } from "@webpack/patcher"; -import { FluxEvents } from "@webpack/types"; import Plugins from "~plugins"; diff --git a/src/plugins/invisibleChat.desktop/index.tsx b/src/plugins/invisibleChat.desktop/index.tsx index ab124192..a19a4615 100644 --- a/src/plugins/invisibleChat.desktop/index.tsx +++ b/src/plugins/invisibleChat.desktop/index.tsx @@ -23,8 +23,8 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { getStegCloak } from "@utils/dependencies"; import definePlugin, { OptionType, ReporterTestable } from "@utils/types"; +import { Message } from "@vencord/discord-types"; import { ChannelStore, Constants, RestAPI, Tooltip } from "@webpack/common"; -import { Message } from "discord-types/general"; import { buildDecModal } from "./components/DecryptionModal"; import { buildEncModal } from "./components/EncryptionModal"; diff --git a/src/plugins/memberCount/index.tsx b/src/plugins/memberCount/index.tsx index ad7491cc..97f6f23c 100644 --- a/src/plugins/memberCount/index.tsx +++ b/src/plugins/memberCount/index.tsx @@ -23,8 +23,8 @@ import { classNameFactory } from "@api/Styles"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; +import { FluxStore } from "@vencord/discord-types"; import { findStoreLazy } from "@webpack"; -import { FluxStore } from "@webpack/types"; import { MemberCount } from "./MemberCount"; diff --git a/src/plugins/mentionAvatars/index.tsx b/src/plugins/mentionAvatars/index.tsx index 8f18567e..11316ef8 100644 --- a/src/plugins/mentionAvatars/index.tsx +++ b/src/plugins/mentionAvatars/index.tsx @@ -10,8 +10,8 @@ import { definePluginSettings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; +import { User } from "@vencord/discord-types"; import { GuildRoleStore, SelectedGuildStore, useState } from "@webpack/common"; -import { User } from "discord-types/general"; const settings = definePluginSettings({ showAtSymbol: { diff --git a/src/plugins/messageLatency/index.tsx b/src/plugins/messageLatency/index.tsx index 460b95a8..cd331b9d 100644 --- a/src/plugins/messageLatency/index.tsx +++ b/src/plugins/messageLatency/index.tsx @@ -9,9 +9,9 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { isNonNullish } from "@utils/guards"; import definePlugin, { OptionType } from "@utils/types"; +import { Message } from "@vencord/discord-types"; import { findComponentByCodeLazy } from "@webpack"; import { SnowflakeUtils, Tooltip } from "@webpack/common"; -import { Message } from "discord-types/general"; type FillValue = ("status-danger" | "status-warning" | "status-positive" | "text-muted"); type Fill = [FillValue, FillValue, FillValue]; diff --git a/src/plugins/messageLinkEmbeds/index.tsx b/src/plugins/messageLinkEmbeds/index.tsx index 1e4f68e0..663fa349 100644 --- a/src/plugins/messageLinkEmbeds/index.tsx +++ b/src/plugins/messageLinkEmbeds/index.tsx @@ -24,6 +24,7 @@ import { Devs } from "@utils/constants.js"; import { classes } from "@utils/misc"; import { Queue } from "@utils/Queue"; import definePlugin, { OptionType } from "@utils/types"; +import { Channel, Message } from "@vencord/discord-types"; import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; import { Button, @@ -39,7 +40,6 @@ import { Text, UserStore } from "@webpack/common"; -import { Channel, Message } from "discord-types/general"; import { JSX } from "react"; const messageCache = new Map<string, { @@ -217,7 +217,7 @@ function withEmbeddedBy(message: Message, embeddedBy: string[]) { return new Proxy(message, { get(_, prop) { if (prop === "vencordEmbeddedBy") return embeddedBy; - // @ts-ignore ts so bad + // @ts-expect-error ts so bad return Reflect.get(...arguments); } }); @@ -225,7 +225,7 @@ function withEmbeddedBy(message: Message, embeddedBy: string[]) { function MessageEmbedAccessory({ message }: { message: Message; }) { - // @ts-ignore + // @ts-expect-error const embeddedBy: string[] = message.vencordEmbeddedBy ?? []; const accessories = [] as (JSX.Element | null)[]; diff --git a/src/plugins/messageLogger/index.tsx b/src/plugins/messageLogger/index.tsx index 3c7aecae..0be4a0f5 100644 --- a/src/plugins/messageLogger/index.tsx +++ b/src/plugins/messageLogger/index.tsx @@ -28,9 +28,9 @@ import { getIntlMessage } from "@utils/discord"; import { Logger } from "@utils/Logger"; import { classes } from "@utils/misc"; import definePlugin, { OptionType } from "@utils/types"; +import { Message } from "@vencord/discord-types"; import { findByPropsLazy } from "@webpack"; import { ChannelStore, FluxDispatcher, Menu, MessageStore, Parser, SelectedChannelStore, Timestamp, UserStore, useStateFromStores } from "@webpack/common"; -import { Message } from "discord-types/general"; import overlayStyle from "./deleteStyleOverlay.css?managed"; import textStyle from "./deleteStyleText.css?managed"; diff --git a/src/plugins/messageTags/index.ts b/src/plugins/messageTags/index.ts index 49e88c42..90ce0ceb 100644 --- a/src/plugins/messageTags/index.ts +++ b/src/plugins/messageTags/index.ts @@ -92,7 +92,7 @@ export default definePlugin({ // TODO(OptionType.CUSTOM Related): Remove DataStore tags migration once enough time has passed const oldTags = await DataStore.get<Tag[]>(DATA_KEY); if (oldTags != null) { - // @ts-ignore + // @ts-expect-error settings.store.tagsList = Object.fromEntries(oldTags.map(oldTag => (delete oldTag.enabled, [oldTag.name, oldTag]))); await DataStore.del(DATA_KEY); } @@ -211,7 +211,7 @@ export default definePlugin({ description: Object.values(getTags()) .map(tag => `\`${tag.name}\`: ${tag.message.slice(0, 72).replaceAll("\\n", " ")}${tag.message.length > 72 ? "..." : ""}`) .join("\n") || `${EMOTE} Woops! There are no tags yet, use \`/tags create\` to create one!`, - // @ts-ignore + // @ts-expect-error color: 0xd77f7f, type: "rich", } diff --git a/src/plugins/mutualGroupDMs/index.tsx b/src/plugins/mutualGroupDMs/index.tsx index b90eb7ed..8d81e43d 100644 --- a/src/plugins/mutualGroupDMs/index.tsx +++ b/src/plugins/mutualGroupDMs/index.tsx @@ -23,9 +23,9 @@ import { Devs } from "@utils/constants"; import { isNonNullish } from "@utils/guards"; import { Logger } from "@utils/Logger"; import definePlugin from "@utils/types"; +import { Channel, User } from "@vencord/discord-types"; import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; import { Avatar, ChannelStore, Clickable, IconUtils, RelationshipStore, ScrollerThin, Text, useMemo, UserStore } from "@webpack/common"; -import { Channel, User } from "discord-types/general"; import { JSX } from "react"; const SelectedChannelActionCreators = findByPropsLazy("selectPrivateChannel"); diff --git a/src/plugins/newGuildSettings/index.tsx b/src/plugins/newGuildSettings/index.tsx index f8a517fa..fba0c1c3 100644 --- a/src/plugins/newGuildSettings/index.tsx +++ b/src/plugins/newGuildSettings/index.tsx @@ -24,9 +24,9 @@ import { definePluginSettings } from "@api/Settings"; import { CogWheel } from "@components/Icons"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; +import { Guild } from "@vencord/discord-types"; import { findByCodeLazy, findByPropsLazy, mapMangledModuleLazy } from "@webpack"; import { Menu } from "@webpack/common"; -import { Guild } from "discord-types/general"; const { updateGuildNotificationSettings } = findByPropsLazy("updateGuildNotificationSettings"); const { toggleShowAllChannels } = mapMangledModuleLazy(".onboardExistingMember(", { diff --git a/src/plugins/noBlockedMessages/index.ts b/src/plugins/noBlockedMessages/index.ts index 973e3796..1a4d691f 100644 --- a/src/plugins/noBlockedMessages/index.ts +++ b/src/plugins/noBlockedMessages/index.ts @@ -21,8 +21,8 @@ import { Devs } from "@utils/constants"; import { runtimeHashMessageKey } from "@utils/intlHash"; import { Logger } from "@utils/Logger"; import definePlugin, { OptionType } from "@utils/types"; +import { Message } from "@vencord/discord-types"; import { i18n, RelationshipStore } from "@webpack/common"; -import { Message } from "discord-types/general"; interface MessageDeleteProps { // Internal intl message for BLOCKED_MESSAGE_COUNT diff --git a/src/plugins/noReplyMention/index.tsx b/src/plugins/noReplyMention/index.tsx index 16b3a3e0..b4de573f 100644 --- a/src/plugins/noReplyMention/index.tsx +++ b/src/plugins/noReplyMention/index.tsx @@ -19,7 +19,7 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; -import type { Message } from "discord-types/general"; +import type { Message } from "@vencord/discord-types"; const settings = definePluginSettings({ userList: { diff --git a/src/plugins/onePingPerDM/index.ts b/src/plugins/onePingPerDM/index.ts index e9cde652..0ef81781 100644 --- a/src/plugins/onePingPerDM/index.ts +++ b/src/plugins/onePingPerDM/index.ts @@ -7,8 +7,8 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; +import { MessageJSON } from "@vencord/discord-types"; import { ChannelStore, ReadStateStore, UserStore } from "@webpack/common"; -import { MessageJSON } from "discord-types/general"; const enum ChannelType { DM = 1, diff --git a/src/plugins/pauseInvitesForever/index.tsx b/src/plugins/pauseInvitesForever/index.tsx index 577d8bd7..7ffba7c5 100644 --- a/src/plugins/pauseInvitesForever/index.tsx +++ b/src/plugins/pauseInvitesForever/index.tsx @@ -27,7 +27,6 @@ function showDisableInvites(guildId: string) { if (!guild) return false; return ( - // @ts-expect-error !hasGuildFeature(guild, "INVITES_DISABLED") && PermissionStore.getGuildPermissionProps(guild).canManageRoles ); diff --git a/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx b/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx index 46ddb146..28beabe1 100644 --- a/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx +++ b/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx @@ -22,10 +22,9 @@ import { InfoIcon, OwnerCrownIcon } from "@components/Icons"; import { copyToClipboard } from "@utils/clipboard"; import { getIntlMessage, getUniqueUsername } from "@utils/discord"; import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal"; +import { Guild, Role, UnicodeEmoji, User } from "@vencord/discord-types"; import { findByCodeLazy } from "@webpack"; import { ContextMenuApi, FluxDispatcher, GuildMemberStore, GuildRoleStore, i18n, Menu, PermissionsBits, ScrollerThin, Text, Tooltip, useEffect, useMemo, UserStore, useState, useStateFromStores } from "@webpack/common"; -import { UnicodeEmoji } from "@webpack/types"; -import type { Guild, Role, User } from "discord-types/general"; import { settings } from ".."; import { cl, getGuildPermissionSpecMap } from "../utils"; diff --git a/src/plugins/permissionsViewer/components/UserPermissions.tsx b/src/plugins/permissionsViewer/components/UserPermissions.tsx index 85b1d418..5185abb3 100644 --- a/src/plugins/permissionsViewer/components/UserPermissions.tsx +++ b/src/plugins/permissionsViewer/components/UserPermissions.tsx @@ -19,9 +19,9 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { getIntlMessage } from "@utils/discord"; import { classes } from "@utils/misc"; +import type { Guild, GuildMember } from "@vencord/discord-types"; import { filters, findBulk, proxyLazyWebpack } from "@webpack"; import { PermissionsBits, Text, Tooltip, useMemo, UserStore } from "@webpack/common"; -import type { Guild, GuildMember } from "discord-types/general"; import { PermissionsSortOrder, settings } from ".."; import { cl, getGuildPermissionSpecMap, getSortedRoles, sortUserRoles } from "../utils"; diff --git a/src/plugins/permissionsViewer/index.tsx b/src/plugins/permissionsViewer/index.tsx index cc942f09..ed2471fb 100644 --- a/src/plugins/permissionsViewer/index.tsx +++ b/src/plugins/permissionsViewer/index.tsx @@ -25,9 +25,9 @@ import { SafetyIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; import { classes } from "@utils/misc"; import definePlugin, { OptionType } from "@utils/types"; +import type { Guild, GuildMember } from "@vencord/discord-types"; import { findByPropsLazy } from "@webpack"; import { Button, ChannelStore, Dialog, GuildMemberStore, GuildRoleStore, GuildStore, match, Menu, PermissionsBits, Popout, TooltipContainer, useRef, UserStore } from "@webpack/common"; -import type { Guild, GuildMember } from "discord-types/general"; import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "./components/RolesAndUsersPermissions"; import UserPermissions from "./components/UserPermissions"; @@ -71,7 +71,7 @@ function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) { const { permissions, header } = match(type) .returnType<{ permissions: RoleOrUserPermission[], header: string; }>() .with(MenuItemParentType.User, () => { - const member = GuildMemberStore.getMember(guildId, id!); + const member = GuildMemberStore.getMember(guildId, id!)!; const permissions: RoleOrUserPermission[] = getSortedRoles(guild, member) .map(role => ({ diff --git a/src/plugins/permissionsViewer/utils.ts b/src/plugins/permissionsViewer/utils.ts index 409c0896..022dca6e 100644 --- a/src/plugins/permissionsViewer/utils.ts +++ b/src/plugins/permissionsViewer/utils.ts @@ -17,9 +17,9 @@ */ import { classNameFactory } from "@api/Styles"; +import { Guild, GuildMember, Role } from "@vencord/discord-types"; import { findByPropsLazy } from "@webpack"; import { GuildRoleStore } from "@webpack/common"; -import { Guild, GuildMember, Role } from "discord-types/general"; import { PermissionsSortOrder, settings } from "."; import { PermissionType } from "./components/RolesAndUsersPermissions"; diff --git a/src/plugins/petpet/index.ts b/src/plugins/petpet/index.ts index 708c6f0c..40fd0af8 100644 --- a/src/plugins/petpet/index.ts +++ b/src/plugins/petpet/index.ts @@ -16,10 +16,11 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { ApplicationCommandInputType, ApplicationCommandOptionType, Argument, CommandContext, findOption, sendBotMessage } from "@api/Commands"; +import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands"; import { Devs } from "@utils/constants"; import { makeLazy } from "@utils/lazy"; import definePlugin from "@utils/types"; +import { CommandArgument, CommandContext } from "@vencord/discord-types"; import { findByPropsLazy } from "@webpack"; import { DraftType, UploadHandler, UploadManager, UserUtils } from "@webpack/common"; import { applyPalette, GIFEncoder, quantize } from "gifenc"; @@ -54,7 +55,7 @@ function loadImage(source: File | string) { }); } -async function resolveImage(options: Argument[], ctx: CommandContext, noServerPfp: boolean): Promise<File | string | null> { +async function resolveImage(options: CommandArgument[], ctx: CommandContext, noServerPfp: boolean): Promise<File | string | null> { for (const opt of options) { switch (opt.name) { case "image": @@ -177,6 +178,8 @@ export default definePlugin({ } gif.finish(); + // @ts-ignore This causes a type error on *only some* typescript versions. + // usage adheres to mdn https://developer.mozilla.org/en-US/docs/Web/API/File/File#parameters const file = new File([gif.bytesView()], "petpet.gif", { type: "image/gif" }); // Immediately after the command finishes, Discord clears all input, including pending attachments. // Thus, setTimeout is needed to make this execute after Discord cleared the input diff --git a/src/plugins/pinDms/index.tsx b/src/plugins/pinDms/index.tsx index 59fee9c0..53524257 100644 --- a/src/plugins/pinDms/index.tsx +++ b/src/plugins/pinDms/index.tsx @@ -11,9 +11,9 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { classes } from "@utils/misc"; import definePlugin, { OptionType, StartAt } from "@utils/types"; +import { Channel } from "@vencord/discord-types"; import { findByPropsLazy, findStoreLazy } from "@webpack"; import { Clickable, ContextMenuApi, FluxDispatcher, Menu, React } from "@webpack/common"; -import { Channel } from "discord-types/general"; import { contextMenus } from "./components/contextMenu"; import { openCategoryModal, requireSettingsMenu } from "./components/CreateCategoryModal"; diff --git a/src/plugins/platformIndicators/index.tsx b/src/plugins/platformIndicators/index.tsx index 7829295a..f804e987 100644 --- a/src/plugins/platformIndicators/index.tsx +++ b/src/plugins/platformIndicators/index.tsx @@ -25,9 +25,9 @@ import { Settings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; +import { User } from "@vencord/discord-types"; import { filters, findStoreLazy, mapMangledModuleLazy } from "@webpack"; import { PresenceStore, Tooltip, UserStore } from "@webpack/common"; -import { User } from "discord-types/general"; export interface Session { sessionId: string; diff --git a/src/plugins/previewMessage/index.tsx b/src/plugins/previewMessage/index.tsx index ded408f9..1f64c714 100644 --- a/src/plugins/previewMessage/index.tsx +++ b/src/plugins/previewMessage/index.tsx @@ -20,9 +20,9 @@ import { ChatBarButton, ChatBarButtonFactory } from "@api/ChatButtons"; import { generateId, sendBotMessage } from "@api/Commands"; import { Devs } from "@utils/constants"; import definePlugin, { StartAt } from "@utils/types"; +import { MessageAttachment } from "@vencord/discord-types"; import { findByPropsLazy } from "@webpack"; import { DraftStore, DraftType, SelectedChannelStore, UserStore, useStateFromStores } from "@webpack/common"; -import { MessageAttachment } from "discord-types/general"; const UploadStore = findByPropsLazy("getUploads"); diff --git a/src/plugins/quickReply/index.ts b/src/plugins/quickReply/index.ts index dcd2038c..33e99873 100644 --- a/src/plugins/quickReply/index.ts +++ b/src/plugins/quickReply/index.ts @@ -19,8 +19,8 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; +import { Message } from "@vencord/discord-types"; import { ChannelStore, ComponentDispatch, FluxDispatcher as Dispatcher, MessageActions, MessageStore, PermissionsBits, PermissionStore, SelectedChannelStore, UserStore } from "@webpack/common"; -import { Message } from "discord-types/general"; import NoBlockedMessagesPlugin from "plugins/noBlockedMessages"; import NoReplyMentionPlugin from "plugins/noReplyMention"; diff --git a/src/plugins/readAllNotificationsButton/index.tsx b/src/plugins/readAllNotificationsButton/index.tsx index 419e93af..274e98d3 100644 --- a/src/plugins/readAllNotificationsButton/index.tsx +++ b/src/plugins/readAllNotificationsButton/index.tsx @@ -22,9 +22,9 @@ import { addServerListElement, removeServerListElement, ServerListRenderPosition import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import { Channel } from "@vencord/discord-types"; import { findStoreLazy } from "@webpack"; import { Button, FluxDispatcher, GuildChannelStore, GuildStore, React, ReadStateStore } from "@webpack/common"; -import { Channel } from "discord-types/general"; interface ThreadJoined { channel: Channel; diff --git a/src/plugins/relationshipNotifier/types.ts b/src/plugins/relationshipNotifier/types.ts index c60d5397..f2e482d6 100644 --- a/src/plugins/relationshipNotifier/types.ts +++ b/src/plugins/relationshipNotifier/types.ts @@ -16,7 +16,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { Channel } from "discord-types/general"; +import { Channel } from "@vencord/discord-types"; export interface ChannelDelete { type: "CHANNEL_DELETE"; diff --git a/src/plugins/relationshipNotifier/utils.ts b/src/plugins/relationshipNotifier/utils.ts index 09ef5cdd..aaef783b 100644 --- a/src/plugins/relationshipNotifier/utils.ts +++ b/src/plugins/relationshipNotifier/utils.ts @@ -19,9 +19,9 @@ import { DataStore, Notices } from "@api/index"; import { showNotification } from "@api/Notifications"; import { getUniqueUsername, openUserProfile } from "@utils/discord"; +import { FluxStore } from "@vencord/discord-types"; import { findStoreLazy } from "@webpack"; import { ChannelStore, GuildMemberStore, GuildStore, RelationshipStore, UserStore, UserUtils } from "@webpack/common"; -import { FluxStore } from "@webpack/types"; import settings from "./settings"; import { ChannelType, RelationshipType, SimpleGroupChannel, SimpleGuild } from "./types"; diff --git a/src/plugins/replyTimestamp/index.tsx b/src/plugins/replyTimestamp/index.tsx index 0be5dfec..dcf70c70 100644 --- a/src/plugins/replyTimestamp/index.tsx +++ b/src/plugins/replyTimestamp/index.tsx @@ -9,9 +9,9 @@ import "./style.css"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import type { Message } from "@vencord/discord-types"; import { findByPropsLazy } from "@webpack"; import { DateUtils, Timestamp } from "@webpack/common"; -import type { Message } from "discord-types/general"; import type { HTMLAttributes } from "react"; const MessageClasses = findByPropsLazy("separator", "latin24CompactTimeStamp"); diff --git a/src/plugins/reviewDB/index.tsx b/src/plugins/reviewDB/index.tsx index 32546b9b..d8374e6f 100644 --- a/src/plugins/reviewDB/index.tsx +++ b/src/plugins/reviewDB/index.tsx @@ -24,9 +24,9 @@ import { NotesIcon, OpenExternalIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; import { classes } from "@utils/misc"; import definePlugin from "@utils/types"; +import { Guild, User } from "@vencord/discord-types"; import { findByPropsLazy } from "@webpack"; import { Alerts, Button, Menu, Parser, TooltipContainer } from "@webpack/common"; -import { Guild, User } from "discord-types/general"; import { Auth, initAuth, updateAuth } from "./auth"; import { openReviewsModal } from "./components/ReviewModal"; diff --git a/src/plugins/seeSummaries/index.tsx b/src/plugins/seeSummaries/index.tsx index 343348f1..a5af9bc4 100644 --- a/src/plugins/seeSummaries/index.tsx +++ b/src/plugins/seeSummaries/index.tsx @@ -111,7 +111,6 @@ export default definePlugin({ // SUMMARIES_ENABLED feature is not in discord-types const guild = GuildStore.getGuild(channel.guild_id); - // @ts-expect-error return hasGuildFeature(guild, "SUMMARIES_ENABLED_GA"); } }); diff --git a/src/plugins/serverInfo/GuildInfoModal.tsx b/src/plugins/serverInfo/GuildInfoModal.tsx index 359590cf..2fa687e8 100644 --- a/src/plugins/serverInfo/GuildInfoModal.tsx +++ b/src/plugins/serverInfo/GuildInfoModal.tsx @@ -11,9 +11,9 @@ import { getGuildAcronym, openImageModal, openUserProfile } from "@utils/discord import { classes } from "@utils/misc"; import { ModalRoot, ModalSize, openModal } from "@utils/modal"; import { useAwaiter } from "@utils/react"; +import { Guild, User } from "@vencord/discord-types"; import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; import { FluxDispatcher, Forms, GuildChannelStore, GuildMemberStore, GuildRoleStore, IconUtils, Parser, PresenceStore, RelationshipStore, ScrollerThin, SnowflakeUtils, TabBar, Timestamp, useEffect, UserStore, UserUtils, useState, useStateFromStores } from "@webpack/common"; -import { Guild, User } from "discord-types/general"; const IconClasses = findByPropsLazy("icon", "acronym", "childWrapper"); const FriendRow = findComponentByCodeLazy("discriminatorClass:", ".isMobileOnline", "getAvatarURL"); diff --git a/src/plugins/serverInfo/index.tsx b/src/plugins/serverInfo/index.tsx index 2a3f3adf..98b9b2d5 100644 --- a/src/plugins/serverInfo/index.tsx +++ b/src/plugins/serverInfo/index.tsx @@ -7,8 +7,8 @@ import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import { Guild } from "@vencord/discord-types"; import { Menu } from "@webpack/common"; -import { Guild } from "discord-types/general"; import { openGuildInfoModal } from "./GuildInfoModal"; diff --git a/src/plugins/showConnections/index.tsx b/src/plugins/showConnections/index.tsx index f99c0be9..882c869e 100644 --- a/src/plugins/showConnections/index.tsx +++ b/src/plugins/showConnections/index.tsx @@ -25,9 +25,9 @@ import { CopyIcon, LinkIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; import { copyWithToast } from "@utils/misc"; import definePlugin, { OptionType } from "@utils/types"; +import { User } from "@vencord/discord-types"; import { findByCodeLazy, findByPropsLazy } from "@webpack"; import { Tooltip, UserProfileStore } from "@webpack/common"; -import { User } from "discord-types/general"; import { VerifiedIcon } from "./VerifiedIcon"; diff --git a/src/plugins/showHiddenChannels/components/HiddenChannelLockScreen.tsx b/src/plugins/showHiddenChannels/components/HiddenChannelLockScreen.tsx index bbe286af..4543301b 100644 --- a/src/plugins/showHiddenChannels/components/HiddenChannelLockScreen.tsx +++ b/src/plugins/showHiddenChannels/components/HiddenChannelLockScreen.tsx @@ -20,9 +20,9 @@ import { Settings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { classes } from "@utils/misc"; import { formatDuration } from "@utils/text"; +import type { Channel } from "@vencord/discord-types"; import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, Parser, PermissionsBits, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common"; -import type { Channel } from "discord-types/general"; import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "../../permissionsViewer/components/RolesAndUsersPermissions"; import { sortPermissionOverwrites } from "../../permissionsViewer/utils"; diff --git a/src/plugins/showHiddenChannels/index.tsx b/src/plugins/showHiddenChannels/index.tsx index 149d422b..c99afc84 100644 --- a/src/plugins/showHiddenChannels/index.tsx +++ b/src/plugins/showHiddenChannels/index.tsx @@ -25,9 +25,9 @@ import { Devs } from "@utils/constants"; import { classes } from "@utils/misc"; import { canonicalizeMatch } from "@utils/patches"; import definePlugin, { OptionType } from "@utils/types"; +import type { Channel, Role } from "@vencord/discord-types"; import { findByPropsLazy } from "@webpack"; import { ChannelStore, PermissionsBits, PermissionStore, Tooltip } from "@webpack/common"; -import type { Channel, Role } from "discord-types/general"; import HiddenChannelLockScreen from "./components/HiddenChannelLockScreen"; diff --git a/src/plugins/showMeYourName/index.tsx b/src/plugins/showMeYourName/index.tsx index ba92e82a..b9b10714 100644 --- a/src/plugins/showMeYourName/index.tsx +++ b/src/plugins/showMeYourName/index.tsx @@ -10,7 +10,7 @@ import { definePluginSettings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; -import { Message, User } from "discord-types/general"; +import { Message, User } from "@vencord/discord-types"; interface UsernameProps { author: { nick: string; }; @@ -62,7 +62,7 @@ export default definePlugin({ const user = userOverride ?? message.author; let { username } = user; if (settings.store.displayNames) - username = (user as any).globalName || username; + username = user.globalName || username; const { nick } = author; const prefix = withMentionPrefix ? "@" : ""; diff --git a/src/plugins/showTimeoutDuration/index.tsx b/src/plugins/showTimeoutDuration/index.tsx index 2c7c8a85..1bd68a0c 100644 --- a/src/plugins/showTimeoutDuration/index.tsx +++ b/src/plugins/showTimeoutDuration/index.tsx @@ -12,9 +12,9 @@ import { Devs } from "@utils/constants"; import { getIntlMessage } from "@utils/discord"; import { canonicalizeMatch } from "@utils/patches"; import definePlugin, { OptionType } from "@utils/types"; +import { Message } from "@vencord/discord-types"; import { findComponentLazy } from "@webpack"; import { ChannelStore, GuildMemberStore, Text, Tooltip } from "@webpack/common"; -import { Message } from "discord-types/general"; import { FunctionComponent, ReactNode } from "react"; const countDownFilter = canonicalizeMatch("#{intl::MAX_AGE_NEVER}"); diff --git a/src/plugins/sortFriendRequests/index.tsx b/src/plugins/sortFriendRequests/index.tsx index d8b64cf9..42af9a3a 100644 --- a/src/plugins/sortFriendRequests/index.tsx +++ b/src/plugins/sortFriendRequests/index.tsx @@ -23,8 +23,8 @@ import { classNameFactory } from "@api/Styles"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; +import { User } from "@vencord/discord-types"; import { DateUtils, RelationshipStore, Text, TooltipContainer } from "@webpack/common"; -import { User } from "discord-types/general"; import { PropsWithChildren } from "react"; const formatter = new Intl.DateTimeFormat(undefined, { diff --git a/src/plugins/spotifyShareCommands/index.ts b/src/plugins/spotifyShareCommands/index.ts index ed793963..e11864ae 100644 --- a/src/plugins/spotifyShareCommands/index.ts +++ b/src/plugins/spotifyShareCommands/index.ts @@ -16,10 +16,11 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { ApplicationCommandInputType, Command, findOption, OptionalMessageOption, sendBotMessage } from "@api/Commands"; +import { ApplicationCommandInputType, findOption, OptionalMessageOption, sendBotMessage } from "@api/Commands"; import { Devs } from "@utils/constants"; import { sendMessage } from "@utils/discord"; import definePlugin from "@utils/types"; +import { Command } from "@vencord/discord-types"; import { findByPropsLazy } from "@webpack"; import { FluxDispatcher, MessageActions } from "@webpack/common"; diff --git a/src/plugins/themeAttributes/index.ts b/src/plugins/themeAttributes/index.ts index 7d904e7e..ca54ea27 100644 --- a/src/plugins/themeAttributes/index.ts +++ b/src/plugins/themeAttributes/index.ts @@ -6,8 +6,8 @@ import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import { Message } from "@vencord/discord-types"; import { UserStore } from "@webpack/common"; -import { Message } from "discord-types/general"; export default definePlugin({ diff --git a/src/plugins/translate/TranslationAccessory.tsx b/src/plugins/translate/TranslationAccessory.tsx index db9461d8..00e35689 100644 --- a/src/plugins/translate/TranslationAccessory.tsx +++ b/src/plugins/translate/TranslationAccessory.tsx @@ -16,8 +16,8 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import { Message } from "@vencord/discord-types"; import { Parser, useEffect, useState } from "@webpack/common"; -import { Message } from "discord-types/general"; import { TranslateIcon } from "./TranslateIcon"; import { cl, TranslationValue } from "./utils"; diff --git a/src/plugins/typingIndicator/index.tsx b/src/plugins/typingIndicator/index.tsx index 160b002d..8f667de9 100644 --- a/src/plugins/typingIndicator/index.tsx +++ b/src/plugins/typingIndicator/index.tsx @@ -56,7 +56,7 @@ function TypingIndicator({ channelId, guildId }: { channelId: string; guildId: s return oldKeys.length === currentKeys.length && currentKeys.every(key => old[key] != null); } ); - const currentChannelId: string = useStateFromStores([SelectedChannelStore], () => SelectedChannelStore.getChannelId()); + const currentChannelId = useStateFromStores([SelectedChannelStore], () => SelectedChannelStore.getChannelId()); if (!settings.store.includeMutedChannels) { const isChannelMuted = UserGuildSettingsStore.isChannelMuted(guildId, channelId); diff --git a/src/plugins/typingTweaks/index.tsx b/src/plugins/typingTweaks/index.tsx index fe7acd48..bcfea898 100644 --- a/src/plugins/typingTweaks/index.tsx +++ b/src/plugins/typingTweaks/index.tsx @@ -21,8 +21,8 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { openUserProfile } from "@utils/discord"; import definePlugin, { OptionType } from "@utils/types"; +import { User } from "@vencord/discord-types"; import { Avatar, GuildMemberStore, React, RelationshipStore } from "@webpack/common"; -import { User } from "discord-types/general"; import { PropsWithChildren } from "react"; import managedStyle from "./style.css?managed"; diff --git a/src/plugins/unsuppressEmbeds/index.tsx b/src/plugins/unsuppressEmbeds/index.tsx index 2df64b72..e5f8557f 100644 --- a/src/plugins/unsuppressEmbeds/index.tsx +++ b/src/plugins/unsuppressEmbeds/index.tsx @@ -20,8 +20,8 @@ import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/Co import { ImageInvisible, ImageVisible } from "@components/Icons"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import { MessageSnapshot } from "@vencord/discord-types"; import { Constants, Menu, PermissionsBits, PermissionStore, RestAPI, UserStore } from "@webpack/common"; -import { MessageSnapshot } from "@webpack/types"; const EMBED_SUPPRESSED = 1 << 2; diff --git a/src/plugins/userMessagesPronouns/PronounsChatComponent.tsx b/src/plugins/userMessagesPronouns/PronounsChatComponent.tsx index c2a54f14..b4c32638 100644 --- a/src/plugins/userMessagesPronouns/PronounsChatComponent.tsx +++ b/src/plugins/userMessagesPronouns/PronounsChatComponent.tsx @@ -20,9 +20,9 @@ import { getUserSettingLazy } from "@api/UserSettings"; import ErrorBoundary from "@components/ErrorBoundary"; import { getIntlMessage } from "@utils/discord"; import { classes } from "@utils/misc"; +import { Message } from "@vencord/discord-types"; import { findByPropsLazy } from "@webpack"; import { Tooltip, UserStore } from "@webpack/common"; -import { Message } from "discord-types/general"; import { settings } from "./settings"; import { useFormattedPronouns } from "./utils"; diff --git a/src/plugins/userVoiceShow/components.tsx b/src/plugins/userVoiceShow/components.tsx index 9029cdc5..12d95242 100644 --- a/src/plugins/userVoiceShow/components.tsx +++ b/src/plugins/userVoiceShow/components.tsx @@ -7,9 +7,9 @@ import { classNameFactory } from "@api/Styles"; import ErrorBoundary from "@components/ErrorBoundary"; import { classes } from "@utils/misc"; +import { Channel } from "@vencord/discord-types"; import { filters, findByCodeLazy, findByPropsLazy, findComponentByCodeLazy, findStoreLazy, mapMangledModuleLazy } from "@webpack"; import { ChannelRouter, ChannelStore, GuildStore, IconUtils, match, P, PermissionsBits, PermissionStore, React, showToast, Text, Toasts, Tooltip, useMemo, UserStore, useStateFromStores } from "@webpack/common"; -import { Channel } from "discord-types/general"; const cl = classNameFactory("vc-uvs-"); diff --git a/src/plugins/validReply/index.ts b/src/plugins/validReply/index.ts index 989513d0..0f0a198d 100644 --- a/src/plugins/validReply/index.ts +++ b/src/plugins/validReply/index.ts @@ -6,10 +6,9 @@ import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import { Channel, Message, User } from "@vencord/discord-types"; import { findByCodeLazy } from "@webpack"; import { FluxDispatcher, RestAPI } from "@webpack/common"; -import { Message, User } from "discord-types/general"; -import { Channel } from "discord-types/general/index.js"; const enum ReferencedMessageState { Loaded, diff --git a/src/plugins/vcNarrator/index.tsx b/src/plugins/vcNarrator/index.tsx index 02eb216c..117c1388 100644 --- a/src/plugins/vcNarrator/index.tsx +++ b/src/plugins/vcNarrator/index.tsx @@ -144,7 +144,14 @@ function playSample(tempSettings: any, type: string) { const currentUser = UserStore.getCurrentUser(); const myGuildId = SelectedGuildStore.getGuildId(); - speak(formatText(s[type + "Message"], currentUser.username, "general", (currentUser as any).globalName ?? currentUser.username, GuildMemberStore.getNick(myGuildId, currentUser.id) ?? currentUser.username), s); + speak(formatText( + s[type + "Message"], + currentUser.username, + "general", + currentUser.globalName ?? currentUser.username, + GuildMemberStore.getNick(myGuildId!, currentUser.id) ?? currentUser.username), + s + ); } export default definePlugin({ @@ -177,7 +184,7 @@ export default definePlugin({ const template = settings.store[type + "Message"]; const user = isMe && !settings.store.sayOwnName ? "" : UserStore.getUser(userId).username; const displayName = user && ((UserStore.getUser(userId) as any).globalName ?? user); - const nickname = user && (GuildMemberStore.getNick(myGuildId, userId) ?? user); + const nickname = user && (GuildMemberStore.getNick(myGuildId!, userId) ?? user); const channel = ChannelStore.getChannel(id).name; speak(formatText(template, user, channel, displayName, nickname)); diff --git a/src/plugins/viewIcons/index.tsx b/src/plugins/viewIcons/index.tsx index 2afdb2d5..3b8485fc 100644 --- a/src/plugins/viewIcons/index.tsx +++ b/src/plugins/viewIcons/index.tsx @@ -22,8 +22,8 @@ import { ImageIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; import { openImageModal } from "@utils/discord"; import definePlugin, { OptionType } from "@utils/types"; +import type { Channel, Guild, User } from "@vencord/discord-types"; import { GuildMemberStore, IconUtils, Menu } from "@webpack/common"; -import type { Channel, Guild, User } from "discord-types/general"; interface UserContextProps { diff --git a/src/plugins/viewRaw/index.tsx b/src/plugins/viewRaw/index.tsx index 7eb7b78f..e6781784 100644 --- a/src/plugins/viewRaw/index.tsx +++ b/src/plugins/viewRaw/index.tsx @@ -27,8 +27,8 @@ import { Margins } from "@utils/margins"; import { copyWithToast } from "@utils/misc"; import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal"; import definePlugin, { OptionType } from "@utils/types"; +import { Message } from "@vencord/discord-types"; import { Button, ChannelStore, Forms, GuildRoleStore, Menu, Text } from "@webpack/common"; -import { Message } from "discord-types/general"; const CopyIcon = () => { diff --git a/src/plugins/whoReacted/index.tsx b/src/plugins/whoReacted/index.tsx index f14de9f5..a2826a2c 100644 --- a/src/plugins/whoReacted/index.tsx +++ b/src/plugins/whoReacted/index.tsx @@ -22,10 +22,9 @@ import { sleep } from "@utils/misc"; import { Queue } from "@utils/Queue"; import { useForceUpdater } from "@utils/react"; import definePlugin from "@utils/types"; +import { CustomEmoji, Message, ReactionEmoji, User } from "@vencord/discord-types"; import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; import { ChannelStore, Constants, FluxDispatcher, React, RestAPI, Tooltip, useEffect, useLayoutEffect } from "@webpack/common"; -import { CustomEmoji } from "@webpack/types"; -import { Message, ReactionEmoji, User } from "discord-types/general"; const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers"); const AvatarStyles = findByPropsLazy("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar"); diff --git a/src/plugins/xsOverlay/index.tsx b/src/plugins/xsOverlay/index.tsx index 1ffbd3ff..27faac93 100644 --- a/src/plugins/xsOverlay/index.tsx +++ b/src/plugins/xsOverlay/index.tsx @@ -9,9 +9,9 @@ import { makeRange } from "@components/PluginSettings/components"; import { Devs } from "@utils/constants"; import { Logger } from "@utils/Logger"; import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types"; +import type { Channel, Embed, GuildMember, MessageAttachment, User } from "@vencord/discord-types"; import { findByCodeLazy, findLazy } from "@webpack"; import { Button, ChannelStore, GuildRoleStore, GuildStore, UserStore } from "@webpack/common"; -import type { Channel, Embed, GuildMember, MessageAttachment, User } from "discord-types/general"; const ChannelTypes = findLazy(m => m.ANNOUNCEMENT_THREAD === 10); diff --git a/src/utils/apng-canvas.js b/src/utils/apng-canvas.js index 5149dcc0..62203a75 100644 --- a/src/utils/apng-canvas.js +++ b/src/utils/apng-canvas.js @@ -1,6 +1,5 @@ /* eslint-disable */ -const self = module.exports; /** * apng-canvas v2.1.2 * @@ -549,11 +548,7 @@ const self = module.exports; }).call( this, Y("VCmEsw"), - "undefined" != typeof self - ? self - : "undefined" != typeof window - ? window - : {} + module.exports ); }, { VCmEsw: 2 }, @@ -880,11 +875,7 @@ const self = module.exports; }); }).call( this, - "undefined" != typeof self - ? self - : "undefined" != typeof window - ? window - : {} + module.exports ); }, { "./loader": 6, "./parser": 7, "./support-test": 8 }, @@ -1153,11 +1144,7 @@ const self = module.exports; }; }).call( this, - "undefined" != typeof self - ? self - : "undefined" != typeof window - ? window - : {} + module.exports ); }, { "es6-promise": 1 }, diff --git a/src/utils/discord.tsx b/src/utils/discord.tsx index fce909c3..4a652a29 100644 --- a/src/utils/discord.tsx +++ b/src/utils/discord.tsx @@ -17,9 +17,8 @@ */ import { MessageObject } from "@api/MessageEvents"; +import { Channel, Guild, GuildFeatures, Message, User } from "@vencord/discord-types"; import { ChannelActionCreators, ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, i18n, IconUtils, InviteActions, MessageActions, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common"; -import { Channel, Guild, Message, User } from "discord-types/general"; -import GuildFeatures from "discord-types/other/Constants"; import { Except } from "type-fest"; import { runtimeHashMessageKey } from "./intlHash"; @@ -228,6 +227,6 @@ export function getGuildAcronym(guild: Guild): string { .replace(/\s/g, ""); } -export function hasGuildFeature(guild: Guild, feature: keyof GuildFeatures["GuildFeatures"]): boolean { +export function hasGuildFeature(guild: Guild, feature: GuildFeatures): boolean { return guild.features?.has(feature) ?? false; } diff --git a/src/utils/types.ts b/src/utils/types.ts index 3ad63ea1..1c53b971 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -18,14 +18,13 @@ import { ProfileBadge } from "@api/Badges"; import { ChatBarButtonFactory } from "@api/ChatButtons"; -import { Command } from "@api/Commands"; import { NavContextMenuPatchCallback } from "@api/ContextMenu"; import { MemberListDecoratorFactory } from "@api/MemberListDecorators"; import { MessageAccessoryFactory } from "@api/MessageAccessories"; import { MessageDecorationFactory } from "@api/MessageDecorations"; import { MessageClickListener, MessageEditListener, MessageSendListener } from "@api/MessageEvents"; import { MessagePopoverButtonFactory } from "@api/MessagePopover"; -import { FluxEvents } from "@webpack/types"; +import { Command, FluxEvents } from "@vencord/discord-types"; import { ReactNode } from "react"; import { Promisable } from "type-fest"; diff --git a/src/webpack/common/classes.ts b/src/webpack/common/classes.ts index ca3d75f5..85b90537 100644 --- a/src/webpack/common/classes.ts +++ b/src/webpack/common/classes.ts @@ -16,9 +16,8 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import * as t from "@vencord/discord-types"; import { findByPropsLazy, findLazy } from "@webpack"; -import * as t from "./types/classes"; - export const ModalImageClasses: t.ImageModalClasses = findLazy(m => m.image && m.modal && !m.applicationIcon); export const ButtonWrapperClasses: t.ButtonWrapperClasses = findByPropsLazy("buttonWrapper", "buttonContent"); diff --git a/src/webpack/common/components.ts b/src/webpack/common/components.ts index bcce3cbb..a392a02f 100644 --- a/src/webpack/common/components.ts +++ b/src/webpack/common/components.ts @@ -17,10 +17,10 @@ */ import { LazyComponent } from "@utils/lazyReact"; +import * as t from "@vencord/discord-types"; import { filters, mapMangledModuleLazy, waitFor } from "@webpack"; import { waitForComponent } from "./internal"; -import * as t from "./types/components"; const FormTitle = waitForComponent<t.FormTitle>("FormTitle", filters.componentByCode('["defaultMargin".concat', '="h5"')); diff --git a/src/webpack/common/index.ts b/src/webpack/common/index.ts index 4193330c..80223b9a 100644 --- a/src/webpack/common/index.ts +++ b/src/webpack/common/index.ts @@ -21,8 +21,5 @@ export * from "./components"; export * from "./menu"; export * from "./react"; export * from "./stores"; -export * as ComponentTypes from "./types/components.d"; -export * as MenuTypes from "./types/menu.d"; -export * as UtilTypes from "./types/utils.d"; export * from "./userSettings"; export * from "./utils"; diff --git a/src/webpack/common/menu.ts b/src/webpack/common/menu.ts index 2bb05f36..e4c5d0a3 100644 --- a/src/webpack/common/menu.ts +++ b/src/webpack/common/menu.ts @@ -16,10 +16,9 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import type * as t from "@vencord/discord-types"; import { filters, mapMangledModuleLazy, waitFor, wreq } from "@webpack"; -import type * as t from "./types/menu"; - export const Menu = {} as t.Menu; // Relies on .name properties added by the MenuItemDemanglerAPI diff --git a/src/webpack/common/stores.ts b/src/webpack/common/stores.ts index 712f5bdc..be72d47c 100644 --- a/src/webpack/common/stores.ts +++ b/src/webpack/common/stores.ts @@ -16,11 +16,10 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import * as t from "@vencord/discord-types"; import { findByCodeLazy, findByPropsLazy, waitFor } from "@webpack"; -import type * as Stores from "discord-types/stores"; import { waitForStore } from "./internal"; -import * as t from "./types/stores"; export const Flux: t.Flux = findByPropsLazy("connectStores"); @@ -28,7 +27,7 @@ export type GenericStore = t.FluxStore & Record<string, any>; export const DraftType = findByPropsLazy("ChannelMessage", "SlashCommand"); -export let MessageStore: Omit<Stores.MessageStore, "getMessages"> & GenericStore & { +export let MessageStore: Omit<t.MessageStore, "getMessages"> & GenericStore & { getMessages(chanId: string): any; }; @@ -41,12 +40,12 @@ export let PresenceStore: GenericStore; export let GuildStore: t.GuildStore; export let GuildRoleStore: t.GuildRoleStore; -export let GuildMemberStore: Stores.GuildMemberStore & t.FluxStore; -export let UserStore: Stores.UserStore & t.FluxStore; +export let GuildMemberStore: t.GuildMemberStore; +export let UserStore: t.UserStore; export let UserProfileStore: GenericStore; -export let SelectedChannelStore: Stores.SelectedChannelStore & t.FluxStore; -export let SelectedGuildStore: t.FluxStore & Record<string, any>; -export let ChannelStore: Stores.ChannelStore & t.FluxStore; +export let SelectedChannelStore: t.SelectedChannelStore; +export let SelectedGuildStore: t.SelectedGuildStore; +export let ChannelStore: t.ChannelStore; export let RelationshipStore: t.RelationshipStore; export let EmojiStore: t.EmojiStore; @@ -55,14 +54,7 @@ export let WindowStore: t.WindowStore; export let DraftStore: t.DraftStore; /** - * React hook that returns stateful data for one or more stores - * You might need a custom comparator (4th argument) if your store data is an object - * @param stores The stores to listen to - * @param mapper A function that returns the data you need - * @param dependencies An array of reactive values which the hook depends on. Use this if your mapper or equality function depends on the value of another hook - * @param isEqual A custom comparator for the data returned by mapper - * - * @example const user = useStateFromStores([UserStore], () => UserStore.getCurrentUser(), null, (old, current) => old.id === current.id); + * @see jsdoc of {@link t.useStateFromStores} */ export const useStateFromStores: t.useStateFromStores = findByCodeLazy("useStateFromStores"); diff --git a/src/webpack/common/types/classes.d.ts b/src/webpack/common/types/classes.d.ts deleted file mode 100644 index b6066177..00000000 --- a/src/webpack/common/types/classes.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2023 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -export interface ImageModalClasses { - image: string, - modal: string, -} - -export interface ButtonWrapperClasses { - hoverScale: string; - buttonWrapper: string; - button: string; - iconMask: string; - buttonContent: string; - icon: string; - pulseIcon: string; - pulseButton: string; - notificationDot: string; - sparkleContainer: string; - sparkleStar: string; - sparklePlus: string; - sparkle: string; - active: string; -} diff --git a/src/webpack/common/types/fluxEvents.d.ts b/src/webpack/common/types/fluxEvents.d.ts deleted file mode 100644 index 1bd50f46..00000000 --- a/src/webpack/common/types/fluxEvents.d.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2023 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -/* -function makeFluxEventList() { - // prefill MESSAGE_CREATE so that typescript infers this is a String Set - // without explicitly typing so that this function is also valid javascript - const events = new Set(["MESSAGE_CREATE"]); - - const { nodes } = Vencord.Webpack.Common.FluxDispatcher._actionHandlers._dependencyGraph; - for (const nodeId in nodes) { - for (const event in nodes[nodeId].actionHandler) { - events.add(event); - } - } - for (const event in Vencord.Webpack.Common.FluxDispatcher._subscriptions) { - events.add(event); - } - - return Array.from(events, e => JSON.stringify(e)).sort().join("|"); -} -*/ - -// 46kb worth of events ??????? -export type FluxEvents = "ACCESSIBILITY_COLORBLIND_TOGGLE" | "ACCESSIBILITY_DARK_SIDEBAR_TOGGLE" | "ACCESSIBILITY_DESATURATE_ROLES_TOGGLE" | "ACCESSIBILITY_FORCED_COLORS_MODAL_SEEN" | "ACCESSIBILITY_KEYBOARD_MODE_DISABLE" | "ACCESSIBILITY_KEYBOARD_MODE_ENABLE" | "ACCESSIBILITY_LOW_CONTRAST_TOGGLE" | "ACCESSIBILITY_RESET_TO_DEFAULT" | "ACCESSIBILITY_SET_ALWAYS_SHOW_LINK_DECORATIONS" | "ACCESSIBILITY_SET_CONTRAST" | "ACCESSIBILITY_SET_FONT_SIZE" | "ACCESSIBILITY_SET_MESSAGE_GROUP_SPACING" | "ACCESSIBILITY_SET_PREFERS_REDUCED_MOTION" | "ACCESSIBILITY_SET_ROLE_STYLE" | "ACCESSIBILITY_SET_SATURATION" | "ACCESSIBILITY_SET_SYNC_FORCED_COLORS" | "ACCESSIBILITY_SET_ZOOM" | "ACCESSIBILITY_SUBMIT_BUTTON_TOGGLE" | "ACCESSIBILITY_SYNC_PROFILE_THEME_WITH_USER_THEME_TOGGLE" | "ACCESSIBILITY_SYSTEM_COLOR_PREFERENCES_CHANGED" | "ACCESSIBILITY_SYSTEM_PREFERS_CONTRAST_CHANGED" | "ACCESSIBILITY_SYSTEM_PREFERS_CROSSFADES_CHANGED" | "ACCESSIBILITY_SYSTEM_PREFERS_REDUCED_MOTION_CHANGED" | "ACKNOWLEDGE_CHANNEL_SAFETY_WARNING_TOOLTIP" | "ACK_APPROVED_GUILD_JOIN_REQUEST" | "ACTIVE_BOGO_PROMOTION_FETCH" | "ACTIVE_BOGO_PROMOTION_FETCH_FAIL" | "ACTIVE_BOGO_PROMOTION_FETCH_SUCCESS" | "ACTIVE_CHANNELS_FETCH_FAILURE" | "ACTIVE_CHANNELS_FETCH_START" | "ACTIVE_CHANNELS_FETCH_SUCCESS" | "ACTIVE_OUTBOUND_PROMOTIONS_FETCH" | "ACTIVE_OUTBOUND_PROMOTIONS_FETCH_FAIL" | "ACTIVE_OUTBOUND_PROMOTIONS_FETCH_SUCCESS" | "ACTIVITIES_WHATS_NEW_ACKNOWLEDGE_SECTION" | "ACTIVITIES_WHATS_NEW_MARK_OPENED_SECTION" | "ACTIVITY_INVITE_EDUCATION_DISMISS" | "ACTIVITY_INVITE_MODAL_CLOSE" | "ACTIVITY_INVITE_MODAL_OPEN" | "ACTIVITY_JOIN" | "ACTIVITY_JOIN_FAILED" | "ACTIVITY_JOIN_LOADING" | "ACTIVITY_LAUNCH_FAIL" | "ACTIVITY_LAYOUT_MODE_UPDATE" | "ACTIVITY_METADATA_UPDATE" | "ACTIVITY_PLAY" | "ACTIVITY_SCREEN_ORIENTATION_UPDATE" | "ACTIVITY_START" | "ACTIVITY_SYNC" | "ACTIVITY_SYNC_STOP" | "ACTIVITY_UPDATE_FAIL" | "ACTIVITY_UPDATE_START" | "ACTIVITY_UPDATE_SUCCESS" | "ADD_STICKER_PREVIEW" | "ADMIN_ONBOARDING_GUIDE_HIDE" | "ADYEN_CASH_APP_PAY_SUBMIT_SUCCESS" | "ADYEN_CREATE_CASH_APP_PAY_COMPONENT_SUCCESS" | "ADYEN_CREATE_CLIENT_SUCCESS" | "ADYEN_TEARDOWN_CLIENT" | "AFK" | "AGE_GATE_FAILURE_MODAL_OPEN" | "AGE_GATE_LOGOUT_UNDERAGE_NEW_USER" | "AGE_GATE_MODAL_CLOSE" | "AGE_GATE_MODAL_OPEN" | "AGE_GATE_SUCCESS_MODAL_OPEN" | "APPLICATIONS_FETCH" | "APPLICATIONS_FETCH_FAIL" | "APPLICATIONS_FETCH_SUCCESS" | "APPLICATIONS_SHELF_FETCH_FAIL" | "APPLICATIONS_SHELF_FETCH_START" | "APPLICATIONS_SHELF_FETCH_SUCCESS" | "APPLICATION_ACTIVITY_STATISTICS_FETCH_FAIL" | "APPLICATION_ACTIVITY_STATISTICS_FETCH_START" | "APPLICATION_ACTIVITY_STATISTICS_FETCH_SUCCESS" | "APPLICATION_ASSETS_FETCH" | "APPLICATION_ASSETS_FETCH_SUCCESS" | "APPLICATION_ASSETS_UPDATE" | "APPLICATION_BRANCHES_FETCH_FAIL" | "APPLICATION_BRANCHES_FETCH_SUCCESS" | "APPLICATION_BUILD_FETCH_START" | "APPLICATION_BUILD_FETCH_SUCCESS" | "APPLICATION_BUILD_NOT_FOUND" | "APPLICATION_BUILD_SIZE_FETCH_FAIL" | "APPLICATION_BUILD_SIZE_FETCH_START" | "APPLICATION_BUILD_SIZE_FETCH_SUCCESS" | "APPLICATION_COMMAND_AUTOCOMPLETE_REQUEST" | "APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE" | "APPLICATION_COMMAND_EXECUTE_BAD_VERSION" | "APPLICATION_COMMAND_INDEX_FETCH_FAILURE" | "APPLICATION_COMMAND_INDEX_FETCH_REQUEST" | "APPLICATION_COMMAND_INDEX_FETCH_SUCCESS" | "APPLICATION_COMMAND_SET_ACTIVE_COMMAND" | "APPLICATION_COMMAND_SET_PREFERRED_COMMAND" | "APPLICATION_COMMAND_UPDATE_CHANNEL_STATE" | "APPLICATION_COMMAND_UPDATE_OPTIONS" | "APPLICATION_COMMAND_USED" | "APPLICATION_DIRECTORY_FETCH_APPLICATION" | "APPLICATION_DIRECTORY_FETCH_APPLICATION_FAILURE" | "APPLICATION_DIRECTORY_FETCH_APPLICATION_SUCCESS" | "APPLICATION_DIRECTORY_FETCH_CATEGORIES_SUCCESS" | "APPLICATION_DIRECTORY_FETCH_COLLECTIONS" | "APPLICATION_DIRECTORY_FETCH_COLLECTIONS_FAILURE" | "APPLICATION_DIRECTORY_FETCH_COLLECTIONS_SUCCESS" | "APPLICATION_DIRECTORY_FETCH_SEARCH" | "APPLICATION_DIRECTORY_FETCH_SEARCH_FAILURE" | "APPLICATION_DIRECTORY_FETCH_SEARCH_SUCCESS" | "APPLICATION_DIRECTORY_FETCH_SIMILAR_APPLICATIONS" | "APPLICATION_DIRECTORY_FETCH_SIMILAR_APPLICATIONS_FAILURE" | "APPLICATION_DIRECTORY_FETCH_SIMILAR_APPLICATIONS_SUCCESS" | "APPLICATION_FETCH" | "APPLICATION_FETCH_FAIL" | "APPLICATION_FETCH_SUCCESS" | "APPLICATION_STORE_ACCEPT_EULA" | "APPLICATION_STORE_ACCEPT_STORE_TERMS" | "APPLICATION_STORE_CLEAR_DATA" | "APPLICATION_STORE_LOCATION_CHANGE" | "APPLICATION_STORE_MATURE_AGREE" | "APPLICATION_STORE_RESET_NAVIGATION" | "APPLICATION_SUBSCRIPTIONS_CHANNEL_NOTICE_DISMISSED" | "APPLICATION_SUBSCRIPTIONS_FETCH_ENTITLEMENTS" | "APPLICATION_SUBSCRIPTIONS_FETCH_ENTITLEMENTS_FAILURE" | "APPLICATION_SUBSCRIPTIONS_FETCH_ENTITLEMENTS_SUCCESS" | "APPLICATION_SUBSCRIPTIONS_FETCH_LISTINGS" | "APPLICATION_SUBSCRIPTIONS_FETCH_LISTINGS_FAILURE" | "APPLICATION_SUBSCRIPTIONS_FETCH_LISTINGS_SUCCESS" | "APPLICATION_SUBSCRIPTIONS_FETCH_LISTING_FOR_PLAN_SUCCESS" | "APPLIED_BOOSTS_COOLDOWN_FETCH_SUCCESS" | "APPLIED_GUILD_BOOST_COUNT_UPDATE" | "APP_ICON_EDITOR_CLOSE" | "APP_ICON_EDITOR_OPEN" | "APP_ICON_TRACK_IMPRESSION" | "APP_ICON_UPDATED" | "APP_LAUNCHER_DISMISS_APP_DETAIL" | "APP_LAUNCHER_DISMISS_POPUP" | "APP_LAUNCHER_SET_ACTIVE_COMMAND" | "APP_LAUNCHER_SHOW_APP_DETAIL" | "APP_LAUNCHER_SHOW_POPUP" | "APP_STATE_UPDATE" | "APP_VIEW_SET_HOME_LINK" | "AUDIO_INPUT_DETECTED" | "AUDIO_RESET" | "AUDIO_SET_ATTENUATION" | "AUDIO_SET_AUTOMATIC_GAIN_CONTROL" | "AUDIO_SET_DEBUG_LOGGING" | "AUDIO_SET_DISPLAY_SILENCE_WARNING" | "AUDIO_SET_ECHO_CANCELLATION" | "AUDIO_SET_INPUT_DEVICE" | "AUDIO_SET_INPUT_VOLUME" | "AUDIO_SET_LOCAL_PAN" | "AUDIO_SET_LOCAL_VIDEO_DISABLED" | "AUDIO_SET_LOCAL_VOLUME" | "AUDIO_SET_LOOPBACK" | "AUDIO_SET_MODE" | "AUDIO_SET_NOISE_CANCELLATION" | "AUDIO_SET_NOISE_SUPPRESSION" | "AUDIO_SET_OUTPUT_DEVICE" | "AUDIO_SET_OUTPUT_VOLUME" | "AUDIO_SET_QOS" | "AUDIO_SET_SELF_MUTE" | "AUDIO_SET_SUBSYSTEM" | "AUDIO_SET_TEMPORARY_SELF_MUTE" | "AUDIO_TOGGLE_LOCAL_MUTE" | "AUDIO_TOGGLE_LOCAL_SOUNDBOARD_MUTE" | "AUDIO_TOGGLE_SELF_DEAF" | "AUDIO_TOGGLE_SELF_MUTE" | "AUDIO_VOLUME_CHANGE" | "AUDIT_LOG_FETCH_FAIL" | "AUDIT_LOG_FETCH_NEXT_PAGE_FAIL" | "AUDIT_LOG_FETCH_NEXT_PAGE_START" | "AUDIT_LOG_FETCH_NEXT_PAGE_SUCCESS" | "AUDIT_LOG_FETCH_START" | "AUDIT_LOG_FETCH_SUCCESS" | "AUDIT_LOG_FILTER_BY_ACTION" | "AUDIT_LOG_FILTER_BY_TARGET" | "AUDIT_LOG_FILTER_BY_USER" | "AUTHENTICATOR_CREATE" | "AUTHENTICATOR_DELETE" | "AUTHENTICATOR_UPDATE" | "AUTH_INVITE_UPDATE" | "AUTH_SESSION_CHANGE" | "AUTO_MODERATION_MENTION_RAID_DETECTION" | "AUTO_MODERATION_MENTION_RAID_NOTICE_DISMISS" | "BACKGROUND_SYNC" | "BACKGROUND_SYNC_CHANNEL_MESSAGES" | "BILLING_ANNUAL_USER_OFFER_FETCH_FAIL" | "BILLING_ANNUAL_USER_OFFER_FETCH_SUCCESS" | "BILLING_CREATE_REFERRAL_PREVIEW_FAIL" | "BILLING_CREATE_REFERRAL_PREVIEW_START" | "BILLING_CREATE_REFERRAL_PREVIEW_SUCCESS" | "BILLING_CREATE_REFERRAL_SUCCESS" | "BILLING_IP_COUNTRY_CODE_FAILURE" | "BILLING_IP_COUNTRY_CODE_FETCH_START" | "BILLING_LOCALIZED_PRICING_PROMO_FAILURE" | "BILLING_MOST_RECENT_SUBSCRIPTION_FETCH_SUCCESS" | "BILLING_NITRO_AFFINITY_FETCHED" | "BILLING_NITRO_AFFINITY_FETCH_SUCCEEDED" | "BILLING_PAYMENTS_FETCH_SUCCESS" | "BILLING_PAYMENT_FETCH_SUCCESS" | "BILLING_PAYMENT_SOURCES_FETCH_FAIL" | "BILLING_PAYMENT_SOURCES_FETCH_START" | "BILLING_PAYMENT_SOURCES_FETCH_SUCCESS" | "BILLING_PAYMENT_SOURCE_CREATE_FAIL" | "BILLING_PAYMENT_SOURCE_CREATE_START" | "BILLING_PAYMENT_SOURCE_CREATE_SUCCESS" | "BILLING_PAYMENT_SOURCE_REMOVE_CLEAR_ERROR" | "BILLING_PAYMENT_SOURCE_REMOVE_FAIL" | "BILLING_PAYMENT_SOURCE_REMOVE_START" | "BILLING_PAYMENT_SOURCE_REMOVE_SUCCESS" | "BILLING_PAYMENT_SOURCE_UPDATE_CLEAR_ERROR" | "BILLING_PAYMENT_SOURCE_UPDATE_FAIL" | "BILLING_PAYMENT_SOURCE_UPDATE_START" | "BILLING_PAYMENT_SOURCE_UPDATE_SUCCESS" | "BILLING_PERKS_RELEVANCE_FETCH_FAIL" | "BILLING_PERKS_RELEVANCE_FETCH_START" | "BILLING_PERKS_RELEVANCE_FETCH_SUCCESS" | "BILLING_POPUP_BRIDGE_CALLBACK" | "BILLING_POPUP_BRIDGE_STATE_UPDATE" | "BILLING_PREVIOUS_PREMIUM_SUBSCRIPTION_FETCH_SUCCESS" | "BILLING_PURCHASE_TOKEN_AUTH_CLEAR_STATE" | "BILLING_REFERRALS_REMAINING_FETCH_FAIL" | "BILLING_REFERRALS_REMAINING_FETCH_START" | "BILLING_REFERRALS_REMAINING_FETCH_SUCCESS" | "BILLING_REFERRAL_RESOLVE_FAIL" | "BILLING_REFERRAL_RESOLVE_SUCCESS" | "BILLING_REFERRAL_TRIAL_OFFER_UPDATE" | "BILLING_SET_IP_COUNTRY_CODE" | "BILLING_SET_LOCALIZED_PRICING_PROMO" | "BILLING_SUBSCRIPTION_CANCEL_FAIL" | "BILLING_SUBSCRIPTION_CANCEL_START" | "BILLING_SUBSCRIPTION_CANCEL_SUCCESS" | "BILLING_SUBSCRIPTION_FETCH_FAIL" | "BILLING_SUBSCRIPTION_FETCH_START" | "BILLING_SUBSCRIPTION_FETCH_SUCCESS" | "BILLING_SUBSCRIPTION_RESET" | "BILLING_SUBSCRIPTION_UPDATE_FAIL" | "BILLING_SUBSCRIPTION_UPDATE_START" | "BILLING_SUBSCRIPTION_UPDATE_SUCCESS" | "BILLING_USER_OFFER_ACKNOWLEDGED_SUCCESS" | "BILLING_USER_OFFER_FETCH_FAIL" | "BILLING_USER_OFFER_FETCH_SUCCESS" | "BILLING_USER_PREMIUM_LIKELIHOOD_FETCH" | "BILLING_USER_PREMIUM_LIKELIHOOD_FETCH_ERROR" | "BILLING_USER_PREMIUM_LIKELIHOOD_FETCH_SUCCESS" | "BILLING_USER_TRIAL_OFFER_ACKNOWLEDGED_SUCCESS" | "BILLING_USER_TRIAL_OFFER_FETCH_SUCCESS" | "BLOCKED_DOMAIN_LIST_FETCHED" | "BOOSTED_GUILD_GRACE_PERIOD_NOTICE_DISMISS" | "BRAINTREE_CREATE_CLIENT_SUCCESS" | "BRAINTREE_CREATE_PAYPAL_CLIENT_SUCCESS" | "BRAINTREE_CREATE_VENMO_CLIENT_SUCCESS" | "BRAINTREE_TEARDOWN_PAYPAL_CLIENT" | "BRAINTREE_TEARDOWN_VENMO_CLIENT" | "BRAINTREE_TOKENIZE_PAYPAL_FAIL" | "BRAINTREE_TOKENIZE_PAYPAL_START" | "BRAINTREE_TOKENIZE_PAYPAL_SUCCESS" | "BRAINTREE_TOKENIZE_VENMO_FAIL" | "BRAINTREE_TOKENIZE_VENMO_START" | "BRAINTREE_TOKENIZE_VENMO_SUCCESS" | "BROADCASTER_BUCKETS_RECEIVED" | "BROADCAST_START" | "BROADCAST_STOP" | "BROADCAST_VIEWERS_UPDATE" | "BROWSER_HANDOFF_BEGIN" | "BROWSER_HANDOFF_FROM_APP" | "BROWSER_HANDOFF_SET_USER" | "BROWSER_HANDOFF_UNAVAILABLE" | "BUILD_OVERRIDE_RESOLVED" | "BULK_ACK" | "BULK_CLEAR_RECENTS" | "BURST_REACTION_ANIMATION_ADD" | "BURST_REACTION_EFFECT_CLEAR" | "BURST_REACTION_EFFECT_PLAY" | "BURST_REACTION_PICKER_ANIMATION_ADD" | "BURST_REACTION_PICKER_ANIMATION_CLEAR" | "CACHED_EMOJIS_LOADED" | "CACHED_STICKERS_LOADED" | "CACHE_LOADED" | "CACHE_LOADED_LAZY" | "CACHE_LOADED_LAZY_NO_CACHE" | "CALL_CHAT_TOASTS_SET_ENABLED" | "CALL_CONNECT" | "CALL_CONNECT_MULTIPLE" | "CALL_CREATE" | "CALL_DELETE" | "CALL_ENQUEUE_RING" | "CALL_UPDATE" | "CANDIDATE_GAMES_CHANGE" | "CATEGORY_COLLAPSE" | "CATEGORY_COLLAPSE_ALL" | "CATEGORY_EXPAND" | "CATEGORY_EXPAND_ALL" | "CERTIFIED_DEVICES_SET" | "CHANGE_LOG_FETCH_FAILED" | "CHANGE_LOG_FETCH_SUCCESS" | "CHANGE_LOG_LOCK" | "CHANGE_LOG_MARK_SEEN" | "CHANGE_LOG_SET_CONFIG" | "CHANGE_LOG_SET_OVERRIDE" | "CHANGE_LOG_UNLOCK" | "CHANNEL_ACK" | "CHANNEL_CALL_POPOUT_WINDOW_OPEN" | "CHANNEL_COLLAPSE" | "CHANNEL_CREATE" | "CHANNEL_DELETE" | "CHANNEL_FOLLOWER_CREATED" | "CHANNEL_FOLLOWER_STATS_FETCH_FAILURE" | "CHANNEL_FOLLOWER_STATS_FETCH_SUCCESS" | "CHANNEL_FOLLOWING_PUBLISH_BUMP_DISMISSED" | "CHANNEL_FOLLOWING_PUBLISH_BUMP_HIDE_PERMANENTLY" | "CHANNEL_LOCAL_ACK" | "CHANNEL_MUTE_EXPIRED" | "CHANNEL_PINS_ACK" | "CHANNEL_PINS_UPDATE" | "CHANNEL_PRELOAD" | "CHANNEL_RECIPIENT_ADD" | "CHANNEL_RECIPIENT_REMOVE" | "CHANNEL_RTC_ACTIVE_CHANNELS" | "CHANNEL_RTC_SELECT_PARTICIPANT" | "CHANNEL_RTC_UPDATE_CHAT_OPEN" | "CHANNEL_RTC_UPDATE_LAYOUT" | "CHANNEL_RTC_UPDATE_PARTICIPANTS_OPEN" | "CHANNEL_RTC_UPDATE_STAGE_STREAM_SIZE" | "CHANNEL_RTC_UPDATE_STAGE_VIDEO_LIMIT_BOOST_UPSELL_DISMISSED" | "CHANNEL_RTC_UPDATE_VOICE_PARTICIPANTS_HIDDEN" | "CHANNEL_SAFETY_WARNING_FEEDBACK" | "CHANNEL_SELECT" | "CHANNEL_SETTINGS_CLOSE" | "CHANNEL_SETTINGS_INIT" | "CHANNEL_SETTINGS_LOADED_INVITES" | "CHANNEL_SETTINGS_OPEN" | "CHANNEL_SETTINGS_OVERWRITE_SELECT" | "CHANNEL_SETTINGS_PERMISSIONS_INIT" | "CHANNEL_SETTINGS_PERMISSIONS_SAVE_SUCCESS" | "CHANNEL_SETTINGS_PERMISSIONS_SELECT_PERMISSION" | "CHANNEL_SETTINGS_PERMISSIONS_SET_ADVANCED_MODE" | "CHANNEL_SETTINGS_PERMISSIONS_SUBMITTING" | "CHANNEL_SETTINGS_PERMISSIONS_UPDATE_PERMISSION" | "CHANNEL_SETTINGS_SET_SECTION" | "CHANNEL_SETTINGS_SUBMIT" | "CHANNEL_SETTINGS_SUBMIT_FAILURE" | "CHANNEL_SETTINGS_SUBMIT_SUCCESS" | "CHANNEL_SETTINGS_UPDATE" | "CHANNEL_STATUSES" | "CHANNEL_TOGGLE_MEMBERS_SECTION" | "CHANNEL_TOGGLE_SUMMARIES_SECTION" | "CHANNEL_UPDATES" | "CHECKING_FOR_UPDATES" | "CHECK_LAUNCHABLE_GAME" | "CLAN_SETUP_ERROR" | "CLAN_SETUP_RESET" | "CLAN_SETUP_SUBMIT" | "CLAN_SETUP_SUCCESS" | "CLAN_SETUP_UPDATE" | "CLEAR_AUTHENTICATION_ERRORS" | "CLEAR_CACHES" | "CLEAR_CHANNEL_SAFETY_WARNINGS" | "CLEAR_CONVERSATION_SUMMARIES" | "CLEAR_HANG_STATUS" | "CLEAR_INTERACTION_MODAL_STATE" | "CLEAR_LAST_SESSION_VOICE_CHANNEL_ID" | "CLEAR_MENTIONS" | "CLEAR_MESSAGES" | "CLEAR_OLDEST_UNREAD_MESSAGE" | "CLEAR_PENDING_CHANNEL_AND_ROLE_UPDATES" | "CLEAR_REMOTE_DISCONNECT_VOICE_CHANNEL_ID" | "CLEAR_STICKER_PREVIEW" | "CLIENT_THEMES_EDITOR_CLOSE" | "CLIENT_THEMES_EDITOR_OPEN" | "CLIPS_CLASSIFY_HARDWARE" | "CLIPS_CLEAR_CLIPS_SESSION" | "CLIPS_CLEAR_NEW_CLIP_IDS" | "CLIPS_DELETE_CLIP" | "CLIPS_DISMISS_EDUCATION" | "CLIPS_INIT" | "CLIPS_INIT_FAILURE" | "CLIPS_LOAD_DIRECTORY_SUCCESS" | "CLIPS_RESTART" | "CLIPS_SAVE_ANIMATION_END" | "CLIPS_SAVE_CLIP" | "CLIPS_SAVE_CLIP_ERROR" | "CLIPS_SAVE_CLIP_PLACEHOLDER" | "CLIPS_SAVE_CLIP_PLACEHOLDER_ERROR" | "CLIPS_SAVE_CLIP_START" | "CLIPS_SETTINGS_UPDATE" | "CLIPS_SHOW_CALL_WARNING" | "CLIPS_UPDATE_METADATA" | "CLOSE_SUSPENDED_USER" | "COLLECTIBLES_CATEGORIES_FETCH" | "COLLECTIBLES_CATEGORIES_FETCH_FAILURE" | "COLLECTIBLES_CATEGORIES_FETCH_SUCCESS" | "COLLECTIBLES_CATEGORY_ITEMS_VIEWED" | "COLLECTIBLES_CLAIM" | "COLLECTIBLES_CLAIM_FAILURE" | "COLLECTIBLES_CLAIM_SUCCESS" | "COLLECTIBLES_PRODUCT_DETAILS_OPEN" | "COLLECTIBLES_PRODUCT_FETCH" | "COLLECTIBLES_PRODUCT_FETCH_FAILURE" | "COLLECTIBLES_PRODUCT_FETCH_SUCCESS" | "COLLECTIBLES_PURCHASES_FETCH" | "COLLECTIBLES_PURCHASES_FETCH_FAILURE" | "COLLECTIBLES_PURCHASES_FETCH_SUCCESS" | "COLLECTIBLES_SHOP_CLOSE" | "COLLECTIBLES_SHOP_OPEN" | "COMMANDS_MIGRATION_NOTICE_DISMISSED" | "COMMANDS_MIGRATION_OVERVIEW_TOOLTIP_DISMISSED" | "COMMANDS_MIGRATION_TOGGLE_TOOLTIP_DISMISSED" | "COMMANDS_MIGRATION_UPDATE_SUCCESS" | "COMPLETE_NEW_MEMBER_ACTION" | "COMPLETE_SIGN_UP" | "CONNECTED_DEVICE_IGNORE" | "CONNECTED_DEVICE_NEVER_SHOW_MODAL" | "CONNECTED_DEVICE_SET" | "CONNECTIONS_GRID_MODAL_HIDE" | "CONNECTIONS_GRID_MODAL_SHOW" | "CONNECTION_CLOSED" | "CONNECTION_INTERRUPTED" | "CONNECTION_OPEN" | "CONNECTION_OPEN_SUPPLEMENTAL" | "CONNECTION_RESUMED" | "CONSOLE_COMMAND_UPDATE" | "CONTENT_INVENTORY_CLEAR_FEED" | "CONTENT_INVENTORY_DEBUG_CLEAR_IMPRESSIONS" | "CONTENT_INVENTORY_DEBUG_LOG_IMPRESSIONS" | "CONTENT_INVENTORY_DEBUG_TOGGLE_FAST_IMPRESSION_CAPPING" | "CONTENT_INVENTORY_DEBUG_TOGGLE_IMPRESSION_CAPPING" | "CONTENT_INVENTORY_MANUAL_REFRESH" | "CONTENT_INVENTORY_SET_FEED" | "CONTENT_INVENTORY_SET_FILTERS" | "CONTENT_INVENTORY_TOGGLE_FEED_HIDDEN" | "CONTENT_INVENTORY_TOGGLE_REPLY_MODE" | "CONTENT_INVENTORY_TRACK_ITEM_IMPRESSIONS" | "CONTEXT_MENU_CLOSE" | "CONTEXT_MENU_OPEN" | "CONVERSATION_SUMMARY_UPDATE" | "CREATE_PENDING_REPLY" | "CREATE_REFERRALS_SUCCESS" | "CREATE_SHALLOW_PENDING_REPLY" | "CREATOR_MONETIZATION_NAG_ACTIVATE_ELIGIBLITY_FETCH_SUCCESS" | "CREATOR_MONETIZATION_PRICE_TIERS_FETCH" | "CREATOR_MONETIZATION_PRICE_TIERS_FETCH_FAILURE" | "CREATOR_MONETIZATION_PRICE_TIERS_FETCH_SUCCESS" | "CURRENT_BUILD_OVERRIDE_RESOLVED" | "CURRENT_USER_UPDATE" | "DCF_DAILY_CAP_OVERRIDE" | "DCF_HANDLE_DC_DISMISSED" | "DCF_HANDLE_DC_SHOWN" | "DCF_RESET" | "DECAY_READ_STATES" | "DELETED_ENTITY_IDS" | "DELETE_PENDING_REPLY" | "DELETE_SUMMARY" | "DETECTABLE_GAME_SUPPLEMENTAL_FETCH" | "DETECTABLE_GAME_SUPPLEMENTAL_FETCH_FAILURE" | "DETECTABLE_GAME_SUPPLEMENTAL_FETCH_SUCCESS" | "DETECTED_OFF_PLATFORM_PREMIUM_PERKS_DISMISS" | "DEVELOPER_ACTIVITY_SHELF_FETCH_FAIL" | "DEVELOPER_ACTIVITY_SHELF_FETCH_START" | "DEVELOPER_ACTIVITY_SHELF_FETCH_SUCCESS" | "DEVELOPER_ACTIVITY_SHELF_MARK_ACTIVITY_USED" | "DEVELOPER_ACTIVITY_SHELF_SET_ACTIVITY_URL_OVERRIDE" | "DEVELOPER_ACTIVITY_SHELF_TOGGLE_USE_ACTIVITY_URL_OVERRIDE" | "DEVELOPER_ACTIVITY_SHELF_UPDATE_FILTER" | "DEVELOPER_OPTIONS_UPDATE_SETTINGS" | "DEVELOPER_TEST_MODE_AUTHORIZATION_FAIL" | "DEVELOPER_TEST_MODE_AUTHORIZATION_START" | "DEVELOPER_TEST_MODE_AUTHORIZATION_SUCCESS" | "DEVELOPER_TEST_MODE_RESET" | "DEVELOPER_TEST_MODE_RESET_ERROR" | "DEV_TOOLS_DESIGN_TOGGLE_SET" | "DEV_TOOLS_DESIGN_TOGGLE_WEB_SET" | "DEV_TOOLS_DEV_SETTING_SET" | "DEV_TOOLS_SETTINGS_UPDATE" | "DISABLE_AUTOMATIC_ACK" | "DISCOVER_CHECKLIST_FETCH_FAILURE" | "DISCOVER_CHECKLIST_FETCH_START" | "DISCOVER_CHECKLIST_FETCH_SUCCESS" | "DISMISS_CHANNEL_SAFETY_WARNINGS" | "DISMISS_FAVORITE_SUGGESTION" | "DISMISS_MEDIA_POST_SHARE_PROMPT" | "DISMISS_SIGN_UP" | "DISPATCH_APPLICATION_ADD_TO_INSTALLATIONS" | "DISPATCH_APPLICATION_CANCEL" | "DISPATCH_APPLICATION_ERROR" | "DISPATCH_APPLICATION_INSTALL" | "DISPATCH_APPLICATION_INSTALL_SCRIPTS_PROGRESS_UPDATE" | "DISPATCH_APPLICATION_LAUNCH_SETUP_COMPLETE" | "DISPATCH_APPLICATION_LAUNCH_SETUP_START" | "DISPATCH_APPLICATION_MOVE_UP" | "DISPATCH_APPLICATION_REMOVE_FINISHED" | "DISPATCH_APPLICATION_REPAIR" | "DISPATCH_APPLICATION_STATE_UPDATE" | "DISPATCH_APPLICATION_UNINSTALL" | "DISPATCH_APPLICATION_UPDATE" | "DISPLAYED_INVITE_SHOW" | "DOMAIN_MIGRATION_FAILURE" | "DOMAIN_MIGRATION_SKIP" | "DOMAIN_MIGRATION_START" | "DRAFT_CHANGE" | "DRAFT_CLEAR" | "DRAFT_SAVE" | "DRAWER_CLOSE" | "DRAWER_OPEN" | "DRAWER_SELECT_TAB" | "DROPS_ELIGIBILITY_FETCH_SUCCESS" | "DROPS_ENROLLED_USER_FETCH_SUCCESS" | "DROPS_FETCH_PROGRESS_FAILURE" | "DROPS_FETCH_PROGRESS_SUCCESS" | "DROPS_HEARTBEAT_FAILURE" | "DROPS_HEARTBEAT_SUCCESS" | "DROPS_PLATFORM_AVAILABILITY_SUCCESS" | "DROPS_UNENROLL_USER" | "DROPS_USER_STATUS_FETCH_FAILURE" | "DROPS_USER_STATUS_FETCH_SUCCESS" | "EMAIL_SETTINGS_FETCH_SUCCESS" | "EMAIL_SETTINGS_UPDATE" | "EMAIL_SETTINGS_UPDATE_SUCCESS" | "EMBEDDED_ACTIVITY_CLOSE" | "EMBEDDED_ACTIVITY_DEFERRED_OPEN" | "EMBEDDED_ACTIVITY_DISCONNECT" | "EMBEDDED_ACTIVITY_DISMISS_NEW_INDICATOR" | "EMBEDDED_ACTIVITY_FETCH_SHELF" | "EMBEDDED_ACTIVITY_FETCH_SHELF_FAIL" | "EMBEDDED_ACTIVITY_FETCH_SHELF_SUCCESS" | "EMBEDDED_ACTIVITY_LAUNCH_FAIL" | "EMBEDDED_ACTIVITY_LAUNCH_START" | "EMBEDDED_ACTIVITY_LAUNCH_SUCCESS" | "EMBEDDED_ACTIVITY_OPEN" | "EMBEDDED_ACTIVITY_SET_CONFIG" | "EMBEDDED_ACTIVITY_SET_FOCUSED_LAYOUT" | "EMBEDDED_ACTIVITY_SET_ORIENTATION_LOCK_STATE" | "EMBEDDED_ACTIVITY_SET_PANEL_MODE" | "EMBEDDED_ACTIVITY_UPDATE" | "EMBEDDED_ACTIVITY_UPDATE_V2" | "EMOJI_AUTOSUGGESTION_UPDATE" | "EMOJI_CAPTIONS_FETCH" | "EMOJI_CAPTIONS_FETCH_ERROR" | "EMOJI_CAPTIONS_FETCH_SUCCESS" | "EMOJI_INTERACTION_INITIATED" | "EMOJI_TRACK_USAGE" | "ENABLE_AUTOMATIC_ACK" | "ENABLE_GUILD_SIGN_UP" | "ENABLE_USER_SIGN_UP" | "ENTITLEMENTS_FETCH_FOR_USER_FAIL" | "ENTITLEMENTS_FETCH_FOR_USER_START" | "ENTITLEMENTS_FETCH_FOR_USER_SUCCESS" | "ENTITLEMENTS_GIFTABLE_FETCH_SUCCESS" | "ENTITLEMENT_CREATE" | "ENTITLEMENT_DELETE" | "ENTITLEMENT_FETCH_APPLICATION_FAIL" | "ENTITLEMENT_FETCH_APPLICATION_START" | "ENTITLEMENT_FETCH_APPLICATION_SUCCESS" | "ENTITLEMENT_UPDATE" | "EVENT_DIRECTORY_FETCH_FAILURE" | "EVENT_DIRECTORY_FETCH_START" | "EVENT_DIRECTORY_FETCH_SUCCESS" | "EXPERIMENTS_FETCH" | "EXPERIMENTS_FETCH_FAILURE" | "EXPERIMENTS_FETCH_SUCCESS" | "EXPERIMENT_OVERRIDE_BUCKET" | "EXPERIMENT_REGISTER_LEGACY" | "FAMILY_CENTER_FETCH_START" | "FAMILY_CENTER_HANDLE_TAB_SELECT" | "FAMILY_CENTER_INITIAL_LOAD" | "FAMILY_CENTER_LINKED_USERS_FETCH_SUCCESS" | "FAMILY_CENTER_LINK_CODE_FETCH_SUCCESS" | "FAMILY_CENTER_REQUEST_LINK_REMOVE_SUCCESS" | "FAMILY_CENTER_REQUEST_LINK_SUCCESS" | "FAMILY_CENTER_REQUEST_LINK_UPDATE_SUCCESS" | "FAMILY_CENTER_TEEN_ACTIVITY_FETCH_SUCCESS" | "FAMILY_CENTER_TEEN_ACTIVITY_MORE_FETCH_SUCCESS" | "FETCH_AUTH_SESSIONS_SUCCESS" | "FETCH_CLAN_DISCOVERY_SEARCH_RESULT_SUCCESS" | "FETCH_GUILD_EVENT" | "FETCH_GUILD_EVENTS_FOR_GUILD" | "FETCH_GUILD_MEMBER_SUPPLEMENTAL_SUCCESS" | "FETCH_INTEGRATION_APPLICATION_IDS_FOR_MY_GUILDS" | "FETCH_INTEGRATION_APPLICATION_IDS_FOR_MY_GUILDS_FAILURE" | "FETCH_INTEGRATION_APPLICATION_IDS_FOR_MY_GUILDS_SUCCESS" | "FETCH_PRIVATE_CHANNEL_INTEGRATIONS_FAIL" | "FETCH_PRIVATE_CHANNEL_INTEGRATIONS_START" | "FETCH_PRIVATE_CHANNEL_INTEGRATIONS_SUCCESS" | "FETCH_STATIC_CLAN_LIST_SUCCESS" | "FINGERPRINT" | "FORCE_INVISIBLE" | "FORGOT_PASSWORD_REQUEST" | "FORGOT_PASSWORD_SENT" | "FORUM_SEARCH_CLEAR" | "FORUM_SEARCH_FAILURE" | "FORUM_SEARCH_QUERY_UPDATED" | "FORUM_SEARCH_START" | "FORUM_SEARCH_SUCCESS" | "FORUM_UNREADS" | "FRIENDS_SET_INITIAL_SECTION" | "FRIENDS_SET_SECTION" | "FRIEND_INVITES_FETCH_REQUEST" | "FRIEND_INVITES_FETCH_RESPONSE" | "FRIEND_INVITE_CREATE_FAILURE" | "FRIEND_INVITE_CREATE_REQUEST" | "FRIEND_INVITE_CREATE_SUCCESS" | "FRIEND_INVITE_REVOKE_REQUEST" | "FRIEND_INVITE_REVOKE_SUCCESS" | "FRIEND_SUGGESTION_CREATE" | "FRIEND_SUGGESTION_DELETE" | "GAMES_DATABASE_FETCH" | "GAMES_DATABASE_FETCH_FAIL" | "GAMES_DATABASE_UPDATE" | "GAME_CLOUD_SYNC_COMPLETE" | "GAME_CLOUD_SYNC_CONFLICT" | "GAME_CLOUD_SYNC_ERROR" | "GAME_CLOUD_SYNC_START" | "GAME_CLOUD_SYNC_UPDATE" | "GAME_CONSOLE_FETCH_DEVICES_FAIL" | "GAME_CONSOLE_FETCH_DEVICES_START" | "GAME_CONSOLE_FETCH_DEVICES_SUCCESS" | "GAME_CONSOLE_SELECT_DEVICE" | "GAME_DETECTION_WATCH_CANDIDATE_GAMES_START" | "GAME_ICON_UPDATE" | "GAME_INVITE_CLEAR_UNSEEN" | "GAME_INVITE_CREATE" | "GAME_INVITE_DELETE" | "GAME_INVITE_DELETE_MANY" | "GAME_INVITE_UPDATE_STATUS" | "GAME_LAUNCHABLE_UPDATE" | "GAME_LAUNCH_FAIL" | "GAME_LAUNCH_START" | "GAME_LAUNCH_SUCCESS" | "GENERIC_PUSH_NOTIFICATION_SENT" | "GIFT_CODES_FETCH" | "GIFT_CODES_FETCH_FAILURE" | "GIFT_CODES_FETCH_SUCCESS" | "GIFT_CODE_CREATE" | "GIFT_CODE_CREATE_SUCCESS" | "GIFT_CODE_REDEEM" | "GIFT_CODE_REDEEM_FAILURE" | "GIFT_CODE_REDEEM_SUCCESS" | "GIFT_CODE_RESOLVE" | "GIFT_CODE_RESOLVE_FAILURE" | "GIFT_CODE_RESOLVE_SUCCESS" | "GIFT_CODE_REVOKE_SUCCESS" | "GIFT_CODE_UPDATE" | "GIF_PICKER_INITIALIZE" | "GIF_PICKER_QUERY" | "GIF_PICKER_QUERY_FAILURE" | "GIF_PICKER_QUERY_SUCCESS" | "GIF_PICKER_SUGGESTIONS_SUCCESS" | "GIF_PICKER_TRENDING_FETCH_SUCCESS" | "GIF_PICKER_TRENDING_SEARCH_TERMS_SUCCESS" | "GUILD_ACK" | "GUILD_APPLICATIONS_FETCH_SUCCESS" | "GUILD_APPLICATION_COMMAND_INDEX_UPDATE" | "GUILD_APPLIED_BOOSTS_FETCH_SUCCESS" | "GUILD_APPLY_BOOST_FAIL" | "GUILD_APPLY_BOOST_START" | "GUILD_APPLY_BOOST_SUCCESS" | "GUILD_BAN_ADD" | "GUILD_BAN_REMOVE" | "GUILD_BOOST_SLOTS_FETCH_SUCCESS" | "GUILD_BOOST_SLOT_CREATE" | "GUILD_BOOST_SLOT_UPDATE" | "GUILD_BOOST_SLOT_UPDATE_SUCCESS" | "GUILD_CREATE" | "GUILD_DELETE" | "GUILD_DIRECTORY_ADMIN_ENTRIES_FETCH_SUCCESS" | "GUILD_DIRECTORY_CACHED_SEARCH" | "GUILD_DIRECTORY_CATEGORY_SELECT" | "GUILD_DIRECTORY_COUNTS_FETCH_SUCCESS" | "GUILD_DIRECTORY_ENTRY_CREATE" | "GUILD_DIRECTORY_ENTRY_DELETE" | "GUILD_DIRECTORY_ENTRY_UPDATE" | "GUILD_DIRECTORY_FETCH_FAILURE" | "GUILD_DIRECTORY_FETCH_START" | "GUILD_DIRECTORY_FETCH_SUCCESS" | "GUILD_DIRECTORY_SEARCH_CLEAR" | "GUILD_DIRECTORY_SEARCH_FAILURE" | "GUILD_DIRECTORY_SEARCH_START" | "GUILD_DIRECTORY_SEARCH_SUCCESS" | "GUILD_DISCOVERY_CATEGORY_ADD" | "GUILD_DISCOVERY_CATEGORY_DELETE" | "GUILD_DISCOVERY_CATEGORY_FETCH_SUCCESS" | "GUILD_DISCOVERY_CATEGORY_UPDATE_FAIL" | "GUILD_DISCOVERY_CLEAR_SEARCH" | "GUILD_DISCOVERY_CLEAR_SEEN_GUILDS" | "GUILD_DISCOVERY_FETCH_FAILURE" | "GUILD_DISCOVERY_FETCH_START" | "GUILD_DISCOVERY_FETCH_SUCCESS" | "GUILD_DISCOVERY_GUILD_SEEN" | "GUILD_DISCOVERY_METADATA_FETCH_FAIL" | "GUILD_DISCOVERY_POPULAR_FETCH_FAILURE" | "GUILD_DISCOVERY_POPULAR_FETCH_START" | "GUILD_DISCOVERY_POPULAR_FETCH_SUCCESS" | "GUILD_DISCOVERY_SEARCH_COUNTS_FAIL" | "GUILD_DISCOVERY_SEARCH_FETCH_FAILURE" | "GUILD_DISCOVERY_SEARCH_FETCH_START" | "GUILD_DISCOVERY_SEARCH_FETCH_SUCCESS" | "GUILD_DISCOVERY_SEARCH_INIT" | "GUILD_DISCOVERY_SEARCH_UPDATE_COUNTS" | "GUILD_DISCOVERY_SELECT_CATEGORY" | "GUILD_DISCOVERY_SLUG_FETCH_FAIL" | "GUILD_DISCOVERY_SLUG_FETCH_SUCCESS" | "GUILD_EMOJIS_UPDATE" | "GUILD_FEATURE_ACK" | "GUILD_FEED_FEATURED_ITEMS_FETCH_FAILURE" | "GUILD_FEED_FEATURED_ITEMS_FETCH_SUCCESS" | "GUILD_FEED_FEATURE_ITEM" | "GUILD_FEED_FETCH_FAILURE" | "GUILD_FEED_FETCH_FRESH_START" | "GUILD_FEED_FETCH_PAGE_START" | "GUILD_FEED_FETCH_SUCCESS" | "GUILD_FEED_ITEM_HIDE" | "GUILD_FEED_ITEM_READ_ACK" | "GUILD_FEED_ITEM_REMOVE" | "GUILD_FEED_ITEM_UNHIDE" | "GUILD_FEED_UNFEATURE_ITEM" | "GUILD_FOLDER_COLLAPSE" | "GUILD_FOLDER_CREATE_LOCAL" | "GUILD_FOLDER_DELETE_LOCAL" | "GUILD_FOLDER_EDIT_LOCAL" | "GUILD_GEO_RESTRICTED" | "GUILD_HOME_ENSURE_HOME_SESSION" | "GUILD_HOME_SETTINGS_FETCH_FAIL" | "GUILD_HOME_SETTINGS_FETCH_START" | "GUILD_HOME_SETTINGS_FETCH_SUCCESS" | "GUILD_HOME_SETTINGS_TOGGLE_ENABLED" | "GUILD_HOME_SETTINGS_UPDATE_SUCCESS" | "GUILD_HOME_SET_SCROLL_POSITION" | "GUILD_HOME_SET_SOURCE" | "GUILD_IDENTITY_SETTINGS_CLEAR_ERRORS" | "GUILD_IDENTITY_SETTINGS_CLOSE" | "GUILD_IDENTITY_SETTINGS_INIT" | "GUILD_IDENTITY_SETTINGS_RESET_ALL_PENDING" | "GUILD_IDENTITY_SETTINGS_RESET_AND_CLOSE_FORM" | "GUILD_IDENTITY_SETTINGS_RESET_PENDING_MEMBER_CHANGES" | "GUILD_IDENTITY_SETTINGS_RESET_PENDING_PROFILE_CHANGES" | "GUILD_IDENTITY_SETTINGS_SET_GUILD" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_AVATAR" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_AVATAR_DECORATION" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_BANNER" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_BIO" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_NICKNAME" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_PROFILE_EFFECT_ID" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_PRONOUNS" | "GUILD_IDENTITY_SETTINGS_SET_PENDING_THEME_COLORS" | "GUILD_IDENTITY_SETTINGS_SUBMIT" | "GUILD_IDENTITY_SETTINGS_SUBMIT_FAILURE" | "GUILD_IDENTITY_SETTINGS_SUBMIT_SUCCESS" | "GUILD_INTEGRATIONS_UPDATE" | "GUILD_JOIN" | "GUILD_JOIN_REQUESTS_BULK_ACTION" | "GUILD_JOIN_REQUESTS_FETCH_FAILURE" | "GUILD_JOIN_REQUESTS_FETCH_START" | "GUILD_JOIN_REQUESTS_FETCH_SUCCESS" | "GUILD_JOIN_REQUESTS_SET_APPLICATION_TAB" | "GUILD_JOIN_REQUESTS_SET_SELECTED" | "GUILD_JOIN_REQUESTS_SET_SORT_ORDER" | "GUILD_JOIN_REQUEST_BY_ID_FETCH_SUCCESS" | "GUILD_JOIN_REQUEST_CREATE" | "GUILD_JOIN_REQUEST_DELETE" | "GUILD_JOIN_REQUEST_UPDATE" | "GUILD_MEMBERS_CHUNK_BATCH" | "GUILD_MEMBERS_REQUEST" | "GUILD_MEMBER_ADD" | "GUILD_MEMBER_LIST_UPDATE" | "GUILD_MEMBER_PROFILE_UPDATE" | "GUILD_MEMBER_REMOVE" | "GUILD_MEMBER_UPDATE" | "GUILD_MEMBER_UPDATE_LOCAL" | "GUILD_MOVE_BY_ID" | "GUILD_MUTE_EXPIRED" | "GUILD_NEW_MEMBER_ACTIONS_DELETE_SUCCESS" | "GUILD_NEW_MEMBER_ACTIONS_FETCH_FAIL" | "GUILD_NEW_MEMBER_ACTIONS_FETCH_START" | "GUILD_NEW_MEMBER_ACTIONS_FETCH_SUCCESS" | "GUILD_NEW_MEMBER_ACTION_UPDATE_SUCCESS" | "GUILD_NSFW_AGREE" | "GUILD_ONBOARDING_COMPLETE" | "GUILD_ONBOARDING_PROMPTS_FETCH_FAILURE" | "GUILD_ONBOARDING_PROMPTS_FETCH_START" | "GUILD_ONBOARDING_PROMPTS_FETCH_SUCCESS" | "GUILD_ONBOARDING_PROMPTS_LOCAL_UPDATE" | "GUILD_ONBOARDING_SELECT_OPTION" | "GUILD_ONBOARDING_SET_STEP" | "GUILD_ONBOARDING_START" | "GUILD_ONBOARDING_UPDATE_RESPONSES_SUCCESS" | "GUILD_POPOUT_FETCH_FAILURE" | "GUILD_POPOUT_FETCH_START" | "GUILD_POPOUT_FETCH_SUCCESS" | "GUILD_PRODUCTS_FETCH" | "GUILD_PRODUCTS_FETCH_FAILURE" | "GUILD_PRODUCTS_FETCH_SUCCESS" | "GUILD_PRODUCT_CREATE" | "GUILD_PRODUCT_DELETE" | "GUILD_PRODUCT_FETCH" | "GUILD_PRODUCT_FETCH_FAILURE" | "GUILD_PRODUCT_FETCH_SUCCESS" | "GUILD_PRODUCT_UPDATE" | "GUILD_PROGRESS_COMPLETED_SEEN" | "GUILD_PROGRESS_DISMISS" | "GUILD_PROGRESS_INITIALIZE" | "GUILD_PROMPT_VIEWED" | "GUILD_RECOMMENDATION_FETCH" | "GUILD_RECOMMENDATION_FETCH_FAILURE" | "GUILD_RECOMMENDATION_FETCH_SUCCESS" | "GUILD_RESOURCE_CHANNEL_UPDATE_SUCCESS" | "GUILD_ROLE_CONNECTION_ELIGIBILITY_FETCH_SUCCESS" | "GUILD_ROLE_CREATE" | "GUILD_ROLE_DELETE" | "GUILD_ROLE_MEMBER_ADD" | "GUILD_ROLE_MEMBER_BULK_ADD" | "GUILD_ROLE_MEMBER_COUNT_FETCH_SUCCESS" | "GUILD_ROLE_MEMBER_COUNT_UPDATE" | "GUILD_ROLE_MEMBER_REMOVE" | "GUILD_ROLE_SUBSCRIPTIONS_CREATE_LISTING" | "GUILD_ROLE_SUBSCRIPTIONS_DELETE_GROUP_LISTING" | "GUILD_ROLE_SUBSCRIPTIONS_DELETE_LISTING" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_LISTINGS" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_LISTINGS_FAILURE" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_LISTINGS_SUCCESS" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_LISTING_FOR_PLAN" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_LISTING_FOR_PLAN_SUCCESS" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_RESTRICTIONS" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_RESTRICTIONS_ABORTED" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_RESTRICTIONS_FAILURE" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_RESTRICTIONS_SUCCESS" | "GUILD_ROLE_SUBSCRIPTIONS_FETCH_TEMPLATES" | "GUILD_ROLE_SUBSCRIPTIONS_STASH_TEMPLATE_CHANNELS" | "GUILD_ROLE_SUBSCRIPTIONS_UPDATE_GROUP_LISTING" | "GUILD_ROLE_SUBSCRIPTIONS_UPDATE_LISTING" | "GUILD_ROLE_SUBSCRIPTIONS_UPDATE_SUBSCRIPTIONS_SETTINGS" | "GUILD_ROLE_SUBSCRIPTIONS_UPDATE_SUBSCRIPTION_TRIAL" | "GUILD_ROLE_UPDATE" | "GUILD_SCHEDULED_EVENT_CREATE" | "GUILD_SCHEDULED_EVENT_DELETE" | "GUILD_SCHEDULED_EVENT_EXCEPTIONS_DELETE" | "GUILD_SCHEDULED_EVENT_EXCEPTION_CREATE" | "GUILD_SCHEDULED_EVENT_EXCEPTION_DELETE" | "GUILD_SCHEDULED_EVENT_EXCEPTION_UPDATE" | "GUILD_SCHEDULED_EVENT_RSVPS_FETCH_SUCESS" | "GUILD_SCHEDULED_EVENT_UPDATE" | "GUILD_SCHEDULED_EVENT_USERS_FETCH_SUCCESS" | "GUILD_SCHEDULED_EVENT_USER_ADD" | "GUILD_SCHEDULED_EVENT_USER_COUNTS_FETCH_SUCCESS" | "GUILD_SCHEDULED_EVENT_USER_REMOVE" | "GUILD_SEARCH_RECENT_MEMBERS" | "GUILD_SETTINGS_CANCEL_CHANGES" | "GUILD_SETTINGS_CLOSE" | "GUILD_SETTINGS_DEFAULT_CHANNELS_SAVE_SUCCESS" | "GUILD_SETTINGS_INIT" | "GUILD_SETTINGS_LOADED_BANS" | "GUILD_SETTINGS_LOADED_BANS_BATCH" | "GUILD_SETTINGS_LOADED_INTEGRATIONS" | "GUILD_SETTINGS_LOADED_INVITES" | "GUILD_SETTINGS_ONBOARDING_PROMPTS_SAVE_SUCCESS" | "GUILD_SETTINGS_ONBOARDING_SET_MODE" | "GUILD_SETTINGS_OPEN" | "GUILD_SETTINGS_ROLE_SELECT" | "GUILD_SETTINGS_SAVE_ROUTE_STACK" | "GUILD_SETTINGS_SET_MFA_SUCCESS" | "GUILD_SETTINGS_SET_SEARCH_QUERY" | "GUILD_SETTINGS_SET_SECTION" | "GUILD_SETTINGS_SET_VANITY_URL" | "GUILD_SETTINGS_SET_WIDGET" | "GUILD_SETTINGS_SUBMIT" | "GUILD_SETTINGS_SUBMIT_FAILURE" | "GUILD_SETTINGS_SUBMIT_SUCCESS" | "GUILD_SETTINGS_UPDATE" | "GUILD_SOUNDBOARD_FETCH" | "GUILD_SOUNDBOARD_SOUNDS_UPDATE" | "GUILD_SOUNDBOARD_SOUND_CREATE" | "GUILD_SOUNDBOARD_SOUND_DELETE" | "GUILD_SOUNDBOARD_SOUND_PLAY_END" | "GUILD_SOUNDBOARD_SOUND_PLAY_LOCALLY" | "GUILD_SOUNDBOARD_SOUND_PLAY_START" | "GUILD_SOUNDBOARD_SOUND_UPDATE" | "GUILD_STICKERS_CREATE_SUCCESS" | "GUILD_STICKERS_FETCH_SUCCESS" | "GUILD_STICKERS_UPDATE" | "GUILD_STOP_LURKING" | "GUILD_STOP_LURKING_FAILURE" | "GUILD_SUBSCRIPTIONS" | "GUILD_SUBSCRIPTIONS_ADD_MEMBER_UPDATES" | "GUILD_SUBSCRIPTIONS_CHANNEL" | "GUILD_SUBSCRIPTIONS_FLUSH" | "GUILD_SUBSCRIPTIONS_MEMBERS_ADD" | "GUILD_SUBSCRIPTIONS_MEMBERS_REMOVE" | "GUILD_SUBSCRIPTIONS_REMOVE_MEMBER_UPDATES" | "GUILD_TEMPLATE_ACCEPT" | "GUILD_TEMPLATE_ACCEPT_FAILURE" | "GUILD_TEMPLATE_ACCEPT_SUCCESS" | "GUILD_TEMPLATE_CREATE_SUCCESS" | "GUILD_TEMPLATE_DELETE_SUCCESS" | "GUILD_TEMPLATE_DIRTY_TOOLTIP_HIDE" | "GUILD_TEMPLATE_DIRTY_TOOLTIP_REFRESH" | "GUILD_TEMPLATE_LOAD_FOR_GUILD_SUCCESS" | "GUILD_TEMPLATE_MODAL_HIDE" | "GUILD_TEMPLATE_MODAL_SHOW" | "GUILD_TEMPLATE_PROMOTION_TOOLTIP_HIDE" | "GUILD_TEMPLATE_RESOLVE" | "GUILD_TEMPLATE_RESOLVE_FAILURE" | "GUILD_TEMPLATE_RESOLVE_SUCCESS" | "GUILD_TEMPLATE_SYNC_SUCCESS" | "GUILD_TOGGLE_COLLAPSE_MUTED" | "GUILD_UNAPPLY_BOOST_FAIL" | "GUILD_UNAPPLY_BOOST_START" | "GUILD_UNAPPLY_BOOST_SUCCESS" | "GUILD_UNAVAILABLE" | "GUILD_UPDATE" | "GUILD_UPDATE_DISCOVERY_METADATA" | "GUILD_UPDATE_DISCOVERY_METADATA_FAIL" | "GUILD_UPDATE_DISCOVERY_METADATA_FROM_SERVER" | "GUILD_VERIFICATION_CHECK" | "HABITUAL_DND_CLEAR" | "HIDE_ACTION_SHEET" | "HIDE_ACTION_SHEET_QUICK_SWITCHER" | "HIDE_KEYBOARD_SHORTCUTS" | "HIGH_FIVE_COMPLETE" | "HIGH_FIVE_COMPLETE_CLEAR" | "HIGH_FIVE_QUEUE" | "HIGH_FIVE_REMOVE" | "HIGH_FIVE_SET_ENABLED" | "HOTSPOT_HIDE" | "HOTSPOT_OVERRIDE_CLEAR" | "HOTSPOT_OVERRIDE_SET" | "HYPESQUAD_ONLINE_MEMBERSHIP_JOIN_SUCCESS" | "HYPESQUAD_ONLINE_MEMBERSHIP_LEAVE_SUCCESS" | "I18N_LOAD_ERROR" | "I18N_LOAD_START" | "I18N_LOAD_SUCCESS" | "IDLE" | "IMPERSONATE_STOP" | "IMPERSONATE_UPDATE" | "INBOX_OPEN" | "INCOMING_CALL_MOVE" | "INITIALIZE_MEMBER_SAFETY_STORE" | "INSTALLATION_LOCATION_ADD" | "INSTALLATION_LOCATION_FETCH_METADATA" | "INSTALLATION_LOCATION_REMOVE" | "INSTALLATION_LOCATION_UPDATE" | "INSTANT_INVITE_CLEAR" | "INSTANT_INVITE_CREATE" | "INSTANT_INVITE_CREATE_FAILURE" | "INSTANT_INVITE_CREATE_SUCCESS" | "INSTANT_INVITE_REVOKE_SUCCESS" | "INTEGRATION_CREATE" | "INTEGRATION_DELETE" | "INTEGRATION_QUERY" | "INTEGRATION_QUERY_FAILURE" | "INTEGRATION_QUERY_SUCCESS" | "INTEGRATION_SETTINGS_INIT" | "INTEGRATION_SETTINGS_SAVE_FAILURE" | "INTEGRATION_SETTINGS_SAVE_SUCCESS" | "INTEGRATION_SETTINGS_SET_SECTION" | "INTEGRATION_SETTINGS_START_EDITING_WEBHOOK" | "INTEGRATION_SETTINGS_STOP_EDITING_WEBHOOK" | "INTEGRATION_SETTINGS_SUBMITTING" | "INTEGRATION_SETTINGS_UPDATE_WEBHOOK" | "INTERACTION_CREATE" | "INTERACTION_FAILURE" | "INTERACTION_IFRAME_MODAL_CLOSE" | "INTERACTION_IFRAME_MODAL_CREATE" | "INTERACTION_IFRAME_MODAL_KEY_CREATE" | "INTERACTION_MODAL_CREATE" | "INTERACTION_QUEUE" | "INTERACTION_SUCCESS" | "INVITE_ACCEPT" | "INVITE_ACCEPT_FAILURE" | "INVITE_ACCEPT_SUCCESS" | "INVITE_APP_NOT_OPENED" | "INVITE_APP_OPENED" | "INVITE_APP_OPENING" | "INVITE_MODAL_CLOSE" | "INVITE_MODAL_ERROR" | "INVITE_MODAL_OPEN" | "INVITE_RESOLVE" | "INVITE_RESOLVE_FAILURE" | "INVITE_RESOLVE_SUCCESS" | "KEYBINDS_ADD_KEYBIND" | "KEYBINDS_DELETE_KEYBIND" | "KEYBINDS_ENABLE_ALL_KEYBINDS" | "KEYBINDS_REGISTER_GLOBAL_KEYBIND_ACTIONS" | "KEYBINDS_SET_KEYBIND" | "KEYBOARD_NAVIGATION_EXPLAINER_MODAL_SEEN" | "LAYER_POP" | "LAYER_POP_ALL" | "LAYER_PUSH" | "LAYOUT_CREATE" | "LAYOUT_CREATE_WIDGETS" | "LAYOUT_DELETE_ALL_WIDGETS" | "LAYOUT_DELETE_WIDGET" | "LAYOUT_SET_PINNED" | "LAYOUT_SET_TOP_WIDGET" | "LAYOUT_UPDATE_WIDGET" | "LIBRARY_APPLICATIONS_TEST_MODE_ENABLED" | "LIBRARY_APPLICATION_ACTIVE_BRANCH_UPDATE" | "LIBRARY_APPLICATION_ACTIVE_LAUNCH_OPTION_UPDATE" | "LIBRARY_APPLICATION_FILTER_UPDATE" | "LIBRARY_APPLICATION_FLAGS_UPDATE_START" | "LIBRARY_APPLICATION_FLAGS_UPDATE_SUCCESS" | "LIBRARY_APPLICATION_UPDATE" | "LIBRARY_FETCH_SUCCESS" | "LIBRARY_TABLE_ACTIVE_ROW_ID_UPDATE" | "LIBRARY_TABLE_SORT_UPDATE" | "LIGHTNING_CHECKOUT_CLOSE" | "LIGHTNING_CHECKOUT_OPEN" | "LIVE_CHANNEL_NOTICE_HIDE" | "LOAD_ARCHIVED_THREADS" | "LOAD_ARCHIVED_THREADS_FAIL" | "LOAD_ARCHIVED_THREADS_SUCCESS" | "LOAD_CHANNELS" | "LOAD_FORUM_POSTS" | "LOAD_FRIEND_SUGGESTIONS_FAILURE" | "LOAD_FRIEND_SUGGESTIONS_SUCCESS" | "LOAD_GUILD_AFFINITIES_SUCCESS" | "LOAD_MESSAGES" | "LOAD_MESSAGES_AROUND_SUCCESS" | "LOAD_MESSAGES_FAILURE" | "LOAD_MESSAGES_SUCCESS" | "LOAD_MESSAGES_SUCCESS_CACHED" | "LOAD_MESSAGE_INTERACTION_DATA_SUCCESS" | "LOAD_MESSAGE_REQUESTS_SUPPLEMENTAL_DATA_ERROR" | "LOAD_MESSAGE_REQUESTS_SUPPLEMENTAL_DATA_SUCCESS" | "LOAD_NOTIFICATION_CENTER_ITEMS" | "LOAD_NOTIFICATION_CENTER_ITEMS_FAILURE" | "LOAD_NOTIFICATION_CENTER_ITEMS_SUCCESS" | "LOAD_PINNED_MESSAGES" | "LOAD_PINNED_MESSAGES_FAILURE" | "LOAD_PINNED_MESSAGES_SUCCESS" | "LOAD_RECENT_MENTIONS" | "LOAD_RECENT_MENTIONS_FAILURE" | "LOAD_RECENT_MENTIONS_SUCCESS" | "LOAD_REGIONS" | "LOAD_RELATIONSHIPS_FAILURE" | "LOAD_RELATIONSHIPS_SUCCESS" | "LOAD_THREADS_SUCCESS" | "LOAD_USER_AFFINITIES" | "LOAD_USER_AFFINITIES_FAILURE" | "LOAD_USER_AFFINITIES_SUCCESS" | "LOCAL_ACTIVITY_UPDATE" | "LOCAL_MESSAGES_LOADED" | "LOCAL_MESSAGE_CREATE" | "LOGIN" | "LOGIN_ACCOUNT_DISABLED" | "LOGIN_ACCOUNT_SCHEDULED_FOR_DELETION" | "LOGIN_ATTEMPTED" | "LOGIN_FAILURE" | "LOGIN_MFA" | "LOGIN_MFA_FAILURE" | "LOGIN_MFA_SMS" | "LOGIN_MFA_SMS_FAILURE" | "LOGIN_MFA_SMS_REQUEST_SUCCESS" | "LOGIN_MFA_STEP" | "LOGIN_PASSWORD_RECOVERY_PHONE_VERIFICATION" | "LOGIN_PHONE_IP_AUTHORIZATION_REQUIRED" | "LOGIN_RESET" | "LOGIN_STATUS_RESET" | "LOGIN_SUCCESS" | "LOGIN_SUSPENDED_USER" | "LOGOUT" | "LOGOUT_AUTH_SESSIONS_SUCCESS" | "MASKED_LINK_ADD_TRUSTED_DOMAIN" | "MASKED_LINK_ADD_TRUSTED_PROTOCOL" | "MAX_MEMBER_COUNT_NOTICE_DISMISS" | "MEDIA_ENGINE_APPLY_MEDIA_FILTER_SETTINGS" | "MEDIA_ENGINE_APPLY_MEDIA_FILTER_SETTINGS_ERROR" | "MEDIA_ENGINE_APPLY_MEDIA_FILTER_SETTINGS_START" | "MEDIA_ENGINE_DEVICES" | "MEDIA_ENGINE_INTERACTION_REQUIRED" | "MEDIA_ENGINE_NOISE_CANCELLATION_ERROR_RESET" | "MEDIA_ENGINE_PERMISSION" | "MEDIA_ENGINE_SET_AEC_DUMP" | "MEDIA_ENGINE_SET_AUDIO_ENABLED" | "MEDIA_ENGINE_SET_EXPERIMENTAL_ENCODERS" | "MEDIA_ENGINE_SET_EXPERIMENTAL_SOUNDSHARE" | "MEDIA_ENGINE_SET_GO_LIVE_SOURCE" | "MEDIA_ENGINE_SET_HARDWARE_H264" | "MEDIA_ENGINE_SET_OPEN_H264" | "MEDIA_ENGINE_SET_VIDEO_DEVICE" | "MEDIA_ENGINE_SET_VIDEO_ENABLED" | "MEDIA_ENGINE_SET_VIDEO_HOOK" | "MEDIA_ENGINE_SOUNDSHARE_FAILED" | "MEDIA_ENGINE_SOUNDSHARE_TRANSMITTING" | "MEDIA_ENGINE_VIDEO_SOURCE_QUALITY_CHANGED" | "MEDIA_ENGINE_VIDEO_STATE_CHANGED" | "MEDIA_POST_EMBED_FETCH" | "MEDIA_POST_EMBED_FETCH_FAILURE" | "MEDIA_POST_EMBED_FETCH_SUCCESS" | "MEDIA_SESSION_JOINED" | "MEMBER_SAFETY_GUILD_MEMBER_SEARCH_SUCCESS" | "MEMBER_SAFETY_GUILD_MEMBER_UPDATE_BATCH" | "MEMBER_SAFETY_NEW_MEMBER_TIMESTAMP_REFRESH" | "MEMBER_SAFETY_PAGINATION_TOKEN_UPDATE" | "MEMBER_SAFETY_PAGINATION_UPDATE" | "MEMBER_SAFETY_SEARCH_STATE_UPDATE" | "MEMBER_VERIFICATION_FORM_FETCH_FAIL" | "MEMBER_VERIFICATION_FORM_UPDATE" | "MENTION_MODAL_CLOSE" | "MENTION_MODAL_OPEN" | "MESSAGE_ACK" | "MESSAGE_ACKED" | "MESSAGE_CREATE" | "MESSAGE_DELETE" | "MESSAGE_DELETE_BULK" | "MESSAGE_EDIT_FAILED_AUTOMOD" | "MESSAGE_END_EDIT" | "MESSAGE_EXPLICIT_CONTENT_FP_CREATE" | "MESSAGE_EXPLICIT_CONTENT_FP_SUBMIT" | "MESSAGE_EXPLICIT_CONTENT_SCAN_TIMEOUT" | "MESSAGE_LENGTH_UPSELL" | "MESSAGE_NOTIFICATION_SHOWN" | "MESSAGE_PREVIEWS_LOADED" | "MESSAGE_PREVIEWS_LOCALLY_LOADED" | "MESSAGE_REACTION_ADD" | "MESSAGE_REACTION_ADD_MANY" | "MESSAGE_REACTION_ADD_USERS" | "MESSAGE_REACTION_REMOVE" | "MESSAGE_REACTION_REMOVE_ALL" | "MESSAGE_REACTION_REMOVE_EMOJI" | "MESSAGE_REMINDER_NOTIFIED" | "MESSAGE_REMINDER_TOGGLE" | "MESSAGE_REQUEST_ACCEPT_OPTIMISTIC" | "MESSAGE_REVEAL" | "MESSAGE_SEND_FAILED" | "MESSAGE_SEND_FAILED_AUTOMOD" | "MESSAGE_START_EDIT" | "MESSAGE_UPDATE" | "MESSAGE_UPDATE_EDIT" | "MFA_CLEAR_BACKUP_CODES" | "MFA_DISABLE_SUCCESS" | "MFA_ENABLE_EMAIL_TOKEN" | "MFA_ENABLE_SUCCESS" | "MFA_SEEN_BACKUP_CODE_PROMPT" | "MFA_SEND_VERIFICATION_KEY" | "MFA_SMS_TOGGLE" | "MFA_SMS_TOGGLE_COMPLETE" | "MFA_VIEW_BACKUP_CODES" | "MFA_WEBAUTHN_CREDENTIALS_LOADED" | "MFA_WEBAUTHN_CREDENTIALS_LOADING" | "MOBILE_NATIVE_UPDATE_CHECK_FINISHED" | "MOBILE_WEB_SIDEBAR_CLOSE" | "MOBILE_WEB_SIDEBAR_OPEN" | "MODAL_POP" | "MODAL_PUSH" | "MOD_VIEW_SEARCH_FINISH" | "MULTI_ACCOUNT_INVALIDATE_PUSH_SYNC_TOKENS" | "MULTI_ACCOUNT_MOBILE_EXPERIMENT_UPDATE" | "MULTI_ACCOUNT_MOVE_ACCOUNT" | "MULTI_ACCOUNT_REMOVE_ACCOUNT" | "MULTI_ACCOUNT_UPDATE_PUSH_SYNC_TOKEN" | "MULTI_ACCOUNT_VALIDATE_TOKEN_FAILURE" | "MULTI_ACCOUNT_VALIDATE_TOKEN_REQUEST" | "MULTI_ACCOUNT_VALIDATE_TOKEN_SUCCESS" | "MUTUAL_FRIENDS_FETCH_FAILURE" | "MUTUAL_FRIENDS_FETCH_START" | "MUTUAL_FRIENDS_FETCH_SUCCESS" | "NEWLY_ADDED_EMOJI_SEEN_ACKNOWLEDGED" | "NEWLY_ADDED_EMOJI_SEEN_PENDING" | "NEWLY_ADDED_EMOJI_SEEN_UPDATED" | "NEW_PAYMENT_SOURCE_ADDRESS_INFO_UPDATE" | "NEW_PAYMENT_SOURCE_CARD_INFO_UPDATE" | "NEW_PAYMENT_SOURCE_CLEAR_ERROR" | "NEW_PAYMENT_SOURCE_STRIPE_PAYMENT_REQUEST_UPDATE" | "NOTICE_DISABLE" | "NOTICE_DISMISS" | "NOTICE_SHOW" | "NOTIFICATIONS_SET_DESKTOP_TYPE" | "NOTIFICATIONS_SET_DISABLED_SOUNDS" | "NOTIFICATIONS_SET_DISABLE_UNREAD_BADGE" | "NOTIFICATIONS_SET_NOTIFY_MESSAGES_IN_SELECTED_CHANNEL" | "NOTIFICATIONS_SET_PERMISSION_STATE" | "NOTIFICATIONS_SET_TASKBAR_FLASH" | "NOTIFICATIONS_SET_TTS_TYPE" | "NOTIFICATIONS_TOGGLE_ALL_DISABLED" | "NOTIFICATION_CENTER_CLEAR_GUILD_MENTIONS" | "NOTIFICATION_CENTER_ITEMS_ACK" | "NOTIFICATION_CENTER_ITEMS_ACK_FAILURE" | "NOTIFICATION_CENTER_ITEMS_LOCAL_ACK" | "NOTIFICATION_CENTER_ITEM_COMPLETED" | "NOTIFICATION_CENTER_ITEM_CREATE" | "NOTIFICATION_CENTER_ITEM_DELETE" | "NOTIFICATION_CENTER_ITEM_DELETE_FAILURE" | "NOTIFICATION_CENTER_REFRESH" | "NOTIFICATION_CENTER_SET_ACTIVE" | "NOTIFICATION_CENTER_SET_TAB" | "NOTIFICATION_CENTER_TAB_FOCUSED" | "NOTIFICATION_CLICK" | "NOTIFICATION_CREATE" | "NOTIFICATION_SETTINGS_UPDATE" | "NOW_PLAYING_MOUNTED" | "NOW_PLAYING_UNMOUNTED" | "NUF_COMPLETE" | "NUF_NEW_USER" | "OAUTH2_TOKEN_REVOKE" | "ONLINE_GUILD_MEMBER_COUNT_UPDATE" | "OUTBOUND_PROMOTIONS_SEEN" | "OUTBOUND_PROMOTION_NOTICE_DISMISS" | "OVERLAY_ACTIVATE_REGION" | "OVERLAY_CALL_PRIVATE_CHANNEL" | "OVERLAY_CRASHED" | "OVERLAY_DEACTIVATE_ALL_REGIONS" | "OVERLAY_DISABLE_EXTERNAL_LINK_ALERT" | "OVERLAY_FOCUSED" | "OVERLAY_INCOMPATIBLE_APP" | "OVERLAY_INITIALIZE" | "OVERLAY_JOIN_GAME" | "OVERLAY_MESSAGE_EVENT_ACTION" | "OVERLAY_NOTIFICATION_EVENT" | "OVERLAY_NOTIFY_READY_TO_SHOW" | "OVERLAY_READY" | "OVERLAY_SELECT_CALL" | "OVERLAY_SELECT_CHANNEL" | "OVERLAY_SET_ASSOCIATED_GAME" | "OVERLAY_SET_AVATAR_SIZE_MODE" | "OVERLAY_SET_CLICK_ZONES" | "OVERLAY_SET_DISPLAY_NAME_MODE" | "OVERLAY_SET_DISPLAY_USER_MODE" | "OVERLAY_SET_ENABLED" | "OVERLAY_SET_INPUT_LOCKED" | "OVERLAY_SET_NOTIFICATION_POSITION_MODE" | "OVERLAY_SET_NOT_IDLE" | "OVERLAY_SET_PREVIEW_IN_GAME_MODE" | "OVERLAY_SET_SHOW_KEYBIND_INDICATORS" | "OVERLAY_SET_TEXT_CHAT_NOTIFICATION_MODE" | "OVERLAY_SET_TEXT_WIDGET_OPACITY" | "OVERLAY_SET_UI_LOCKED" | "OVERLAY_SOUNDBOARD_SOUNDS_FETCH_REQUEST" | "OVERLAY_START_SESSION" | "OVERLAY_SUCCESSFULLY_SHOWN" | "OVERLAY_WIDGET_CHANGED" | "PASSIVE_UPDATE_V1" | "PASSWORD_UPDATED" | "PAYMENT_AUTHENTICATION_CLEAR_ERROR" | "PAYMENT_AUTHENTICATION_ERROR" | "PAYMENT_UPDATE" | "PERMISSION_CLEAR_ELEVATED_PROCESS" | "PERMISSION_CLEAR_PTT_ADMIN_WARNING" | "PERMISSION_CLEAR_SUPPRESS_WARNING" | "PERMISSION_CLEAR_VAD_WARNING" | "PERMISSION_CONTINUE_NONELEVATED_PROCESS" | "PERMISSION_REQUEST_ELEVATED_PROCESS" | "PHONE_SET_COUNTRY_CODE" | "PICTURE_IN_PICTURE_CLOSE" | "PICTURE_IN_PICTURE_HIDE" | "PICTURE_IN_PICTURE_MOVE" | "PICTURE_IN_PICTURE_OPEN" | "PICTURE_IN_PICTURE_SHOW" | "PICTURE_IN_PICTURE_UPDATE_RECT" | "PICTURE_IN_PICTURE_UPDATE_SELECTED_WINDOW" | "POGGERMODE_ACHIEVEMENT_UNLOCK" | "POGGERMODE_SETTINGS_UPDATE" | "POGGERMODE_TEMPORARILY_DISABLED" | "POGGERMODE_UPDATE_COMBO" | "POGGERMODE_UPDATE_MESSAGE_COMBO" | "POPOUT_WINDOW_CLOSE" | "POPOUT_WINDOW_OPEN" | "POPOUT_WINDOW_SET_ALWAYS_ON_TOP" | "POST_CONNECTION_OPEN" | "PREMIUM_MARKETING_DATA_READY" | "PREMIUM_MARKETING_PREVIEW" | "PREMIUM_PAYMENT_ERROR_CLEAR" | "PREMIUM_PAYMENT_MODAL_CLOSE" | "PREMIUM_PAYMENT_MODAL_OPEN" | "PREMIUM_PAYMENT_SUBSCRIBE_FAIL" | "PREMIUM_PAYMENT_SUBSCRIBE_START" | "PREMIUM_PAYMENT_SUBSCRIBE_SUCCESS" | "PREMIUM_PAYMENT_UPDATE_FAIL" | "PREMIUM_PAYMENT_UPDATE_SUCCESS" | "PREMIUM_PERKS_DEMOS_FETCH_FAILURE" | "PREMIUM_PERKS_DEMOS_FETCH_SUCCESS" | "PREMIUM_PERKS_DEMO_ACTIVATE_FAILURE" | "PREMIUM_PERKS_DEMO_ACTIVATE_SUCCESS" | "PREMIUM_PERKS_DEMO_COMPLETE" | "PREMIUM_PERKS_DEMO_OVERRIDE" | "PREMIUM_REQUIRED_MODAL_CLOSE" | "PREMIUM_REQUIRED_MODAL_OPEN" | "PRESENCES_REPLACE" | "PRESENCE_UPDATES" | "PRIVATE_CHANNEL_INTEGRATION_CREATE" | "PRIVATE_CHANNEL_INTEGRATION_DELETE" | "PRIVATE_CHANNEL_INTEGRATION_UPDATE" | "PRIVATE_CHANNEL_RECIPIENTS_ADD_USER" | "PRIVATE_CHANNEL_RECIPIENTS_INVITE_CLOSE" | "PRIVATE_CHANNEL_RECIPIENTS_INVITE_OPEN" | "PRIVATE_CHANNEL_RECIPIENTS_INVITE_QUERY" | "PRIVATE_CHANNEL_RECIPIENTS_INVITE_SELECT" | "PRIVATE_CHANNEL_RECIPIENTS_REMOVE_USER" | "PROFILE_CUSTOMIZATION_OPEN_PREVIEW_MODAL" | "PROFILE_EFFECTS_SET_TRY_IT_OUT" | "PROFILE_PANEL_TOGGLE_SECTION" | "PROXY_BLOCKED_REQUEST" | "PUBLIC_UPSELL_NOTICE_DISMISS" | "PURCHASED_ITEMS_FESTIVITY_FETCH_WOW_MOMENT_MEDIA_SUCCESS" | "PURCHASED_ITEMS_FESTIVITY_IS_FETCHING_WOW_MOMENT_MEDIA" | "PURCHASED_ITEMS_FESTIVITY_SET_CAN_PLAY_WOW_MOMENT" | "PURCHASE_CONFIRMATION_MODAL_CLOSE" | "PURCHASE_CONFIRMATION_MODAL_OPEN" | "PUSH_NOTIFICATION_CLICK" | "QUESTS_CLAIM_REWARD_BEGIN" | "QUESTS_CLAIM_REWARD_CODE_BEGIN" | "QUESTS_CLAIM_REWARD_CODE_FAILURE" | "QUESTS_CLAIM_REWARD_CODE_SUCCESS" | "QUESTS_CLAIM_REWARD_FAILURE" | "QUESTS_CLAIM_REWARD_SUCCESS" | "QUESTS_DELIVERY_OVERRIDE" | "QUESTS_DISMISS_CONTENT_BEGIN" | "QUESTS_DISMISS_CONTENT_FAILURE" | "QUESTS_DISMISS_CONTENT_SUCCESS" | "QUESTS_DISMISS_PROGRESS_TRACKING_FAILURE_NOTICE" | "QUESTS_ENROLL_BEGIN" | "QUESTS_ENROLL_FAILURE" | "QUESTS_ENROLL_SUCCESS" | "QUESTS_FETCH_CURRENT_QUESTS_BEGIN" | "QUESTS_FETCH_CURRENT_QUESTS_FAILURE" | "QUESTS_FETCH_CURRENT_QUESTS_SUCCESS" | "QUESTS_FETCH_REWARD_CODE_BEGIN" | "QUESTS_FETCH_REWARD_CODE_FAILURE" | "QUESTS_FETCH_REWARD_CODE_SUCCESS" | "QUESTS_OPTIMISTIC_PROGRESS_UPDATE" | "QUESTS_PREVIEW_UPDATE_SUCCESS" | "QUESTS_SEND_HEARTBEAT_FAILURE" | "QUESTS_SEND_HEARTBEAT_SUCCESS" | "QUEUE_INTERACTION_COMPONENT_STATE" | "QUICKSWITCHER_HIDE" | "QUICKSWITCHER_SEARCH" | "QUICKSWITCHER_SELECT" | "QUICKSWITCHER_SHOW" | "QUICKSWITCHER_SWITCH_TO" | "RECEIVE_CHANNEL_AFFINITIES" | "RECEIVE_CHANNEL_SUMMARIES" | "RECEIVE_CHANNEL_SUMMARIES_BULK" | "RECEIVE_CHANNEL_SUMMARY" | "RECENT_MENTION_DELETE" | "RECOMPUTE_READ_STATES" | "REFERRALS_FETCH_ELIGIBLE_USER_FAIL" | "REFERRALS_FETCH_ELIGIBLE_USER_START" | "REFERRALS_FETCH_ELIGIBLE_USER_SUCCESS" | "REGISTER" | "REGISTER_FAILURE" | "REGISTER_SAVE_FORM" | "REGISTER_SUCCESS" | "RELATIONSHIP_ADD" | "RELATIONSHIP_PENDING_INCOMING_REMOVED" | "RELATIONSHIP_REMOVE" | "RELATIONSHIP_UPDATE" | "REMOTE_COMMAND" | "REMOTE_SESSION_CONNECT" | "REMOTE_SESSION_DISCONNECT" | "REMOVE_AUTOMOD_MESSAGE_NOTICE" | "REQUEST_CHANNEL_AFFINITIES" | "REQUEST_CHANNEL_SUMMARIES" | "REQUEST_CHANNEL_SUMMARIES_BULK" | "REQUEST_CHANNEL_SUMMARY" | "REQUEST_FORUM_UNREADS" | "REQUEST_SOUNDBOARD_SOUNDS" | "RESET_NOTIFICATION_CENTER" | "RESET_PAYMENT_ID" | "RESET_PREVIEW_CLIENT_THEME" | "RESET_SOCKET" | "RESORT_THREADS" | "RPC_APP_AUTHENTICATED" | "RPC_APP_CONNECTED" | "RPC_APP_DISCONNECTED" | "RPC_NOTIFICATION_CREATE" | "RPC_SERVER_READY" | "RTC_CONNECTION_FLAGS" | "RTC_CONNECTION_LOSS_RATE" | "RTC_CONNECTION_PING" | "RTC_CONNECTION_PLATFORM" | "RTC_CONNECTION_STATE" | "RTC_CONNECTION_UPDATE_ID" | "RTC_CONNECTION_USER_CREATE" | "RTC_CONNECTION_VIDEO" | "RTC_DEBUG_MODAL_CLOSE" | "RTC_DEBUG_MODAL_OPEN" | "RTC_DEBUG_MODAL_OPEN_REPLAY" | "RTC_DEBUG_MODAL_OPEN_REPLAY_AT_PATH" | "RTC_DEBUG_MODAL_SET_SECTION" | "RTC_DEBUG_MODAL_UPDATE" | "RTC_DEBUG_MODAL_UPDATE_VIDEO_OUTPUT" | "RTC_DEBUG_POPOUT_WINDOW_OPEN" | "RTC_DEBUG_SET_RECORDING_FLAG" | "RTC_LATENCY_TEST_COMPLETE" | "RTC_SPEED_TEST_START_TEST" | "RTC_SPEED_TEST_STOP_TEST" | "RUNNING_GAMES_CHANGE" | "RUNNING_GAME_ADD_OVERRIDE" | "RUNNING_GAME_DELETE_ENTRY" | "RUNNING_GAME_EDIT_NAME" | "RUNNING_GAME_TOGGLE_DETECTION" | "RUNNING_GAME_TOGGLE_OVERLAY" | "RUNNING_STREAMER_TOOLS_CHANGE" | "SAFETY_HUB_APPEAL_CLOSE" | "SAFETY_HUB_APPEAL_OPEN" | "SAFETY_HUB_APPEAL_SIGNAL_CUSTOM_INPUT_CHANGE" | "SAFETY_HUB_APPEAL_SIGNAL_SELECT" | "SAFETY_HUB_FETCH_CLASSIFICATION_FAILURE" | "SAFETY_HUB_FETCH_CLASSIFICATION_START" | "SAFETY_HUB_FETCH_CLASSIFICATION_SUCCESS" | "SAFETY_HUB_FETCH_FAILURE" | "SAFETY_HUB_FETCH_START" | "SAFETY_HUB_FETCH_SUCCESS" | "SAFETY_HUB_REQUEST_REVIEW_FAILURE" | "SAFETY_HUB_REQUEST_REVIEW_START" | "SAFETY_HUB_REQUEST_REVIEW_SUCCESS" | "SAVED_MESSAGES_UPDATE" | "SAVE_LAST_NON_VOICE_ROUTE" | "SAVE_LAST_ROUTE" | "SEARCH_ADD_HISTORY" | "SEARCH_AUTOCOMPLETE_QUERY_UPDATE" | "SEARCH_CLEAR_HISTORY" | "SEARCH_EDITOR_STATE_CHANGE" | "SEARCH_EDITOR_STATE_CLEAR" | "SEARCH_ENSURE_SEARCH_STATE" | "SEARCH_FINISH" | "SEARCH_INDEXING" | "SEARCH_MODAL_CLOSE" | "SEARCH_MODAL_OPEN" | "SEARCH_REMOVE_HISTORY" | "SEARCH_SCREEN_OPEN" | "SEARCH_SET_SHOW_BLOCKED_RESULTS" | "SEARCH_START" | "SELECTIVELY_SYNCED_USER_SETTINGS_UPDATE" | "SELECT_HOME_RESOURCE_CHANNEL" | "SELECT_NEW_MEMBER_ACTION_CHANNEL" | "SELF_PRESENCE_STORE_UPDATE" | "SESSIONS_REPLACE" | "SET_CHANNEL_BITRATE" | "SET_CHANNEL_VIDEO_QUALITY_MODE" | "SET_CONSENT_REQUIRED" | "SET_CREATED_AT_OVERRIDE" | "SET_GUILD_FOLDER_EXPANDED" | "SET_HIGHLIGHTED_SUMMARY" | "SET_INTERACTION_COMPONENT_STATE" | "SET_LOCATION_METADATA" | "SET_LOGIN_CREDENTIALS" | "SET_NATIVE_PERMISSION" | "SET_PENDING_REPLY_SHOULD_MENTION" | "SET_PREMIUM_TYPE_OVERRIDE" | "SET_RECENTLY_ACTIVE_COLLAPSED" | "SET_RECENT_MENTIONS_FILTER" | "SET_RECENT_MENTIONS_STALE" | "SET_SELECTED_SUMMARY" | "SET_SOUNDPACK" | "SET_STREAM_APP_INTENT" | "SET_SUMMARY_FEEDBACK" | "SET_TTS_SPEECH_RATE" | "SET_VAD_PERMISSION" | "SHARED_CANVAS_CLEAR_DRAWABLES" | "SHARED_CANVAS_DRAW_LINE_POINT" | "SHARED_CANVAS_SET_DRAW_MODE" | "SHARED_CANVAS_UPDATE_EMOJI_HOSE" | "SHARED_CANVAS_UPDATE_LINE_POINTS" | "SHOW_ACTION_SHEET" | "SHOW_ACTION_SHEET_QUICK_SWITCHER" | "SHOW_KEYBOARD_SHORTCUTS" | "SIDEBAR_CLOSE" | "SIDEBAR_CLOSE_GUILD" | "SIDEBAR_CREATE_THREAD" | "SIDEBAR_VIEW_CHANNEL" | "SIDEBAR_VIEW_GUILD" | "SKUS_FETCH_SUCCESS" | "SKU_FETCH_FAIL" | "SKU_FETCH_START" | "SKU_FETCH_SUCCESS" | "SKU_PURCHASE_AWAIT_CONFIRMATION" | "SKU_PURCHASE_CLEAR_ERROR" | "SKU_PURCHASE_FAIL" | "SKU_PURCHASE_MODAL_CLOSE" | "SKU_PURCHASE_MODAL_OPEN" | "SKU_PURCHASE_PREVIEW_FETCH" | "SKU_PURCHASE_PREVIEW_FETCH_FAILURE" | "SKU_PURCHASE_PREVIEW_FETCH_SUCCESS" | "SKU_PURCHASE_SHOW_CONFIRMATION_STEP" | "SKU_PURCHASE_START" | "SKU_PURCHASE_SUCCESS" | "SKU_PURCHASE_UPDATE_IS_GIFT" | "SLOWMODE_RESET_COOLDOWN" | "SLOWMODE_SET_COOLDOWN" | "SOUNDBOARD_FETCH_DEFAULT_SOUNDS" | "SOUNDBOARD_FETCH_DEFAULT_SOUNDS_SUCCESS" | "SOUNDBOARD_MUTE_JOIN_SOUND" | "SOUNDBOARD_SET_OVERLAY_ENABLED" | "SOUNDBOARD_SOUNDS_RECEIVED" | "SPEAKING" | "SPEAKING_MESSAGE" | "SPEAK_MESSAGE" | "SPEAK_TEXT" | "SPEED_TEST_CREATE" | "SPEED_TEST_DELETE" | "SPEED_TEST_SERVER_UPDATE" | "SPELLCHECK_LEARN_WORD" | "SPELLCHECK_TOGGLE" | "SPELLCHECK_UNLEARN_WORD" | "SPOTIFY_ACCOUNT_ACCESS_TOKEN" | "SPOTIFY_ACCOUNT_ACCESS_TOKEN_REVOKE" | "SPOTIFY_NEW_TRACK" | "SPOTIFY_PLAYER_PAUSE" | "SPOTIFY_PLAYER_PLAY" | "SPOTIFY_PLAYER_STATE" | "SPOTIFY_PROFILE_UPDATE" | "SPOTIFY_SET_ACTIVE_DEVICE" | "SPOTIFY_SET_DEVICES" | "SPOTIFY_SET_PROTOCOL_REGISTERED" | "STAGE_INSTANCE_CREATE" | "STAGE_INSTANCE_DELETE" | "STAGE_INSTANCE_UPDATE" | "STAGE_MUSIC_MUTE" | "STAGE_MUSIC_PLAY" | "START_BROADCAST_STREAM" | "START_SESSION" | "STATUS_PAGE_INCIDENT" | "STATUS_PAGE_SCHEDULED_MAINTENANCE" | "STATUS_PAGE_SCHEDULED_MAINTENANCE_ACK" | "STICKER_FETCH_SUCCESS" | "STICKER_PACKS_FETCH_START" | "STICKER_PACKS_FETCH_SUCCESS" | "STICKER_PACK_FETCH_SUCCESS" | "STICKER_TRACK_USAGE" | "STOP_SPEAKING" | "STORE_LISTINGS_FETCH_SUCCESS" | "STORE_LISTING_FETCH_SUCCESS" | "STREAMER_MODE_UPDATE" | "STREAMING_UPDATE" | "STREAM_CLOSE" | "STREAM_CREATE" | "STREAM_DELETE" | "STREAM_LAYOUT_UPDATE" | "STREAM_PREVIEW_FETCH_FAIL" | "STREAM_PREVIEW_FETCH_START" | "STREAM_PREVIEW_FETCH_SUCCESS" | "STREAM_SERVER_UPDATE" | "STREAM_SET_PAUSED" | "STREAM_START" | "STREAM_STATS_UPDATE" | "STREAM_STOP" | "STREAM_TIMED_OUT" | "STREAM_UPDATE" | "STREAM_UPDATE_SELF_HIDDEN" | "STREAM_UPDATE_SETTINGS" | "STREAM_WATCH" | "STRIPE_TOKEN_FAILURE" | "SUBSCRIPTION_PLANS_FETCH" | "SUBSCRIPTION_PLANS_FETCH_FAILURE" | "SUBSCRIPTION_PLANS_FETCH_SUCCESS" | "SUBSCRIPTION_PLANS_RESET" | "SURVEY_FETCHED" | "SURVEY_HIDE" | "SURVEY_OVERRIDE" | "SURVEY_SEEN" | "SYSTEM_THEME_CHANGE" | "THERMAL_STATE_CHANGE" | "THREAD_CREATE" | "THREAD_CREATE_LOCAL" | "THREAD_DELETE" | "THREAD_LIST_SYNC" | "THREAD_MEMBERS_UPDATE" | "THREAD_MEMBER_LIST_UPDATE" | "THREAD_MEMBER_LOCAL_UPDATE" | "THREAD_MEMBER_UPDATE" | "THREAD_SETTINGS_DRAFT_CHANGE" | "THREAD_UPDATE" | "TOGGLE_GUILD_FOLDER_EXPAND" | "TOGGLE_OVERLAY_CANVAS" | "TOGGLE_TOPICS_BAR" | "TOP_EMOJIS_FETCH" | "TOP_EMOJIS_FETCH_SUCCESS" | "TRUNCATE_MENTIONS" | "TRUNCATE_MESSAGES" | "TRY_ACK" | "TUTORIAL_INDICATOR_DISMISS" | "TUTORIAL_INDICATOR_HIDE" | "TUTORIAL_INDICATOR_SHOW" | "TUTORIAL_INDICATOR_SUPPRESS_ALL" | "TYPING_START" | "TYPING_START_LOCAL" | "TYPING_STOP" | "TYPING_STOP_LOCAL" | "UNREAD_SETTING_NOTICE_CHANNEL_VISIT" | "UNREAD_SETTING_NOTICE_RENDERED" | "UNSYNCED_USER_SETTINGS_UPDATE" | "UNVERIFIED_GAME_UPDATE" | "UPCOMING_GUILD_EVENT_NOTICE_HIDE" | "UPCOMING_GUILD_EVENT_NOTICE_SEEN" | "UPDATE_AVAILABLE" | "UPDATE_BACKGROUND_GRADIENT_PRESET" | "UPDATE_CHANNEL_DIMENSIONS" | "UPDATE_CHANNEL_LIST_DIMENSIONS" | "UPDATE_CHANNEL_LIST_SUBTITLES" | "UPDATE_CLIENT_PREMIUM_TYPE" | "UPDATE_CONSENTS" | "UPDATE_DOWNLOADED" | "UPDATE_ERROR" | "UPDATE_GUILD_LIST_DIMENSIONS" | "UPDATE_HANG_STATUS" | "UPDATE_HANG_STATUS_CUSTOM" | "UPDATE_MANUALLY" | "UPDATE_MOBILE_PENDING_THEME_INDEX" | "UPDATE_NOT_AVAILABLE" | "UPDATE_TOKEN" | "UPDATE_VISIBLE_MESSAGES" | "UPLOAD_ATTACHMENT_ADD_FILES" | "UPLOAD_ATTACHMENT_CLEAR_ALL_FILES" | "UPLOAD_ATTACHMENT_POP_FILE" | "UPLOAD_ATTACHMENT_REMOVE_FILE" | "UPLOAD_ATTACHMENT_REMOVE_FILES" | "UPLOAD_ATTACHMENT_SET_FILE" | "UPLOAD_ATTACHMENT_SET_UPLOADS" | "UPLOAD_ATTACHMENT_UPDATE_FILE" | "UPLOAD_CANCEL_REQUEST" | "UPLOAD_COMPLETE" | "UPLOAD_COMPRESSION_PROGRESS" | "UPLOAD_FAIL" | "UPLOAD_FILE_UPDATE" | "UPLOAD_ITEM_CANCEL_REQUEST" | "UPLOAD_PROGRESS" | "UPLOAD_RESTORE_FAILED_UPLOAD" | "UPLOAD_START" | "USER_ACHIEVEMENT_UPDATE" | "USER_ACTIVITY_STATISTICS_FETCH_SUCCESS" | "USER_APPLICATION_REMOVE" | "USER_APPLICATION_UPDATE" | "USER_APPLIED_BOOSTS_FETCH_START" | "USER_APPLIED_BOOSTS_FETCH_SUCCESS" | "USER_AUTHORIZED_APPS_UPDATE" | "USER_CONNECTIONS_INTEGRATION_JOINING" | "USER_CONNECTIONS_INTEGRATION_JOINING_ERROR" | "USER_CONNECTIONS_UPDATE" | "USER_CONNECTION_UPDATE" | "USER_GUILD_JOIN_REQUEST_UPDATE" | "USER_GUILD_SETTINGS_CHANNEL_UPDATE" | "USER_GUILD_SETTINGS_CHANNEL_UPDATE_BULK" | "USER_GUILD_SETTINGS_FULL_UPDATE" | "USER_GUILD_SETTINGS_GUILD_AND_CHANNELS_UPDATE" | "USER_GUILD_SETTINGS_GUILD_UPDATE" | "USER_GUILD_SETTINGS_REMOVE_PENDING_CHANNEL_UPDATES" | "USER_JOIN_REQUEST_GUILDS_FETCH" | "USER_NON_CHANNEL_ACK" | "USER_NOTE_LOADED" | "USER_NOTE_LOAD_START" | "USER_NOTE_UPDATE" | "USER_PAYMENT_BROWSER_CHECKOUT_DONE" | "USER_PAYMENT_BROWSER_CHECKOUT_STARTED" | "USER_PAYMENT_CLIENT_ADD" | "USER_PROFILE_ACCESSIBILITY_TOOLTIP_VIEWED" | "USER_PROFILE_EFFECTS_FETCH" | "USER_PROFILE_EFFECTS_FETCH_FAILURE" | "USER_PROFILE_EFFECTS_FETCH_SUCCESS" | "USER_PROFILE_FETCH_FAILURE" | "USER_PROFILE_FETCH_START" | "USER_PROFILE_FETCH_SUCCESS" | "USER_PROFILE_MODAL_CLOSE" | "USER_PROFILE_MODAL_OPEN" | "USER_PROFILE_UPDATE_FAILURE" | "USER_PROFILE_UPDATE_START" | "USER_PROFILE_UPDATE_SUCCESS" | "USER_RECENT_GAMES_FETCH_ERROR" | "USER_RECENT_GAMES_FETCH_START" | "USER_RECENT_GAMES_FETCH_SUCCESS" | "USER_RECENT_GAMES_UPDATE_LOCAL" | "USER_REQUIRED_ACTION_UPDATE" | "USER_SETTINGS_ACCOUNT_CLOSE" | "USER_SETTINGS_ACCOUNT_INIT" | "USER_SETTINGS_ACCOUNT_RESET_AND_CLOSE_FORM" | "USER_SETTINGS_ACCOUNT_SET_PENDING_ACCENT_COLOR" | "USER_SETTINGS_ACCOUNT_SET_PENDING_AVATAR" | "USER_SETTINGS_ACCOUNT_SET_PENDING_AVATAR_DECORATION" | "USER_SETTINGS_ACCOUNT_SET_PENDING_BANNER" | "USER_SETTINGS_ACCOUNT_SET_PENDING_BIO" | "USER_SETTINGS_ACCOUNT_SET_PENDING_GLOBAL_NAME" | "USER_SETTINGS_ACCOUNT_SET_PENDING_PROFILE_EFFECT_ID" | "USER_SETTINGS_ACCOUNT_SET_PENDING_PRONOUNS" | "USER_SETTINGS_ACCOUNT_SET_PENDING_THEME_COLORS" | "USER_SETTINGS_ACCOUNT_SET_SINGLE_TRY_IT_OUT_COLLECTIBLES_ITEM" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_AVATAR" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_AVATAR_DECORATION" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_BANNER" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_PROFILE_EFFECT_ID" | "USER_SETTINGS_ACCOUNT_SET_TRY_IT_OUT_THEME_COLORS" | "USER_SETTINGS_ACCOUNT_SUBMIT" | "USER_SETTINGS_ACCOUNT_SUBMIT_FAILURE" | "USER_SETTINGS_ACCOUNT_SUBMIT_SUCCESS" | "USER_SETTINGS_CLEAR_ERRORS" | "USER_SETTINGS_LOCALE_OVERRIDE" | "USER_SETTINGS_MODAL_CLEAR_SCROLL_POSITION" | "USER_SETTINGS_MODAL_CLEAR_SUBSECTION" | "USER_SETTINGS_MODAL_CLOSE" | "USER_SETTINGS_MODAL_INIT" | "USER_SETTINGS_MODAL_OPEN" | "USER_SETTINGS_MODAL_RESET" | "USER_SETTINGS_MODAL_SET_SECTION" | "USER_SETTINGS_MODAL_SUBMIT" | "USER_SETTINGS_MODAL_SUBMIT_COMPLETE" | "USER_SETTINGS_MODAL_SUBMIT_FAILURE" | "USER_SETTINGS_MODAL_UPDATE_ACCOUNT" | "USER_SETTINGS_OVERRIDE_APPLY" | "USER_SETTINGS_OVERRIDE_CLEAR" | "USER_SETTINGS_PROTO_ENQUEUE_UPDATE" | "USER_SETTINGS_PROTO_LOAD_IF_NECESSARY" | "USER_SETTINGS_PROTO_UPDATE" | "USER_SETTINGS_PROTO_UPDATE_EDIT_INFO" | "USER_SETTINGS_RESET_ALL_PENDING" | "USER_SETTINGS_RESET_ALL_TRY_IT_OUT" | "USER_SETTINGS_RESET_PENDING_ACCOUNT_CHANGES" | "USER_SETTINGS_RESET_PENDING_AVATAR_DECORATION" | "USER_SETTINGS_RESET_PENDING_PROFILE_CHANGES" | "USER_SOUNDBOARD_SET_VOLUME" | "USER_TENURE_REWARD_STATUS_DELETE" | "USER_TENURE_REWARD_STATUS_RESET" | "USER_TENURE_REWARD_SYNC_START" | "USER_TENURE_REWARD_SYNC_SUCCESS" | "USER_UPDATE" | "VERIFY_FAILURE" | "VERIFY_SUCCESS" | "VIDEO_FILTER_ASSETS_FETCH_SUCCESS" | "VIDEO_FILTER_ASSET_DELETE_SUCCESS" | "VIDEO_FILTER_ASSET_UPLOAD_SUCCESS" | "VIDEO_SAVE_LAST_USED_BACKGROUND_OPTION" | "VIEW_HISTORY_MARK_VIEW" | "VOICE_CATEGORY_COLLAPSE" | "VOICE_CATEGORY_EXPAND" | "VOICE_CHANNEL_EFFECT_CLEAR" | "VOICE_CHANNEL_EFFECT_RECENT_EMOJI" | "VOICE_CHANNEL_EFFECT_SEND" | "VOICE_CHANNEL_EFFECT_SENT_LOCAL" | "VOICE_CHANNEL_EFFECT_TOGGLE_ANIMATION_TYPE" | "VOICE_CHANNEL_EFFECT_UPDATE_TIME_STAMP" | "VOICE_CHANNEL_SELECT" | "VOICE_CHANNEL_STATUS_UPDATE" | "VOICE_SERVER_UPDATE" | "VOICE_STATE_UPDATES" | "WAIT_FOR_REMOTE_SESSION" | "WEBHOOKS_FETCHING" | "WEBHOOKS_UPDATE" | "WEBHOOK_CREATE" | "WEBHOOK_DELETE" | "WEBHOOK_UPDATE" | "WELCOME_SCREEN_FETCH_FAIL" | "WELCOME_SCREEN_FETCH_START" | "WELCOME_SCREEN_FETCH_SUCCESS" | "WELCOME_SCREEN_SUBMIT_SUCCESS" | "WELCOME_SCREEN_UPDATE" | "WELCOME_SCREEN_VIEW" | "WINDOW_FOCUS" | "WINDOW_FULLSCREEN_CHANGE" | "WINDOW_HIDDEN" | "WINDOW_INIT" | "WINDOW_RESIZED" | "WINDOW_UNLOAD" | "WINDOW_VISIBILITY_CHANGE" | "WRITE_CACHES"; diff --git a/src/webpack/common/types/index.d.ts b/src/webpack/common/types/index.d.ts deleted file mode 100644 index 77148dd0..00000000 --- a/src/webpack/common/types/index.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2023 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -export * from "./classes"; -export * from "./components"; -export * from "./fluxEvents"; -export * from "./menu"; -export * from "./stores"; -export * from "./utils"; diff --git a/src/webpack/common/types/stores.d.ts b/src/webpack/common/types/stores.d.ts deleted file mode 100644 index f0235986..00000000 --- a/src/webpack/common/types/stores.d.ts +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2023 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -import { Channel, Guild, Role } from "discord-types/general"; - -import { FluxDispatcher, FluxEvents } from "./utils"; - -type GenericFunction = (...args: any[]) => any; - -export class FluxStore { - constructor(dispatcher: FluxDispatcher, eventHandlers?: Partial<Record<FluxEvents, (data: any) => void>>); - - addChangeListener(callback: () => void): void; - addReactChangeListener(callback: () => void): void; - removeChangeListener(callback: () => void): void; - removeReactChangeListener(callback: () => void): void; - emitChange(): void; - getDispatchToken(): string; - getName(): string; - initialize(): void; - initializeIfNeeded(): void; - registerActionHandlers: GenericFunction; - syncWith: GenericFunction; - waitFor: GenericFunction; - __getLocalVars(): Record<string, any>; - - static getAll(): FluxStore[]; -} - -export class FluxEmitter { - constructor(); - - changeSentinel: number; - changedStores: Set<FluxStore>; - isBatchEmitting: boolean; - isDispatching: boolean; - isPaused: boolean; - pauseTimer: NodeJS.Timeout | null; - reactChangedStores: Set<FluxStore>; - - batched(batch: (...args: any[]) => void): void; - destroy(): void; - emit(): void; - emitNonReactOnce(): void; - emitReactOnce(): void; - getChangeSentinel(): number; - getIsPaused(): boolean; - injectBatchEmitChanges(batch: (...args: any[]) => void): void; - markChanged(store: FluxStore): void; - pause(): void; - resume(): void; -} - -export interface Flux { - Store: typeof FluxStore; - Emitter: FluxEmitter; -} - -export class WindowStore extends FluxStore { - isElementFullScreen(): boolean; - isFocused(): boolean; - windowSize(): Record<"width" | "height", number>; -} - -type Emoji = CustomEmoji | UnicodeEmoji; -export interface CustomEmoji { - allNamesString: string; - animated: boolean; - available: boolean; - guildId: string; - id: string; - managed: boolean; - name: string; - originalName?: string; - require_colons: boolean; - roles: string[]; - type: 1; -} - -export interface UnicodeEmoji { - diversityChildren: Record<any, any>; - emojiObject: { - names: string[]; - surrogates: string; - unicodeVersion: number; - }; - index: number; - surrogates: string; - type: 0; - uniqueName: string; - useSpriteSheet: boolean; - get allNamesString(): string; - get animated(): boolean; - get defaultDiversityChild(): any; - get hasDiversity(): boolean | undefined; - get hasDiversityParent(): boolean | undefined; - get hasMultiDiversity(): boolean | undefined; - get hasMultiDiversityParent(): boolean | undefined; - get managed(): boolean; - get name(): string; - get names(): string[]; - get optionallyDiverseSequence(): string | undefined; - get unicodeVersion(): number; - get url(): string; -} - -export class EmojiStore extends FluxStore { - getCustomEmojiById(id?: string | null): CustomEmoji; - getUsableCustomEmojiById(id?: string | null): CustomEmoji; - getGuilds(): Record<string, { - id: string; - _emojiMap: Record<string, CustomEmoji>; - _emojis: CustomEmoji[]; - get emojis(): CustomEmoji[]; - get rawEmojis(): CustomEmoji[]; - _usableEmojis: CustomEmoji[]; - get usableEmojis(): CustomEmoji[]; - _emoticons: any[]; - get emoticons(): any[]; - }>; - getGuildEmoji(guildId?: string | null): CustomEmoji[]; - getNewlyAddedEmoji(guildId?: string | null): CustomEmoji[]; - getTopEmoji(guildId?: string | null): CustomEmoji[]; - getTopEmojisMetadata(guildId?: string | null): { - emojiIds: string[]; - topEmojisTTL: number; - }; - hasPendingUsage(): boolean; - hasUsableEmojiInAnyGuild(): boolean; - searchWithoutFetchingLatest(data: any): any; - getSearchResultsOrder(...args: any[]): any; - getState(): { - pendingUsages: { key: string, timestamp: number; }[]; - }; - searchWithoutFetchingLatest(data: { - channel: Channel, - query: string; - count?: number; - intention: number; - includeExternalGuilds?: boolean; - matchComparator?(name: string): boolean; - }): Record<"locked" | "unlocked", Emoji[]>; - - getDisambiguatedEmojiContext(): { - backfillTopEmojis: Record<any, any>; - customEmojis: Record<string, CustomEmoji>; - emojisById: Record<string, CustomEmoji>; - emojisByName: Record<string, CustomEmoji>; - emoticonRegex: RegExp | null; - emoticonsByName: Record<string, any>; - escapedEmoticonNames: string; - favoriteNamesAndIds?: any; - favorites?: any; - frequentlyUsed?: any; - groupedCustomEmojis: Record<string, CustomEmoji[]>; - guildId?: string; - isFavoriteEmojiWithoutFetchingLatest(e: Emoji): boolean; - newlyAddedEmoji: Record<string, CustomEmoji[]>; - topEmojis?: any; - unicodeAliases: Record<string, string>; - get favoriteEmojisWithoutFetchingLatest(): Emoji[]; - }; -} - -export interface DraftObject { - channelId: string; - timestamp: number; - draft: string; -} - -interface DraftState { - [userId: string]: { - [channelId: string]: { - [key in DraftType]?: Omit<DraftObject, "channelId">; - } | undefined; - } | undefined; -} - - -export class DraftStore extends FluxStore { - getDraft(channelId: string, type: DraftType): string; - getRecentlyEditedDrafts(type: DraftType): DraftObject[]; - getState(): DraftState; - getThreadDraftWithParentMessageId?(arg: any): any; - getThreadSettings(channelId: string): any | null; -} - -export enum DraftType { - ChannelMessage, - ThreadSettings, - FirstThreadMessage, - ApplicationLauncherCommand, - Poll, - SlashCommand, -} - -export class GuildStore extends FluxStore { - getGuild(guildId: string): Guild; - getGuildCount(): number; - getGuilds(): Record<string, Guild>; - getGuildIds(): string[]; -} - -export class GuildRoleStore extends FluxStore { - getRole(guildId: string, roleId: string): Role; - getRoles(guildId: string): Record<string, Role>; - getAllGuildRoles(): Record<string, Record<string, Role>>; -} - -export class ThemeStore extends FluxStore { - theme: "light" | "dark" | "darker" | "midnight"; - darkSidebar: boolean; - isSystemThemeAvailable: boolean; - systemPrefersColorScheme: "light" | "dark"; - systemTheme: null; -} - -export type useStateFromStores = <T>( - stores: any[], - mapper: () => T, - dependencies?: any, - isEqual?: (old: T, newer: T) => boolean -) => T; - -export class RelationshipStore extends FluxStore { - getFriendIDs(): string[]; - getIgnoredIDs(): string[]; - getBlockedIDs(): string[]; - - getPendingCount(): number; - getRelationshipCount(): number; - - /** Related to friend nicknames. */ - getNickname(userId: string): string; - /** @returns Enum value from constants.RelationshipTypes */ - getRelationshipType(userId: string): number; - isFriend(userId: string): boolean; - isBlocked(userId: string): boolean; - isIgnored(userId: string): boolean; - getSince(userId: string): string; - - /** @returns Format: [userId: Enum value from constants.RelationshipTypes] */ - getMutableRelationships(): Map<string, number>; -} diff --git a/src/webpack/common/utils.ts b/src/webpack/common/utils.ts index 5c54c95a..1d653dea 100644 --- a/src/webpack/common/utils.ts +++ b/src/webpack/common/utils.ts @@ -16,10 +16,8 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import type * as t from "@vencord/discord-types"; import { _resolveReady, filters, findByCodeLazy, findByPropsLazy, findLazy, mapMangledModuleLazy, waitFor } from "@webpack"; -import type { Channel } from "discord-types/general"; - -import type * as t from "./types/utils"; export let FluxDispatcher: t.FluxDispatcher; waitFor(["dispatch", "subscribe"], m => { @@ -138,7 +136,7 @@ export const UserUtils = { export const UploadManager = findByPropsLazy("clearAll", "addFile"); export const UploadHandler = { - promptToUpload: findByCodeLazy("=!0,showLargeMessageDialog:") as (files: File[], channel: Channel, draftType: Number) => void + promptToUpload: findByCodeLazy("=!0,showLargeMessageDialog:") as (files: File[], channel: t.Channel, draftType: Number) => void }; export const ApplicationAssetUtils = mapMangledModuleLazy("getAssetImage: size must === [", { diff --git a/src/webpack/index.ts b/src/webpack/index.ts index 6f1fd25b..37dda6fe 100644 --- a/src/webpack/index.ts +++ b/src/webpack/index.ts @@ -17,5 +17,5 @@ */ export * as Common from "./common"; +export * from "./types"; export * from "./webpack"; -export * from "./wreq.d"; diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index d9b35f01..767fa20d 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -10,10 +10,11 @@ import { Logger } from "@utils/Logger"; import { interpolateIfDefined } from "@utils/misc"; import { canonicalizeReplacement } from "@utils/patches"; import { Patch, PatchReplacement } from "@utils/types"; +import { WebpackRequire } from "@vencord/discord-types/webpack"; import { traceFunctionWithResults } from "../debug/Tracer"; +import { AnyModuleFactory, AnyWebpackRequire, MaybePatchedModuleFactory, PatchedModuleFactory } from "./types"; import { _blacklistBadModules, _initWebpack, factoryListeners, findModuleFactory, moduleListeners, waitForSubscriptions, wreq } from "./webpack"; -import { AnyModuleFactory, AnyWebpackRequire, MaybePatchedModuleFactory, PatchedModuleFactory, WebpackRequire } from "./wreq.d"; export const patches = [] as Patch[]; diff --git a/src/webpack/types.ts b/src/webpack/types.ts new file mode 100644 index 00000000..328aa8bc --- /dev/null +++ b/src/webpack/types.ts @@ -0,0 +1,28 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2025 Vendicated, Nuckyz and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { Module, ModuleExports, WebpackRequire } from "@vencord/discord-types/webpack"; + +import { SYM_ORIGINAL_FACTORY, SYM_PATCHED_BY, SYM_PATCHED_SOURCE } from "./patchWebpack"; + +export type AnyWebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & Partial<Omit<WebpackRequire, "m">> & { + /** The module factories, where all modules that have been loaded are stored (pre-loaded or loaded by lazy chunks) */ + m: Record<PropertyKey, AnyModuleFactory>; +}; + +/** exports can be anything, however initially it is always an empty object */ +export type AnyModuleFactory = ((this: ModuleExports, module: Module, exports: ModuleExports, require: AnyWebpackRequire) => void) & { + [SYM_PATCHED_SOURCE]?: string; + [SYM_PATCHED_BY]?: Set<string>; +}; + +export type PatchedModuleFactory = AnyModuleFactory & { + [SYM_ORIGINAL_FACTORY]: AnyModuleFactory; + [SYM_PATCHED_SOURCE]?: string; + [SYM_PATCHED_BY]?: Set<string>; +}; + +export type MaybePatchedModuleFactory = PatchedModuleFactory | AnyModuleFactory; diff --git a/src/webpack/webpack.ts b/src/webpack/webpack.ts index 98e7d4d1..247ea3f4 100644 --- a/src/webpack/webpack.ts +++ b/src/webpack/webpack.ts @@ -20,11 +20,12 @@ import { makeLazy, proxyLazy } from "@utils/lazy"; import { LazyComponent } from "@utils/lazyReact"; import { Logger } from "@utils/Logger"; import { canonicalizeMatch } from "@utils/patches"; -import { FluxStore } from "@webpack/types"; +import { FluxStore } from "@vencord/discord-types"; +import { ModuleExports, WebpackRequire } from "@vencord/discord-types/webpack"; import { traceFunction } from "../debug/Tracer"; import { Flux } from "./common"; -import { AnyModuleFactory, AnyWebpackRequire, ModuleExports, WebpackRequire } from "./wreq"; +import { AnyModuleFactory, AnyWebpackRequire } from "./types"; const logger = new Logger("Webpack"); diff --git a/tsconfig.json b/tsconfig.json index d2a42bd5..0123021c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "resolveJsonModule": true, "allowSyntheticDefaultImports": true, "esModuleInterop": true, - "skipLibCheck": true, + "skipLibCheck": false, "allowJs": true, "lib": [ "DOM", @@ -27,7 +27,6 @@ "@components/*": ["./components/*"], "@utils/*": ["./utils/*"], "@shared/*": ["./shared/*"], - "@webpack/types": ["./webpack/common/types"], "@webpack/common": ["./webpack/common"], "@webpack": ["./webpack/webpack"], "@webpack/patcher": ["./webpack/patchWebpack"], From c2fbcec3bda495ae8618d3062c8de2bc1c4ca0b6 Mon Sep 17 00:00:00 2001 From: Cookie <52550063+Covkie@users.noreply.github.com> Date: Wed, 9 Jul 2025 18:42:38 -0400 Subject: [PATCH 16/25] Settings: remove outdated style (#3490) --- src/components/PluginSettings/PluginModal.tsx | 6 +++--- src/components/VencordSettings/PatchHelperTab.tsx | 2 +- src/components/VencordSettings/ThemesTab.tsx | 2 +- src/components/VencordSettings/UpdaterTab.tsx | 2 +- src/components/VencordSettings/settingsStyles.css | 9 --------- 5 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/components/PluginSettings/PluginModal.tsx b/src/components/PluginSettings/PluginModal.tsx index 29ce90c9..ddbcf8b8 100644 --- a/src/components/PluginSettings/PluginModal.tsx +++ b/src/components/PluginSettings/PluginModal.tsx @@ -26,7 +26,7 @@ import { Flex } from "@components/Flex"; import { gitRemote } from "@shared/vencordUserAgent"; import { proxyLazy } from "@utils/lazy"; import { Margins } from "@utils/margins"; -import { classes, isObjectEmpty } from "@utils/misc"; +import { isObjectEmpty } from "@utils/misc"; import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal"; import { OptionType, Plugin } from "@utils/types"; import { User } from "@vencord/discord-types"; @@ -212,7 +212,7 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti const pluginMeta = PluginMeta[plugin.name]; return ( - <ModalRoot transitionState={transitionState} size={ModalSize.MEDIUM} className="vc-text-selectable"> + <ModalRoot transitionState={transitionState} size={ModalSize.MEDIUM}> <ModalHeader separator={false}> <Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>{plugin.name}</Text> @@ -268,7 +268,7 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti </div> </Forms.FormSection> {!!plugin.settingsAboutComponent && ( - <div className={classes(Margins.bottom8, "vc-text-selectable")}> + <div className={Margins.bottom8}> <Forms.FormSection> <ErrorBoundary message="An error occurred while rendering this plugin's custom Info Component"> <plugin.settingsAboutComponent tempSettings={tempSettings} /> diff --git a/src/components/VencordSettings/PatchHelperTab.tsx b/src/components/VencordSettings/PatchHelperTab.tsx index accccd49..83364d19 100644 --- a/src/components/VencordSettings/PatchHelperTab.tsx +++ b/src/components/VencordSettings/PatchHelperTab.tsx @@ -194,7 +194,7 @@ function ReplacementInput({ replacement, setReplacement, replacementError }) { error={error ?? replacementError} /> {!isFunc && ( - <div className="vc-text-selectable"> + <div> <Forms.FormTitle className={Margins.top8}>Cheat Sheet</Forms.FormTitle> {Object.entries({ "\\i": "Special regex escape sequence that matches identifiers (varnames, classnames, etc.)", diff --git a/src/components/VencordSettings/ThemesTab.tsx b/src/components/VencordSettings/ThemesTab.tsx index 692e20bf..f557adf1 100644 --- a/src/components/VencordSettings/ThemesTab.tsx +++ b/src/components/VencordSettings/ThemesTab.tsx @@ -309,7 +309,7 @@ function ThemesTab() { function renderOnlineThemes() { return ( <> - <Card className="vc-settings-card vc-text-selectable"> + <Card className="vc-settings-card"> <Forms.FormTitle tag="h5">Paste links to css files here</Forms.FormTitle> <Forms.FormText>One link per line</Forms.FormText> <Forms.FormText>You can prefix lines with @light or @dark to toggle them based on your Discord theme</Forms.FormText> diff --git a/src/components/VencordSettings/UpdaterTab.tsx b/src/components/VencordSettings/UpdaterTab.tsx index 9871bfcc..f5e3d4b2 100644 --- a/src/components/VencordSettings/UpdaterTab.tsx +++ b/src/components/VencordSettings/UpdaterTab.tsx @@ -225,7 +225,7 @@ function Updater() { <Forms.FormTitle tag="h5">Repo</Forms.FormTitle> - <Forms.FormText className="vc-text-selectable"> + <Forms.FormText> {repoPending ? repo : err diff --git a/src/components/VencordSettings/settingsStyles.css b/src/components/VencordSettings/settingsStyles.css index 35c12197..0161ff4e 100644 --- a/src/components/VencordSettings/settingsStyles.css +++ b/src/components/VencordSettings/settingsStyles.css @@ -60,15 +60,6 @@ background-color: var(--button-danger-background); } -.vc-text-selectable, -.vc-text-selectable :where([class*="text" i], [class*="title" i]) { - /* make text selectable, silly discord makes the entirety of settings not selectable */ - user-select: text; - - /* discord also sets cursor: default which prevents the cursor from showing as text */ - cursor: initial; -} - .vc-updater-modal { padding: 1.5em !important; } From c2d7b68950c11a1602c72c61e6a0f075b6bf3b08 Mon Sep 17 00:00:00 2001 From: Vendicated <vendicated@riseup.net> Date: Thu, 10 Jul 2025 01:37:13 +0200 Subject: [PATCH 17/25] Online Themes: fix & improve ui --- src/components/PluginSettings/index.tsx | 2 +- src/components/PluginSettings/styles.css | 7 -- src/components/VencordSettings/ThemesTab.tsx | 67 +++---------------- .../VencordSettings/settingsStyles.css | 20 ++++-- .../VencordSettings/specialCard.css | 5 -- src/plugins/_core/supportHelper.tsx | 2 +- src/plugins/voiceMessages/index.tsx | 2 +- src/utils/cspViolations.ts | 2 +- 8 files changed, 26 insertions(+), 81 deletions(-) diff --git a/src/components/PluginSettings/index.tsx b/src/components/PluginSettings/index.tsx index 27eb10a3..4d4e41e7 100644 --- a/src/components/PluginSettings/index.tsx +++ b/src/components/PluginSettings/index.tsx @@ -62,7 +62,7 @@ function showErrorToast(message: string) { function ReloadRequiredCard({ required }: { required: boolean; }) { return ( - <Card className={cl("info-card", { "restart-card": required })}> + <Card className={classes(cl("info-card"), required && "vc-warning-card")}> {required ? ( <> <Forms.FormTitle tag="h5">Restart required!</Forms.FormTitle> diff --git a/src/components/PluginSettings/styles.css b/src/components/PluginSettings/styles.css index ed5e9aa1..c3d97051 100644 --- a/src/components/PluginSettings/styles.css +++ b/src/components/PluginSettings/styles.css @@ -66,13 +66,6 @@ gap: 0.25em; } -.vc-plugins-restart-card { - padding: 1em; - background: var(--info-warning-background); - border: 1px solid var(--info-warning-foreground); - color: var(--info-warning-foreground); -} - .vc-plugins-restart-button { margin-top: 0.5em; background: var(--info-warning-foreground) !important; diff --git a/src/components/VencordSettings/ThemesTab.tsx b/src/components/VencordSettings/ThemesTab.tsx index f557adf1..6d41ab86 100644 --- a/src/components/VencordSettings/ThemesTab.tsx +++ b/src/components/VencordSettings/ThemesTab.tsx @@ -29,7 +29,7 @@ import { openInviteModal } from "@utils/discord"; import { Margins } from "@utils/margins"; import { classes } from "@utils/misc"; import { relaunch } from "@utils/native"; -import { useAwaiter, useForceUpdater } from "@utils/react"; +import { useForceUpdater } from "@utils/react"; import { getStylusWebStoreUrl } from "@utils/web"; import { findLazy } from "@webpack"; import { Alerts, Button, Card, Forms, React, showToast, TabBar, TextArea, useEffect, useRef, useState } from "@webpack/common"; @@ -52,62 +52,6 @@ const FileInput: FileInput = findLazy(m => m.prototype?.activateUploadDialogue & const cl = classNameFactory("vc-settings-theme-"); -function Validator({ link }: { link: string; }) { - const [res, err, pending] = useAwaiter(() => fetch(link).then(res => { - if (res.status > 300) throw `${res.status} ${res.statusText}`; - const contentType = res.headers.get("Content-Type"); - if (!contentType?.startsWith("text/css") && !contentType?.startsWith("text/plain")) - throw "Not a CSS file. Remember to use the raw link!"; - - return "Okay!"; - })); - - const text = pending - ? "Checking..." - : err - ? `Error: ${err instanceof Error ? err.message : String(err)}` - : "Valid!"; - - return <Forms.FormText style={{ - color: pending ? "var(--text-muted)" : err ? "var(--text-danger)" : "var(--status-positive)" - }}>{text}</Forms.FormText>; -} - -function Validators({ themeLinks }: { themeLinks: string[]; }) { - if (!themeLinks.length) return null; - - return ( - <> - <Forms.FormTitle className={Margins.top20} tag="h5">Validator</Forms.FormTitle> - <Forms.FormText>This section will tell you whether your themes can successfully be loaded</Forms.FormText> - <div> - {themeLinks.map(rawLink => { - const { label, link } = (() => { - const match = /^@(light|dark) (.*)/.exec(rawLink); - if (!match) return { label: rawLink, link: rawLink }; - - const [, mode, link] = match; - return { label: `[${mode} mode only] ${link}`, link }; - })(); - - return <Card style={{ - padding: ".5em", - marginBottom: ".5em", - marginTop: ".5em" - }} key={link}> - <Forms.FormTitle tag="h5" style={{ - overflowWrap: "break-word" - }}> - {label} - </Forms.FormTitle> - <Validator link={link} /> - </Card>; - })} - </div> - </> - ); -} - interface ThemeCardProps { theme: UserThemeHeader; enabled: boolean; @@ -309,6 +253,12 @@ function ThemesTab() { function renderOnlineThemes() { return ( <> + <Card className={classes("vc-warning-card", Margins.bottom16)}> + <Forms.FormText> + This section is for advanced users. If you are having difficulties using it, use the + Local Themes tab instead. + </Forms.FormText> + </Card> <Card className="vc-settings-card"> <Forms.FormTitle tag="h5">Paste links to css files here</Forms.FormTitle> <Forms.FormText>One link per line</Forms.FormText> @@ -321,12 +271,11 @@ function ThemesTab() { value={themeText} onChange={setThemeText} className={"vc-settings-theme-links"} - placeholder="Theme Links" + placeholder="Enter Theme Links..." spellCheck={false} onBlur={onBlur} rows={10} /> - <Validators themeLinks={settings.themeLinks} /> </Forms.FormSection> </> ); diff --git a/src/components/VencordSettings/settingsStyles.css b/src/components/VencordSettings/settingsStyles.css index 0161ff4e..c92d588f 100644 --- a/src/components/VencordSettings/settingsStyles.css +++ b/src/components/VencordSettings/settingsStyles.css @@ -1,7 +1,7 @@ .vc-settings-tab-bar { margin-top: 20px; margin-bottom: 10px; - border-bottom: 2px solid var(--background-modifier-accent); + border-bottom: 1px solid var(--border-subtle); } .vc-settings-tab-bar-item { @@ -20,6 +20,13 @@ margin-bottom: 1em; } +.vc-warning-card { + padding: 1em; + background: var(--info-warning-background); + border: 1px solid var(--info-warning-foreground); + color: var(--info-warning-foreground); +} + .vc-backup-restore-card { background-color: var(--info-warning-background); border-color: var(--info-warning-foreground); @@ -30,19 +37,20 @@ /* Needed to fix bad themes that hide certain textarea elements for whatever eldritch reason */ display: inline-block !important; color: var(--text-default) !important; - padding: 0.5em; - border: 1px solid var(--background-modifier-accent); + padding: 0.5em 1em; + border: 1px solid var(--input-border); max-height: unset; background-color: transparent; box-sizing: border-box; - font-size: 12px; - line-height: 14px; resize: none; width: 100%; + font-size: 1em; + line-height: 2em; + white-space: nowrap; } .vc-settings-theme-links::placeholder { - color: var(--header-secondary); + color: var(--text-muted) !important; } .vc-settings-theme-links:focus { diff --git a/src/components/VencordSettings/specialCard.css b/src/components/VencordSettings/specialCard.css index 07b628f5..fb868283 100644 --- a/src/components/VencordSettings/specialCard.css +++ b/src/components/VencordSettings/specialCard.css @@ -12,11 +12,6 @@ position: relative; } -.vc-settings-card { - padding: 1em; - margin-bottom: 1em; -} - .vc-special-card-special { padding: 1em 1.5em; margin-bottom: 1em; diff --git a/src/plugins/_core/supportHelper.tsx b/src/plugins/_core/supportHelper.tsx index 956343f6..82e09b88 100644 --- a/src/plugins/_core/supportHelper.tsx +++ b/src/plugins/_core/supportHelper.tsx @@ -318,7 +318,7 @@ export default definePlugin({ if (RelationshipStore.isFriend(userId) || isPluginDev(UserStore.getCurrentUser()?.id)) return null; return ( - <Card className={`vc-plugins-restart-card ${Margins.top8}`}> + <Card className={`vc-warning-card ${Margins.top8}`}> Please do not private message Vencord plugin developers for support! <br /> Instead, use the Vencord support channel: {Parser.parse("https://discord.com/channels/1015060230222131221/1026515880080842772")} diff --git a/src/plugins/voiceMessages/index.tsx b/src/plugins/voiceMessages/index.tsx index 8365bb51..74f39ea3 100644 --- a/src/plugins/voiceMessages/index.tsx +++ b/src/plugins/voiceMessages/index.tsx @@ -219,7 +219,7 @@ function Modal({ modalProps }: { modalProps: ModalProps; }) { /> {isUnsupportedFormat && ( - <Card className={`vc-plugins-restart-card ${Margins.top16}`}> + <Card className={`vc-warning-card ${Margins.top16}`}> <Forms.FormText>Voice Messages have to be OggOpus to be playable on iOS. This file is <code>{blob.type}</code> so it will not be playable on iOS.</Forms.FormText> <Forms.FormText className={Margins.top8}> diff --git a/src/utils/cspViolations.ts b/src/utils/cspViolations.ts index 9477bcaa..b1acc4c6 100644 --- a/src/utils/cspViolations.ts +++ b/src/utils/cspViolations.ts @@ -8,7 +8,7 @@ import { useLayoutEffect } from "@webpack/common"; import { useForceUpdater } from "./react"; -const cssRelevantDirectives = ["style-src", "img-src", "font-src"] as const; +const cssRelevantDirectives = ["style-src", "style-src-elem", "img-src", "font-src"] as const; export const CspBlockedUrls = new Set<string>(); const CspErrorListeners = new Set<() => void>(); From 4c315b6886532f0109487ffa80634955f045968f Mon Sep 17 00:00:00 2001 From: Vendicated <vendicated@riseup.net> Date: Thu, 10 Jul 2025 01:37:32 +0200 Subject: [PATCH 18/25] fix various plugins still using outdated Discord classes --- src/plugins/clientTheme/clientTheme.css | 2 +- src/plugins/reviewDB/style.css | 2 +- src/plugins/sendTimestamps/styles.css | 4 ++-- src/plugins/serverInfo/styles.css | 2 +- src/plugins/spotifyControls/spotifyStyles.css | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/clientTheme/clientTheme.css b/src/plugins/clientTheme/clientTheme.css index 49cc3e15..828703e5 100644 --- a/src/plugins/clientTheme/clientTheme.css +++ b/src/plugins/clientTheme/clientTheme.css @@ -16,7 +16,7 @@ } .vc-clientTheme-container [class^="swatch"] { - border: thin solid var(--background-modifier-accent) !important; + border: thin solid var(--input-border) !important; } .vc-clientTheme-buttons-container { diff --git a/src/plugins/reviewDB/style.css b/src/plugins/reviewDB/style.css index 50499b29..47ccd091 100644 --- a/src/plugins/reviewDB/style.css +++ b/src/plugins/reviewDB/style.css @@ -123,7 +123,7 @@ display: block; width: 100%; height: 100%; - background-color: var(--background-modifier-accent); + background-color: var(--border-subtle); } .vc-rdb-block-modal-username { diff --git a/src/plugins/sendTimestamps/styles.css b/src/plugins/sendTimestamps/styles.css index d96e886a..7d82b800 100644 --- a/src/plugins/sendTimestamps/styles.css +++ b/src/plugins/sendTimestamps/styles.css @@ -15,11 +15,11 @@ .vc-st-format-select { margin-bottom: 1em; - --background-modifier-accent: transparent; + --border-subtle: transparent; } .vc-st-format-label { - --background-modifier-accent: transparent; + --border-subtle: transparent; } .vc-st-modal-header { diff --git a/src/plugins/serverInfo/styles.css b/src/plugins/serverInfo/styles.css index 0fc44e02..f10fb6ac 100644 --- a/src/plugins/serverInfo/styles.css +++ b/src/plugins/serverInfo/styles.css @@ -38,7 +38,7 @@ } .vc-gp-tab-bar { - border-bottom: 2px solid var(--background-modifier-accent); + border-bottom: 1px solid var(--border-subtle); margin: 20px 12px 0; display: flex; gap: 40px; diff --git a/src/plugins/spotifyControls/spotifyStyles.css b/src/plugins/spotifyControls/spotifyStyles.css index 58d74504..d4afbc83 100644 --- a/src/plugins/spotifyControls/spotifyStyles.css +++ b/src/plugins/spotifyControls/spotifyStyles.css @@ -1,6 +1,6 @@ #vc-spotify-player { padding: 0.375rem 0.5rem; - border-bottom: 1px solid var(--background-modifier-accent); + border-bottom: 1px solid var(--border-subtle); --vc-spotify-green: var(--spotify, #1db954); /* so custom themes can easily change it */ --vc-spotify-green-90: color-mix(in hsl, var(--vc-spotify-green), transparent 90%); From 8ec5b0a8d86dc99aca099774386b5872eef27e25 Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Thu, 10 Jul 2025 15:56:12 -0400 Subject: [PATCH 19/25] fix ImageZoom & FakeProfileThemes (#3546) Co-authored-by: Vendicated <vendicated@riseup.net> --- src/plugins/fakeProfileThemes/index.tsx | 2 +- src/plugins/imageZoom/index.tsx | 11 +++-------- src/plugins/showHiddenChannels/index.tsx | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/plugins/fakeProfileThemes/index.tsx b/src/plugins/fakeProfileThemes/index.tsx index a84722c1..1de38ab4 100644 --- a/src/plugins/fakeProfileThemes/index.tsx +++ b/src/plugins/fakeProfileThemes/index.tsx @@ -122,7 +122,7 @@ export default definePlugin({ { find: "#{intl::USER_SETTINGS_RESET_PROFILE_THEME}", replacement: { - match: /#{intl::USER_SETTINGS_RESET_PROFILE_THEME}\)}\)(?<=color:(\i),.{0,500}?color:(\i),.{0,500}?)/, + match: /#{intl::USER_SETTINGS_RESET_PROFILE_THEME}\).+?}\)(?=\])(?<=color:(\i),.{0,500}?color:(\i),.{0,500}?)/, replace: "$&,$self.addCopy3y3Button({primary:$1,accent:$2})" } } diff --git a/src/plugins/imageZoom/index.tsx b/src/plugins/imageZoom/index.tsx index 56e1d4a2..4fbfe3ff 100644 --- a/src/plugins/imageZoom/index.tsx +++ b/src/plugins/imageZoom/index.tsx @@ -171,14 +171,9 @@ export default definePlugin({ replace: `id:"${ELEMENT_ID}",$&` }, { - // This patch needs to be above the next one as it uses the zoomed class as an anchor - match: /\.zoomed]:.+?,(?=children:)/, - replace: "$&onClick:()=>{}," - }, - { - match: /className:\i\(\)\(\i\.wrapper,.+?}\),/, - replace: "" - }, + match: /(?<=null!=(\i)\?.{0,20})\i\.\i,{children:\1/, + replace: "'div',{onClick:e=>e.stopPropagation(),children:$1" + } ] }, // Make media viewer options not hide when zoomed in with the default Discord feature diff --git a/src/plugins/showHiddenChannels/index.tsx b/src/plugins/showHiddenChannels/index.tsx index c99afc84..a0ef38a6 100644 --- a/src/plugins/showHiddenChannels/index.tsx +++ b/src/plugins/showHiddenChannels/index.tsx @@ -250,7 +250,7 @@ export default definePlugin({ replace: (m, channel) => `${m}if($self.isHiddenChannel(${channel}))break;` }, { - match: /(?<="renderHeaderBar",\(\)=>{.+?hideSearch:(\i)\.isDirectory\(\))/, + match: /(?<="renderHeaderBar",\i=>{.+?hideSearch:(\i)\.isDirectory\(\))/, replace: (_, channel) => `||$self.isHiddenChannel(${channel})` }, { From 8411026c512506d3a9630fe1a167b29caac1154c Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Thu, 10 Jul 2025 16:38:27 -0400 Subject: [PATCH 20/25] FakeProfileThemes: fix error when own profile is not loaded (#3514) Co-authored-by: V <vendicated@riseup.net> --- packages/discord-types/enums/commands.ts | 5 + .../discord-types/src/common/Application.d.ts | 23 ++ packages/discord-types/src/common/User.d.ts | 3 +- packages/discord-types/src/common/index.d.ts | 1 + .../src/stores/UserProfileStore.d.ts | 151 +++++++++++++ packages/discord-types/src/stores/index.d.ts | 1 + src/plugins/fakeProfileThemes/index.tsx | 202 +++++++++--------- src/plugins/showConnections/index.tsx | 15 +- src/plugins/validUser/index.tsx | 18 +- src/utils/discord.tsx | 2 +- src/webpack/common/stores.ts | 2 +- 11 files changed, 297 insertions(+), 126 deletions(-) create mode 100644 packages/discord-types/src/common/Application.d.ts create mode 100644 packages/discord-types/src/stores/UserProfileStore.d.ts diff --git a/packages/discord-types/enums/commands.ts b/packages/discord-types/enums/commands.ts index 0556e72d..298f9b7a 100644 --- a/packages/discord-types/enums/commands.ts +++ b/packages/discord-types/enums/commands.ts @@ -25,3 +25,8 @@ export const enum ApplicationCommandType { USER = 2, MESSAGE = 3, } + +export const enum ApplicationIntegrationType { + GUILD_INSTALL = 0, + USER_INSTALL = 1 +} diff --git a/packages/discord-types/src/common/Application.d.ts b/packages/discord-types/src/common/Application.d.ts new file mode 100644 index 00000000..d2ec1e7e --- /dev/null +++ b/packages/discord-types/src/common/Application.d.ts @@ -0,0 +1,23 @@ +import { User } from "./User"; + +export interface Application { + id: string; + name: string; + description?: string | null; + type: number | null; + icon: string | null | undefined; + is_discoverable: boolean; + is_monetized: boolean; + is_verified: boolean; + bot?: User; + deeplink_uri?: string; + flags?: number; + privacy_policy_url?: string; + terms_of_service_url?: string; + install_params?: ApplicationInstallParams; +} + +export interface ApplicationInstallParams { + permissions: string | null; + scopes: string[]; +} diff --git a/packages/discord-types/src/common/User.d.ts b/packages/discord-types/src/common/User.d.ts index a5503bcb..07eb4718 100644 --- a/packages/discord-types/src/common/User.d.ts +++ b/packages/discord-types/src/common/User.d.ts @@ -6,7 +6,7 @@ export class User extends DiscordRecord { constructor(user: object); accentColor: number; avatar: string; - banner: string; + banner: string | null | undefined; bio: string; bot: boolean; desktop: boolean; @@ -27,7 +27,6 @@ export class User extends DiscordRecord { system: boolean; username: string; verified: boolean; - themeColors?: [number, number]; get createdAt(): Date; get hasPremiumPerks(): boolean; diff --git a/packages/discord-types/src/common/index.d.ts b/packages/discord-types/src/common/index.d.ts index f85a7c72..5e50e96e 100644 --- a/packages/discord-types/src/common/index.d.ts +++ b/packages/discord-types/src/common/index.d.ts @@ -1,3 +1,4 @@ +export * from "./Application"; export * from "./Channel"; export * from "./Guild"; export * from "./GuildMember"; diff --git a/packages/discord-types/src/stores/UserProfileStore.d.ts b/packages/discord-types/src/stores/UserProfileStore.d.ts new file mode 100644 index 00000000..d9efc47b --- /dev/null +++ b/packages/discord-types/src/stores/UserProfileStore.d.ts @@ -0,0 +1,151 @@ +import { FluxStore, Guild, User, Application, ApplicationInstallParams } from ".."; +import { ApplicationIntegrationType } from "../../enums"; + +export interface MutualFriend { + /** + * the userid of the mutual friend + */ + key: string; + /** + * the status of the mutual friend + */ + status: "online" | "offline" | "idle" | "dnd"; + /** + * the user object of the mutual friend + */ + user: User; +} + +export interface MutualGuild { + /** + * the guild object of the mutual guild + */ + guild: Guild; + /** + * the user's nickname in the guild, if any + */ + nick: string | null; + +} + +export interface ProfileBadge { + id: string; + description: string; + icon: string; + link?: string; +} + +export interface ConnectedAccount { + type: "twitch" | "youtube" | "skype" | "steam" | "leagueoflegends" | "battlenet" | "bluesky" | "bungie" | "reddit" | "twitter" | "twitter_legacy" | "spotify" | "facebook" | "xbox" | "samsung" | "contacts" | "instagram" | "mastodon" | "soundcloud" | "github" | "playstation" | "playstation-stg" | "epicgames" | "riotgames" | "roblox" | "paypal" | "ebay" | "tiktok" | "crunchyroll" | "domain" | "amazon-music"; + /** + * underlying id of connected account + * eg. account uuid + */ + id: string; + /** + * display name of connected account + */ + name: string; + verified: boolean; + metadata?: Record<string, string>; +} + +export interface ProfileApplication { + id: string; + customInstallUrl: string | undefined; + installParams: ApplicationInstallParams | undefined; + flags: number; + popularApplicationCommandIds?: string[]; + integrationTypesConfig: Record<ApplicationIntegrationType, Partial<{ + oauth2_install_params: ApplicationInstallParams; + }>>; + primarySkuId: string | undefined; + storefront_available: boolean; +} + +export interface UserProfileBase extends Pick<User, "banner"> { + accentColor: number | null; + /** + * often empty for guild profiles, get the user profile for badges + */ + badges: ProfileBadge[]; + bio: string | undefined; + popoutAnimationParticleType: string | null; + profileEffectExpiresAt: number | Date | undefined; + profileEffectId: undefined | string; + /** + * often an empty string when not set + */ + pronouns: string | "" | undefined; + themeColors: [number, number] | undefined; + userId: string; +} + +export interface ApplicationRoleConnection { + application: Application; + application_metadata: Record<string, any>; + metadata: Record<string, any>; + platform_name: string; + platform_username: string; +} + +export interface UserProfile extends UserProfileBase, Pick<User, "premiumType"> { + /** If this is a bot user profile, this will be its application */ + application: ProfileApplication | null; + applicationRoleConnections: ApplicationRoleConnection[] | undefined; + connectedAccounts: ConnectedAccount[] | undefined; + fetchStartedAt: number; + fetchEndedAt: number; + legacyUsername: string | undefined; + premiumGuildSince: Date | null; + premiumSince: Date | null; +} + +export class UserProfileStore extends FluxStore { + /** + * @param userId the user ID of the profile being fetched. + * @param guildId the guild ID to of the profile being fetched. + * defaults to the internal symbol `NO GUILD ID` if nullish + * + * @returns true if the profile is being fetched, false otherwise. + */ + isFetchingProfile(userId: string, guildId?: string): boolean; + /** + * Check if mutual friends for {@link userId} are currently being fetched. + * + * @param userId the user ID of the mutual friends being fetched. + * + * @returns true if mutual friends are being fetched, false otherwise. + */ + isFetchingFriends(userId: string): boolean; + + get isSubmitting(): boolean; + + getUserProfile(userId: string): UserProfile | undefined; + + getGuildMemberProfile(userId: string, guildId: string | undefined): UserProfileBase | null; + /** + * Get the mutual friends of a user. + * + * @param userId the user ID of the user to get the mutual friends of. + * + * @returns an array of mutual friends, or undefined if the user has no mutual friends + */ + getMutualFriends(userId: string): MutualFriend[] | undefined; + /** + * Get the count of mutual friends for a user. + * + * @param userId the user ID of the user to get the mutual friends count of. + * + * @returns the count of mutual friends, or undefined if the user has no mutual friends + */ + getMutualFriendsCount(userId: string): number | undefined; + /** + * Get the mutual guilds of a user. + * + * @param userId the user ID of the user to get the mutual guilds of. + * + * @returns an array of mutual guilds, or undefined if the user has no mutual guilds + */ + getMutualGuilds(userId: string): MutualGuild[] | undefined; +} diff --git a/packages/discord-types/src/stores/index.d.ts b/packages/discord-types/src/stores/index.d.ts index b6254844..23045832 100644 --- a/packages/discord-types/src/stores/index.d.ts +++ b/packages/discord-types/src/stores/index.d.ts @@ -11,6 +11,7 @@ export * from "./RelationshipStore"; export * from "./SelectedChannelStore"; export * from "./SelectedGuildStore"; export * from "./ThemeStore"; +export * from "./UserProfileStore"; export * from "./UserStore"; export * from "./WindowStore"; diff --git a/src/plugins/fakeProfileThemes/index.tsx b/src/plugins/fakeProfileThemes/index.tsx index 1de38ab4..5d16a842 100644 --- a/src/plugins/fakeProfileThemes/index.tsx +++ b/src/plugins/fakeProfileThemes/index.tsx @@ -22,13 +22,14 @@ import "./index.css"; import { definePluginSettings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; +import { fetchUserProfile } from "@utils/discord"; import { Margins } from "@utils/margins"; import { classes, copyWithToast } from "@utils/misc"; +import { useAwaiter } from "@utils/react"; import definePlugin, { OptionType } from "@utils/types"; -import { User } from "@vencord/discord-types"; +import { User, UserProfile } from "@vencord/discord-types"; import { findComponentByCodeLazy } from "@webpack"; import { Button, ColorPicker, Flex, Forms, React, Text, UserProfileStore, UserStore, useState } from "@webpack/common"; -import { ReactElement } from "react"; import virtualMerge from "virtual-merge"; interface Colors { @@ -81,14 +82,6 @@ const settings = definePluginSettings({ } }); -interface ColorPickerProps { - color: number | null; - label: ReactElement<any>; - showEyeDropper?: boolean; - suggestedColors?: string[]; - onChange(value: number | null): void; -} - // I can't be bothered to figure out the semantics of this component. The // functions surely get some event argument sent to them and they likely aren't // all required. If anyone who wants to use this component stumbles across this @@ -106,6 +99,100 @@ interface ProfileModalProps { const ProfileModal = findComponentByCodeLazy<ProfileModalProps>("isTryItOutFlow:", "pendingThemeColors:", "pendingAvatarDecoration:", "EDIT_PROFILE_BANNER"); +function SettingsAboutComponentWrapper() { + const [, , userProfileLoading] = useAwaiter(() => fetchUserProfile(UserStore.getCurrentUser().id)); + + return !userProfileLoading && <SettingsAboutComponent />; +} + +function SettingsAboutComponent() { + const existingColors = decode( + UserProfileStore.getUserProfile(UserStore.getCurrentUser().id)?.bio ?? "" + ) ?? [0, 0]; + const [color1, setColor1] = useState(existingColors[0]); + const [color2, setColor2] = useState(existingColors[1]); + + return ( + <Forms.FormSection> + <Forms.FormTitle tag="h3">Usage</Forms.FormTitle> + <Forms.FormText> + After enabling this plugin, you will see custom colors in + the profiles of other people using compatible plugins.{" "} + <br /> + To set your own colors: + <ul> + <li> + • use the color pickers below to choose your colors + </li> + <li>• click the "Copy 3y3" button</li> + <li>• paste the invisible text anywhere in your bio</li> + </ul><br /> + <Forms.FormDivider + className={classes(Margins.top8, Margins.bottom8)} + /> + <Forms.FormTitle tag="h3">Color pickers</Forms.FormTitle> + <Flex + direction={Flex.Direction.HORIZONTAL} + style={{ gap: "1rem" }} + > + <ColorPicker + color={color1} + label={ + <Text + variant={"text-xs/normal"} + style={{ marginTop: "4px" }} + > + Primary + </Text> + } + onChange={(color: number) => { + setColor1(color); + }} + /> + <ColorPicker + color={color2} + label={ + <Text + variant={"text-xs/normal"} + style={{ marginTop: "4px" }} + > + Accent + </Text> + } + onChange={(color: number) => { + setColor2(color); + }} + /> + <Button + onClick={() => { + const colorString = encode(color1, color2); + copyWithToast(colorString); + }} + color={Button.Colors.PRIMARY} + size={Button.Sizes.XLARGE} + > + Copy 3y3 + </Button> + </Flex> + <Forms.FormDivider + className={classes(Margins.top8, Margins.bottom8)} + /> + <Forms.FormTitle tag="h3">Preview</Forms.FormTitle> + <div className="vc-fpt-preview"> + <ProfileModal + user={UserStore.getCurrentUser()} + pendingThemeColors={[color1, color2]} + onAvatarChange={() => { }} + onBannerChange={() => { }} + canUsePremiumCustomization={true} + hideExampleButton={true} + hideFakeActivity={true} + isTryItOutFlow={true} + /> + </div> + </Forms.FormText> + </Forms.FormSection>); +} export default definePlugin({ name: "FakeProfileThemes", @@ -117,7 +204,7 @@ export default definePlugin({ replacement: { match: /(?<=getUserProfile\(\i\){return )(.+?)(?=})/, replace: "$self.colorDecodeHook($1)" - } + }, }, { find: "#{intl::USER_SETTINGS_RESET_PROFILE_THEME}", @@ -127,97 +214,12 @@ export default definePlugin({ } } ], - settingsAboutComponent: () => { - const existingColors = decode( - UserProfileStore.getUserProfile(UserStore.getCurrentUser().id).bio - ) ?? [0, 0]; - const [color1, setColor1] = useState(existingColors[0]); - const [color2, setColor2] = useState(existingColors[1]); - return ( - <Forms.FormSection> - <Forms.FormTitle tag="h3">Usage</Forms.FormTitle> - <Forms.FormText> - After enabling this plugin, you will see custom colors in - the profiles of other people using compatible plugins.{" "} - <br /> - To set your own colors: - <ul> - <li> - • use the color pickers below to choose your colors - </li> - <li>• click the "Copy 3y3" button</li> - <li>• paste the invisible text anywhere in your bio</li> - </ul><br /> - <Forms.FormDivider - className={classes(Margins.top8, Margins.bottom8)} - /> - <Forms.FormTitle tag="h3">Color pickers</Forms.FormTitle> - <Flex - direction={Flex.Direction.HORIZONTAL} - style={{ gap: "1rem" }} - > - <ColorPicker - color={color1} - label={ - <Text - variant={"text-xs/normal"} - style={{ marginTop: "4px" }} - > - Primary - </Text> - } - onChange={(color: number) => { - setColor1(color); - }} - /> - <ColorPicker - color={color2} - label={ - <Text - variant={"text-xs/normal"} - style={{ marginTop: "4px" }} - > - Accent - </Text> - } - onChange={(color: number) => { - setColor2(color); - }} - /> - <Button - onClick={() => { - const colorString = encode(color1, color2); - copyWithToast(colorString); - }} - color={Button.Colors.PRIMARY} - size={Button.Sizes.XLARGE} - > - Copy 3y3 - </Button> - </Flex> - <Forms.FormDivider - className={classes(Margins.top8, Margins.bottom8)} - /> - <Forms.FormTitle tag="h3">Preview</Forms.FormTitle> - <div className="vc-fpt-preview"> - <ProfileModal - user={UserStore.getCurrentUser()} - pendingThemeColors={[color1, color2]} - onAvatarChange={() => { }} - onBannerChange={() => { }} - canUsePremiumCustomization={true} - hideExampleButton={true} - hideFakeActivity={true} - isTryItOutFlow={true} - /> - </div> - </Forms.FormText> - </Forms.FormSection>); - }, + settingsAboutComponent: SettingsAboutComponentWrapper, + settings, - colorDecodeHook(user: User) { - if (user) { + colorDecodeHook(user: UserProfile) { + if (user?.bio) { // don't replace colors if already set with nitro if (settings.store.nitroFirst && user.themeColors) return user; const colors = decode(user.bio); diff --git a/src/plugins/showConnections/index.tsx b/src/plugins/showConnections/index.tsx index 882c869e..ca90cc48 100644 --- a/src/plugins/showConnections/index.tsx +++ b/src/plugins/showConnections/index.tsx @@ -25,7 +25,7 @@ import { CopyIcon, LinkIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; import { copyWithToast } from "@utils/misc"; import definePlugin, { OptionType } from "@utils/types"; -import { User } from "@vencord/discord-types"; +import { ConnectedAccount, User } from "@vencord/discord-types"; import { findByCodeLazy, findByPropsLazy } from "@webpack"; import { Tooltip, UserProfileStore } from "@webpack/common"; @@ -60,15 +60,8 @@ const settings = definePluginSettings({ } }); -interface Connection { - type: string; - id: string; - name: string; - verified: boolean; -} - interface ConnectionPlatform { - getPlatformUserUrl(connection: Connection): string; + getPlatformUserUrl(connection: ConnectedAccount): string; icon: { lightSVG: string, darkSVG: string; }; } @@ -88,7 +81,7 @@ function ConnectionsComponent({ id, theme }: { id: string, theme: string; }) { if (!profile) return null; - const connections: Connection[] = profile.connectedAccounts; + const connections = profile.connectedAccounts; if (!connections?.length) return null; @@ -102,7 +95,7 @@ function ConnectionsComponent({ id, theme }: { id: string, theme: string; }) { ); } -function CompactConnectionComponent({ connection, theme }: { connection: Connection, theme: string; }) { +function CompactConnectionComponent({ connection, theme }: { connection: ConnectedAccount, theme: string; }) { const platform = platforms.get(useLegacyPlatformType(connection.type)); const url = platform.getPlatformUserUrl?.(connection); diff --git a/src/plugins/validUser/index.tsx b/src/plugins/validUser/index.tsx index 4825cdaa..488b6bd6 100644 --- a/src/plugins/validUser/index.tsx +++ b/src/plugins/validUser/index.tsx @@ -22,6 +22,7 @@ import { isNonNullish } from "@utils/guards"; import { sleep } from "@utils/misc"; import { Queue } from "@utils/Queue"; import definePlugin from "@utils/types"; +import { ProfileBadge } from "@vencord/discord-types"; import { Constants, FluxDispatcher, RestAPI, UserProfileStore, UserStore, useState } from "@webpack/common"; import { type ComponentType, type ReactNode } from "react"; @@ -47,13 +48,6 @@ const badges: Record<string, ProfileBadge> = { const fetching = new Set<string>(); const queue = new Queue(5); -interface ProfileBadge { - id: string; - description: string; - icon: string; - link?: string; -} - interface MentionProps { data: { userId?: string; @@ -102,10 +96,12 @@ async function getUser(id: string) { // Fill in what we can deduce const profile = UserProfileStore.getUserProfile(id); - profile.accentColor = user.accent_color; - profile.badges = fakeBadges; - profile.banner = user.banner; - profile.premiumType = user.premium_type; + if (profile) { + profile.accentColor = user.accent_color; + profile.badges = fakeBadges; + profile.banner = user.banner; + profile.premiumType = user.premium_type; + } return userObj; } diff --git a/src/utils/discord.tsx b/src/utils/discord.tsx index 4a652a29..d7a38ebb 100644 --- a/src/utils/discord.tsx +++ b/src/utils/discord.tsx @@ -194,7 +194,7 @@ export async function fetchUserProfile(id: string, options?: FetchUserProfileOpt }); FluxDispatcher.dispatch({ type: "USER_UPDATE", user: body.user }); - await FluxDispatcher.dispatch({ type: "USER_PROFILE_FETCH_SUCCESS", ...body }); + await FluxDispatcher.dispatch({ type: "USER_PROFILE_FETCH_SUCCESS", userProfile: body }); if (options?.guild_id && body.guild_member) FluxDispatcher.dispatch({ type: "GUILD_MEMBER_PROFILE_UPDATE", guildId: options.guild_id, guildMember: body.guild_member }); diff --git a/src/webpack/common/stores.ts b/src/webpack/common/stores.ts index be72d47c..4165af8e 100644 --- a/src/webpack/common/stores.ts +++ b/src/webpack/common/stores.ts @@ -42,7 +42,7 @@ export let GuildStore: t.GuildStore; export let GuildRoleStore: t.GuildRoleStore; export let GuildMemberStore: t.GuildMemberStore; export let UserStore: t.UserStore; -export let UserProfileStore: GenericStore; +export let UserProfileStore: t.UserProfileStore; export let SelectedChannelStore: t.SelectedChannelStore; export let SelectedGuildStore: t.SelectedGuildStore; export let ChannelStore: t.ChannelStore; From aa52e1a42b975c157f0b4147dcdcb7cc8ae9fcaf Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 14 Jul 2025 17:07:22 -0300 Subject: [PATCH 21/25] Fix MessagePopoverAPI incorrectly hiding the emoji button --- src/plugins/_api/messagePopover.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/_api/messagePopover.ts b/src/plugins/_api/messagePopover.ts index a297fc87..a49658fb 100644 --- a/src/plugins/_api/messagePopover.ts +++ b/src/plugins/_api/messagePopover.ts @@ -27,7 +27,7 @@ export default definePlugin({ { find: "#{intl::MESSAGE_UTILITIES_A11Y_LABEL}", replacement: { - match: /(?<=:null),(.{0,40}togglePopout:.+?}\)),(.+?)\]}\):null,(?<=\((\i\.\i),{label:.+?children:\[(\i&&!\i)\?\(0,\i\.jsxs?\)\(\i\.Fragment.+?message:(\i).+?)/, + match: /(?<=:null),(.{0,40}togglePopout:.+?}\)),(.+?)\]}\):null,(?<=\((\i\.\i),{label:.+?:null,(\i)\?\(0,\i\.jsxs?\)\(\i\.Fragment.+?message:(\i).+?)/, replace: (_, ReactButton, PotionButton, ButtonComponent, showReactButton, message) => "" + `]}):null,Vencord.Api.MessagePopover._buildPopoverElements(${ButtonComponent},${message}),${showReactButton}?${ReactButton}:null,${showReactButton}&&${PotionButton},` } From 2a52efbd97aa478267228cc6d0e7394572678cc5 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 14 Jul 2025 17:07:43 -0300 Subject: [PATCH 22/25] Fix Experiments embed patches --- src/plugins/experiments/index.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/experiments/index.tsx b/src/plugins/experiments/index.tsx index eee732d0..21c6088b 100644 --- a/src/plugins/experiments/index.tsx +++ b/src/plugins/experiments/index.tsx @@ -116,11 +116,19 @@ export default definePlugin({ }, // Fix some tricky experiments name causing a client crash { - match: /.getRegisteredExperiments\(\)(?<=(\i)=.+?).+?if\(null==(\i)(?=\)return null;)/, - replace: "$&||!Object.hasOwn($1,$2)" + match: /.getExperimentBucketName.+?if\(null==(\i)\|\|null==\i(?=\)return null;)/, + replace: "$&||({})[$1]!=null" } ] }, + // Fix another function which cases crashes with tricky experiment names and the experiment embed + { + find: "}getServerAssignment(", + replacement: { + match: /}getServerAssignment\((\i),\i,\i\){/, + replace: "$&if($1==null)return;" + } + } ], start: () => !BugReporterExperiment.getCurrentConfig().hasBugReporterAccess && enableStyle(hideBugReport), From ec6fbb190f486001915ad66549df7661b15d14cc Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 14 Jul 2025 17:09:21 -0300 Subject: [PATCH 23/25] Attempt to make OverrideForumDefaults not always slow --- src/plugins/overrideForumDefaults/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/overrideForumDefaults/index.tsx b/src/plugins/overrideForumDefaults/index.tsx index be106ac8..a377fff5 100644 --- a/src/plugins/overrideForumDefaults/index.tsx +++ b/src/plugins/overrideForumDefaults/index.tsx @@ -36,11 +36,11 @@ export default definePlugin({ find: "getDefaultLayout(){", replacement: [ { - match: /getDefaultLayout\(\){/, + match: /}getDefaultLayout\(\){/, replace: "$&return $self.getLayout();" }, { - match: /getDefaultSortOrder\(\){/, + match: /}getDefaultSortOrder\(\){/, replace: "$&return $self.getSortOrder();" } ] From 3abb5fcda8eb449ca0b7fd4345253f33d5b105b1 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 14 Jul 2025 21:02:44 -0300 Subject: [PATCH 24/25] Fix Plugin Settings broken webpack find --- src/components/PluginSettings/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/PluginSettings/index.tsx b/src/components/PluginSettings/index.tsx index 4d4e41e7..acfb0609 100644 --- a/src/components/PluginSettings/index.tsx +++ b/src/components/PluginSettings/index.tsx @@ -45,7 +45,7 @@ const { startDependenciesRecursive, startPlugin, stopPlugin } = proxyLazy(() => const cl = classNameFactory("vc-plugins-"); const logger = new Logger("PluginSettings", "#a6d189"); -const InputStyles = findByPropsLazy("inputWrapper", "inputDefault", "error"); +const InputStyles = findByPropsLazy("inputWrapper", "inputError", "error"); const ButtonClasses = findByPropsLazy("button", "disabled", "enabled"); @@ -349,7 +349,7 @@ export default function PluginSettings() { select={onStatusChange} isSelected={v => v === searchValue.status} closeOnSelect={true} - className={InputStyles.inputDefault} + className={InputStyles.input} /> </div> </div> From 35509f74122533ba0315cc8520f469103eee00b9 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 14 Jul 2025 21:05:04 -0300 Subject: [PATCH 25/25] Bump to v1.12.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 81b9a1c5..577bf39d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vencord", "private": "true", - "version": "1.12.5", + "version": "1.12.6", "description": "The cutest Discord client mod", "homepage": "https://github.com/Vendicated/Vencord#readme", "bugs": {