diff --git a/.gitignore b/.gitignore index 9f877c05..e45af171 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,4 @@ lerna-debug.log* src/userplugins ExtensionCache/ -settings/ +/settings diff --git a/.vscode/settings.json b/.vscode/settings.json index fa543b38..fe123188 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,11 +13,14 @@ "typescript.format.semicolons": "insert", "typescript.preferences.quoteStyle": "double", "javascript.preferences.quoteStyle": "double", - "gitlens.remotes": [ { "domain": "codeberg.org", "type": "Gitea" } - ] -} + ], + "css.format.spaceAroundSelectorSeparator": true, + "[css]": { + "editor.defaultFormatter": "vscode.css-language-features" + } +} \ No newline at end of file diff --git a/README.md b/README.md index 61575d4b..52d3c1b6 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,21 @@ # Vencord +![](https://img.shields.io/github/package-json/v/Vendicated/Vencord?style=for-the-badge&logo=github&logoColor=d3869b&label=&color=1d2021&labelColor=282828) [![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,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAKbUlEQVR4nNVae3AV5RX/nW/3Pva+b24e5HHzIICQKGoiYiW8NFBFgohaa6ctglpbFSujSGurzUinohWsOij/gGX6R2fqOK0d1FYTEZXaTrWCBbEikJCEyCvkeXNvkrunf+zdkJDkPnex/c3cmd29+53v/M6e73znnF2Cydj4Tntldzi6qrN/qKqzf2jy6b7BnL4B1dI7oMp9AyoRAIdVsNMqhlxWMZjtspzyK/Jhr036OMsm//bh2vzPzNSPzBD6xFutd7R0Dq758ky4orkjYuc05RCAkixbeEq2/UCJ1/LczxcX/c5IPfU5DMHmxpbCpu7o1k/b+xc1n43YjJI7EqV+W2RmvuPt0oDjB2vn5bQbITNjAzzdeKK8qTO0bU9T77zucNQUjzofHrvENWWu3aUBZfW6+ZOOZiIrbYXrmUXo9daX3v6i667O/iGRiRLpwqtIvKDc+0efJ3hb/UIaSkdGWgZ4sqGt9r2m3lc/P9HvSWe80ZiRp3TPL/UsX1+bvyvVsSkb4NE3WjbuPNj5SM8Fcvdk4bAKrqvwv7DxhuCPUxmXNIn6XSy3nWr6R8OhrqrU1btwqJ3m/bgwu/SqZJdEUgbYsuuka09b9/4Pm3tLMlPvwuAbpe6m+RcplfdcURBKdG9CA2zZddLV2Nx1+JO2vlxj1LswqCpynlxc6SxLZIS40bueWfy9vXvv/xt5APhXa1/u7v+EPqvfxXK8++IaoO2Vpn9+cLS33FjVLhw+bOotOX7q6N/i3TOhAX7y+rHN/+sBLxm8fah71k93tjw/0f/jGuDJxtZrdh7setA8tS4sdn7eef+v3mmfP95/Ywxw6x9Yev9I35/6Iubv83WVfl5a6Uu3VkoavZEo7TnS/Vo98xi+Yy6UKC3bDp7sd5ut1OWFDjyzNMib6oq5Oug0ezp8dqLfG3r92Nbzr48ywNONJ8obDnV/z2xlAk4ZW1aUqhaJIAvCb5YVqwFn3GBtCBoO9dz5TOPxUbnMKAM0dYa2d5lc2AgCNi8r5klui3aBgWynjE11QZbI3FV3NjQkjnYNbB+lj36wubGlcE9T71xTNQDw0Px8nlvmHl73GmfCrKCL19Tkmh4P9jT1LHz2vVP5+vmwAZq71a1m1/PXTPXwD68eS5KIEVUZd1yZwwumeEw1Qld/lJrPhF7Sz4cNsO+rUK2ZExd6rfj10iCPZ2GJCCoAZuCJxQUc9FvNVAX72kPX6ccC0Hp4zR0Ru1kT2mTCSzeXqn5l/EAniMAqoDLDYZWwqa5EVSzmhaKmsxHbLxvbbgdiBmjpHFxj2mwANlxXxBdPUib8nwgQgqAyEFUZxT4L1i/MN3UpHDsTWQvEDHDoTLjCrIluuyzAt8zMSkhGFhp5hrYUFk3z8IqZftOMcKRj4GIAEM80tFccM8n9Z+Qq+MXigqRIWCQCMzQvYIbKwH1X53FFnjkr88iZsLKpoXWa6BiIrjbDzF67hK23lKp2Obm1LAstPEZVjTwDkAio/2ZQ9dolw/VjAB0DfKfoCg9WGy2cADy1NMhBX2rR3CIRGICq8rAhAg4Jj9UWsDBhg+4MR6vF2VC0zGjB99fk8eJp3pQdyyrRMHF9KURVxswCB6+alWO4o3b2RyeLU32D2UYKnVPm5gfm5qWlrF0Wo4hzbCmoDNw0089XlboNNcLpvsFc0RtRDXuNle+x4Lkbi9PO6WWJIBFGEY+qjGjswtq5eVzosRilLnoiUavoH1INiTCyIDy/vETNcmRW1dl0L4gRVxmx3YFhlwnrry1QrZIxASE0yJIIDaiGSHt8UQFXF2Ve1zusYgzxkXGhyGvFvePUE+mgfyAqhGqAqKWVPv5udbYhSjmtkpYWq6OJqzFjqCpjTpmbl1Rk3klSGRBWmTISNC3Hjo1LgoYFJ0GA1aIVR+cTVxlQoS2Pb18a4PLszMKXzSJYuCySmq4Al03CiytKVYfBhYvLKk1IXE+XLRLhwZp81WlNf26HTFHhd0jhdAYTgKduCPLkgPHfQjitYkLiAIEZBDBlu2R6aF7euCV2Mgg45bDw2qWOdAavnp3D109PPdlJBvpTnYg4kVY3MDMuylVw62WJi63x4LHLZ0TAIR9OdWBVodPUclUQwWmT4hLXfgCIUDfDi6oiR8rzBJzyl8LnkD9KZVCOU8aLN5eoshnJ+Qh4bFJC4gztmEjgrtk5anaKnWWfXfpIuBTLjmSpSILw/E0laq7LuGxsIngVCYmIa96hLRG3TaZ1C/KTfjAEQLFIO8TPFk7aH/RZI8kMWrdgEs8udqXLKSUoMkEW4ETEQTRsoHyPlVZfmVw+Uuy3hR9bVHBQAMD0XPu/Ew24dqqH777K/La1DiKCxyYlRRzQymgG4+oyDxZOTdxZnp5r3wvEWmJ5btuL8W4uzbJh87LitLebdOFVpKSJx4IlwIzbL81CcYLO8iSX/IImGQCYae6Wg/2tXQNjNnW7LPDKyilqZd7ETU2zEBlifNTSS4i9PNFIx44x4jh2nZlBsUr0dN8QP/6XVhEaHJvnlfhtkXd/NF0BUextKRFXFznfGk+JDdcX8tdBHtDa6YpFsB4I9ac88omf8wbEgqa2XAIOme6bM35foqrQ+QZIKwGG80ifVbrXZZNGDfhOVYBvviS9JMMoaP3AEcQpPnHdOxiMGXkKbrx4dGfZY5c4T8H9+vmwAeqXFLXOKXW9r59fWuDA44sKv1byAOBzyCkTH+kdS2f4MLPgXJI0p9T17vrFxcf181GVxEUB+0qfIqt+RcKWFSWGNR4ygd4RTpW4HiCJgFWzstmnSPA7ZLU827pypPwxDB/687GXl1X6Vs6bbGz/LRN80hZCT+yLFZ0cgHED4egACeiXm89GsP9EePuzy4rvGil7jAGYmQDsBjDHUBYZ4GhHBMfORigd4rpnyIS9u6d4rqgnGrUtjCmmSYuOqwB0GcwjbWh9xviurpNnxnDA1IspMPe6bOL755MHJvhKjIgOA7jbJD4pw22Thj+kSIW47h2KRaydVezeP57sCdspRPQqgGeNJJIuBAE+ReJUiOv32mXaXjPZs21C2QnmXgdghyEsMoRfkVMiDgCywF/by9z3xJMb1wCxeHAPgDczZpAh/Iq+HSYmDjCsstgThmf5t4ii8eQm7CgS0SCA5QBezoRApnBaBSyCEhIHCLJEb4ZUd+2SqZSwzE+qpUpEQ9CC4qb01M8cRIQsh8zxiKsMtsn08nvlnrpkyAPj5AGJwMw3AtgGwJ/q2ExxvHsQB74KxfKBMblAyGmTHq4pc4/5GjQeUm6qE9FrAK4E8H6ie41GlkN/jTk6F5Ak2ueUpNmpkgfSMAAAENERAAsB3AHgZDoy0oFdFnBYpXPEBfU4beLRD6Z4qmumug+kIzPjaoeZfQDWAHgAQFam8hLh4MkwWjsHemyS2OF08IYrCjynzZ4zKTCzi5nXMvOnzBw16bevIxR95JOj7DNKb1PqXWa+HMDtAGoBXII0lxq0N2OfAmgA8Hsi2muMhudgesHPzNkA5gKoADADwFRoS8UHQO+x9wLoBNAB4AsAnwM4AOADIjLVxf8L9kdXUOE0IskAAAAASUVORK5CYII=)](https://codeberg.org/Vee/cord) The cutest Discord client mod -| ![image](https://github.com/Vendicated/Vencord/assets/45497981/706722b1-32de-4d99-bee9-93993b504334) | -| :--------------------------------------------------------------------------------------------------: | -| A screenshot of vencord showcasing the [vencord-theme](https://github.com/synqat/vencord-theme) | +![](https://github.com/user-attachments/assets/3fac98c0-c411-4d2a-97a3-13b7da8687a2) ## Features -- Super easy to install (Download Installer, open, click install button, done) -- 100+ plugins built in: [See a list](https://vencord.dev/plugins) - - Some highlights: SpotifyControls, MessageLogger, Experiments, GameActivityToggle, Translate, NoTrack, QuickReply, Free Emotes/Stickers, PermissionsViewer, CustomCommands, ShowHiddenChannels, PronounDB +- Easy to install +- [100+ built in plugins](https://vencord.dev/plugins) - Fairly lightweight despite the many inbuilt plugins - Excellent Browser Support: Run Vencord in your Browser via extension or UserScript -- Works on any Discord branch: Stable, Canary or PTB all work (though for the best experience I recommend stable!) +- Works on any Discord branch: Stable, Canary or PTB all work - Custom CSS and Themes: Inbuilt css editor with support to import any css files (including BetterDiscord themes) -- Privacy friendly, blocks Discord analytics & crash reporting out of the box and has no telemetry +- Privacy friendly: blocks Discord analytics & crash reporting out of the box and has no telemetry - Maintained very actively, broken plugins are usually fixed within 12 hours - Settings sync: Keep your plugins and their settings synchronised between devices / apps (optional) diff --git a/browser/VencordNativeStub.ts b/browser/VencordNativeStub.ts index 79f0f2cd..c99c176c 100644 --- a/browser/VencordNativeStub.ts +++ b/browser/VencordNativeStub.ts @@ -20,16 +20,13 @@ /// import monacoHtmlLocal from "file://monacoWin.html?minify"; -import monacoHtmlCdn from "file://../src/main/monacoWin.html?minify"; import * as DataStore from "../src/api/DataStore"; -import { debounce } from "../src/utils"; +import { debounce, localStorage } from "../src/utils"; import { EXTENSION_BASE_URL } from "../src/utils/web-metadata"; import { getTheme, Theme } from "../src/utils/discord"; import { getThemeInfo } from "../src/main/themes"; import { Settings } from "../src/Vencord"; - -// Discord deletes this so need to store in variable -const { localStorage } = window; +import { getStylusWebStoreUrl } from "@utils/web"; // listeners for ipc.on const cssListeners = new Set<(css: string) => void>(); @@ -45,12 +42,13 @@ window.VencordNative = { themes: { uploadTheme: (fileName: string, fileData: string) => DataStore.set(fileName, fileData, themeStore), deleteTheme: (fileName: string) => DataStore.del(fileName, themeStore), - getThemesDir: async () => "", getThemesList: () => DataStore.entries(themeStore).then(entries => entries.map(([name, css]) => getThemeInfo(css, name.toString())) ), getThemeData: (fileName: string) => DataStore.get(fileName, themeStore), getSystemValues: async () => ({}), + + openFolder: async () => Promise.reject("themes:openFolder is not supported on web"), }, native: { @@ -77,6 +75,14 @@ window.VencordNative = { addThemeChangeListener: NOOP, openFile: NOOP_ASYNC, async openEditor() { + if (IS_USERSCRIPT) { + const shouldOpenWebStore = confirm("QuickCSS is not supported on the Userscript. You can instead use the Stylus extension.\n\nDo you want to open the Stylus web store page?"); + if (shouldOpenWebStore) { + window.open(getStylusWebStoreUrl(), "_blank"); + } + return; + } + const features = `popup,width=${Math.min(window.innerWidth, 1000)},height=${Math.min(window.innerHeight, 1000)}`; const win = open("about:blank", "VencordQuickCss", features); if (!win) { @@ -92,7 +98,7 @@ window.VencordNative = { ? "vs-light" : "vs-dark"; - win.document.write(IS_EXTENSION ? monacoHtmlLocal : monacoHtmlCdn); + win.document.write(monacoHtmlLocal); }, }, @@ -106,8 +112,9 @@ window.VencordNative = { } }, set: async (s: Settings) => localStorage.setItem("VencordSettings", JSON.stringify(s)), - getSettingsDir: async () => "LocalStorage" + openFolder: async () => Promise.reject("settings:openFolder is not supported on web"), }, pluginHelpers: {} as any, + csp: {} as any, }; diff --git a/package.json b/package.json index 4c6d5023..4f05e969 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vencord", "private": "true", - "version": "1.12.2", + "version": "1.13.0", "description": "The cutest Discord client mod", "homepage": "https://github.com/Vendicated/Vencord#readme", "bugs": { @@ -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/CONTRIBUTING.md b/packages/discord-types/CONTRIBUTING.md new file mode 100644 index 00000000..3bef4092 --- /dev/null +++ b/packages/discord-types/CONTRIBUTING.md @@ -0,0 +1 @@ +Hint: https://docs.discord.food is an incredible resource and allows you to copy paste complete enums and interfaces 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. + 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/activity.ts b/packages/discord-types/enums/activity.ts new file mode 100644 index 00000000..513a65de --- /dev/null +++ b/packages/discord-types/enums/activity.ts @@ -0,0 +1,30 @@ +export const enum ActivityType { + PLAYING = 0, + STREAMING = 1, + LISTENING = 2, + WATCHING = 3, + CUSTOM_STATUS = 4, + COMPETING = 5, + HANG_STATUS = 6 +} + +export const enum ActivityFlags { + INSTANCE = 1 << 0, + JOIN = 1 << 1, + /** @deprecated */ + SPECTATE = 1 << 2, + /** @deprecated */ + JOIN_REQUEST = 1 << 3, + SYNC = 1 << 4, + PLAY = 1 << 5, + PARTY_PRIVACY_FRIENDS = 1 << 6, + PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7, + EMBEDDED = 1 << 8, + CONTEXTLESS = 1 << 9 +} + +export const enum ActivityStatusDisplayType { + NAME = 0, + STATE = 1, + DETAILS = 2 +} diff --git a/packages/discord-types/enums/channel.ts b/packages/discord-types/enums/channel.ts new file mode 100644 index 00000000..7aae546b --- /dev/null +++ b/packages/discord-types/enums/channel.ts @@ -0,0 +1,15 @@ +export const enum ChannelType { + GUILD_TEXT = 0, + DM = 1, + GUILD_VOICE = 2, + GROUP_DM = 3, + GUILD_CATEGORY = 4, + GUILD_ANNOUNCEMENT = 5, + ANNOUNCEMENT_THREAD = 10, + PUBLIC_THREAD = 11, + PRIVATE_THREAD = 12, + GUILD_STAGE_VOICE = 13, + GUILD_DIRECTORY = 14, + GUILD_FORUM = 15, + GUILD_MEDIA = 16 +} \ No newline at end of file diff --git a/packages/discord-types/enums/commands.ts b/packages/discord-types/enums/commands.ts new file mode 100644 index 00000000..298f9b7a --- /dev/null +++ b/packages/discord-types/enums/commands.ts @@ -0,0 +1,32 @@ +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, +} + +export const enum ApplicationIntegrationType { + GUILD_INSTALL = 0, + USER_INSTALL = 1 +} diff --git a/packages/discord-types/enums/index.ts b/packages/discord-types/enums/index.ts new file mode 100644 index 00000000..a25ff3b5 --- /dev/null +++ b/packages/discord-types/enums/index.ts @@ -0,0 +1,5 @@ +export * from "./activity"; +export * from "./channel"; +export * from "./commands"; +export * from "./messages"; +export * from "./misc"; diff --git a/packages/discord-types/enums/messages.ts b/packages/discord-types/enums/messages.ts new file mode 100644 index 00000000..8aa6fbb3 --- /dev/null +++ b/packages/discord-types/enums/messages.ts @@ -0,0 +1,596 @@ +export const enum StickerType { + /** an official sticker in a pack */ + STANDARD = 1, + /** a sticker uploaded to a guild for the guild's members */ + GUILD = 2 +} + +export const enum StickerFormatType { + PNG = 1, + APNG = 2, + LOTTIE = 3, + GIF = 4 +} + +export const enum MessageType { + /** + * A default message (see below) + * + * Value: 0 + * Name: DEFAULT + * Rendered Content: "{content}" + * Deletable: true + */ + DEFAULT = 0, + /** + * A message sent when a user is added to a group DM or thread + * + * Value: 1 + * Name: RECIPIENT_ADD + * Rendered Content: "{author} added {mentions [0] } to the {group/thread}." + * Deletable: false + */ + RECIPIENT_ADD = 1, + /** + * A message sent when a user is removed from a group DM or thread + * + * Value: 2 + * Name: RECIPIENT_REMOVE + * Rendered Content: "{author} removed {mentions [0] } from the {group/thread}." + * Deletable: false + */ + RECIPIENT_REMOVE = 2, + /** + * A message sent when a user creates a call in a private channel + * + * Value: 3 + * Name: CALL + * Rendered Content: participated ? "{author} started a call{ended ? " that lasted {duration}" : " — Join the call"}." : "You missed a call from {author} that lasted {duration}." + * Deletable: false + */ + CALL = 3, + /** + * A message sent when a group DM or thread's name is changed + * + * Value: 4 + * Name: CHANNEL_NAME_CHANGE + * Rendered Content: "{author} changed the {is_forum ? "post title" : "channel name"}: {content} " + * Deletable: false + */ + CHANNEL_NAME_CHANGE = 4, + /** + * A message sent when a group DM's icon is changed + * + * Value: 5 + * Name: CHANNEL_ICON_CHANGE + * Rendered Content: "{author} changed the channel icon." + * Deletable: false + */ + CHANNEL_ICON_CHANGE = 5, + /** + * A message sent when a message is pinned in a channel + * + * Value: 6 + * Name: CHANNEL_PINNED_MESSAGE + * Rendered Content: "{author} pinned a message to this channel." + * Deletable: true + */ + CHANNEL_PINNED_MESSAGE = 6, + /** + * A message sent when a user joins a guild + * + * Value: 7 + * Name: USER_JOIN + * Rendered Content: See user join message type , obtained via the formula timestamp_ms % 13 + * Deletable: true + */ + USER_JOIN = 7, + /** + * A message sent when a user subscribes to (boosts) a guild + * + * Value: 8 + * Name: PREMIUM_GUILD_SUBSCRIPTION + * Rendered Content: "{author} just boosted the server{content ? " {content} times"}!" + * Deletable: true + */ + PREMIUM_GUILD_SUBSCRIPTION = 8, + /** + * A message sent when a user subscribes to (boosts) a guild to tier 1 + * + * Value: 9 + * Name: PREMIUM_GUILD_SUBSCRIPTION_TIER_1 + * Rendered Content: "{author} just boosted the server{content ? " {content} times"}! {guild} has achieved Level 1! " + * Deletable: true + */ + PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9, + /** + * A message sent when a user subscribes to (boosts) a guild to tier 2 + * + * Value: 10 + * Name: PREMIUM_GUILD_SUBSCRIPTION_TIER_2 + * Rendered Content: "{author} just boosted the server{content ? " {content} times"}! {guild} has achieved Level 2! " + * Deletable: true + */ + PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10, + /** + * A message sent when a user subscribes to (boosts) a guild to tier 3 + * + * Value: 11 + * Name: PREMIUM_GUILD_SUBSCRIPTION_TIER_3 + * Rendered Content: "{author} just boosted the server{content ? " {content} times"}! {guild} has achieved Level 3! " + * Deletable: true + */ + PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11, + /** + * A message sent when a news channel is followed + * + * Value: 12 + * Name: CHANNEL_FOLLOW_ADD + * Rendered Content: "{author} has added {content} to this channel. Its most important updates will show up here." + * Deletable: true + */ + CHANNEL_FOLLOW_ADD = 12, + /** + * A message sent when a guild is disqualified from discovery + * + * Value: 14 + * Name: GUILD_DISCOVERY_DISQUALIFIED + * Rendered Content: "This server has been removed from Server Discovery because it no longer passes all the requirements. Check Server Settings for more details." + * Deletable: true + */ + GUILD_DISCOVERY_DISQUALIFIED = 14, + /** + * A message sent when a guild requalifies for discovery + * + * Value: 15 + * Name: GUILD_DISCOVERY_REQUALIFIED + * Rendered Content: "This server is eligible for Server Discovery again and has been automatically relisted!" + * Deletable: true + */ + GUILD_DISCOVERY_REQUALIFIED = 15, + /** + * A message sent when a guild has failed discovery requirements for a week + * + * Value: 16 + * Name: GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING + * Rendered Content: "This server has failed Discovery activity requirements for 1 week. If this server fails for 4 weeks in a row, it will be automatically removed from Discovery." + * Deletable: true + */ + GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING = 16, + /** + * A message sent when a guild has failed discovery requirements for 3 weeks + * + * Value: 17 + * Name: GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING + * Rendered Content: "This server has failed Discovery activity requirements for 3 weeks in a row. If this server fails for 1 more week, it will be removed from Discovery." + * Deletable: true + */ + GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING = 17, + /** + * A message sent when a thread is created + * + * Value: 18 + * Name: THREAD_CREATED + * Rendered Content: "{author} started a thread: {content} . See all threads." + * Deletable: true + */ + THREAD_CREATED = 18, + /** + * A message sent when a user replies to a message + * + * Value: 19 + * Name: REPLY + * Rendered Content: "{content}" + * Deletable: true + */ + REPLY = 19, + /** + * A message sent when a user uses a slash command + * + * Value: 20 + * Name: CHAT_INPUT_COMMAND + * Rendered Content: "{content}" + * Deletable: true + */ + CHAT_INPUT_COMMAND = 20, + /** + * A message sent when a thread starter message is added to a thread + * + * Value: 21 + * Name: THREAD_STARTER_MESSAGE + * Rendered Content: "{referenced_message?.content}" ?? "Sorry, we couldn't load the first message in this thread" + * Deletable: false + */ + THREAD_STARTER_MESSAGE = 21, + /** + * A message sent to remind users to invite friends to a guild + * + * Value: 22 + * Name: GUILD_INVITE_REMINDER + * Rendered Content: "Wondering who to invite?\nStart by inviting anyone who can help you build the server!" + * Deletable: true + */ + GUILD_INVITE_REMINDER = 22, + /** + * A message sent when a user uses a context menu command + * + * Value: 23 + * Name: CONTEXT_MENU_COMMAND + * Rendered Content: "{content}" + * Deletable: true + */ + CONTEXT_MENU_COMMAND = 23, + /** + * A message sent when auto moderation takes an action + * + * Value: 24 + * Name: AUTO_MODERATION_ACTION + * Rendered Content: Special embed rendered from embeds[0] + * Deletable: true 1 + */ + AUTO_MODERATION_ACTION = 24, + /** + * A message sent when a user purchases or renews a role subscription + * + * Value: 25 + * Name: ROLE_SUBSCRIPTION_PURCHASE + * Rendered Content: "{author} {is_renewal ? "renewed" : "joined"} {role_subscription.tier_name} and has been a subscriber of {guild} for {role_subscription.total_months_subscribed} month(?s)!" + * Deletable: true + */ + ROLE_SUBSCRIPTION_PURCHASE = 25, + /** + * A message sent when a user is upsold to a premium interaction + * + * Value: 26 + * Name: INTERACTION_PREMIUM_UPSELL + * Rendered Content: "{content}" + * Deletable: true + */ + INTERACTION_PREMIUM_UPSELL = 26, + /** + * A message sent when a stage channel starts + * + * Value: 27 + * Name: STAGE_START + * Rendered Content: "{author} started {content} " + * Deletable: true + */ + STAGE_START = 27, + /** + * A message sent when a stage channel ends + * + * Value: 28 + * Name: STAGE_END + * Rendered Content: "{author} ended {content} " + * Deletable: true + */ + STAGE_END = 28, + /** + * A message sent when a user starts speaking in a stage channel + * + * Value: 29 + * Name: STAGE_SPEAKER + * Rendered Content: "{author} is now a speaker." + * Deletable: true + */ + STAGE_SPEAKER = 29, + /** + * A message sent when a user raises their hand in a stage channel + * + * Value: 30 + * Name: STAGE_RAISE_HAND + * Rendered Content: "{author} requested to speak." + * Deletable: true + */ + STAGE_RAISE_HAND = 30, + /** + * A message sent when a stage channel's topic is changed + * + * Value: 31 + * Name: STAGE_TOPIC + * Rendered Content: "{author} changed the Stage topic: {content} " + * Deletable: true + */ + STAGE_TOPIC = 31, + /** + * A message sent when a user purchases an application premium subscription + * + * Value: 32 + * Name: GUILD_APPLICATION_PREMIUM_SUBSCRIPTION + * Rendered Content: "{author} upgraded {application ?? "a deleted application"} to premium for this server!" + * Deletable: true + */ + GUILD_APPLICATION_PREMIUM_SUBSCRIPTION = 32, + /** + * A message sent when a user gifts a premium (Nitro) referral + * + * Value: 35 + * Name: PREMIUM_REFERRAL + * Rendered Content: "{content}" + * Deletable: true + */ + PREMIUM_REFERRAL = 35, + /** + * A message sent when a user enabled lockdown for the guild + * + * Value: 36 + * Name: GUILD_INCIDENT_ALERT_MODE_ENABLED + * Rendered Content: "{author} enabled security actions until {content}." + * Deletable: true + */ + GUILD_INCIDENT_ALERT_MODE_ENABLED = 36, + /** + * A message sent when a user disables lockdown for the guild + * + * Value: 37 + * Name: GUILD_INCIDENT_ALERT_MODE_DISABLED + * Rendered Content: "{author} disabled security actions." + * Deletable: true + */ + GUILD_INCIDENT_ALERT_MODE_DISABLED = 37, + /** + * A message sent when a user reports a raid for the guild + * + * Value: 38 + * Name: GUILD_INCIDENT_REPORT_RAID + * Rendered Content: "{author} reported a raid in {guild}." + * Deletable: true + */ + GUILD_INCIDENT_REPORT_RAID = 38, + /** + * A message sent when a user reports a false alarm for the guild + * + * Value: 39 + * Name: GUILD_INCIDENT_REPORT_FALSE_ALARM + * Rendered Content: "{author} reported a false alarm in {guild}." + * Deletable: true + */ + GUILD_INCIDENT_REPORT_FALSE_ALARM = 39, + /** + * A message sent when no one sends a message in the current channel for 1 hour + * + * Value: 40 + * Name: GUILD_DEADCHAT_REVIVE_PROMPT + * Rendered Content: "{content}" + * Deletable: true + */ + GUILD_DEADCHAT_REVIVE_PROMPT = 40, + /** + * A message sent when a user buys another user a gift + * + * Value: 41 + * Name: CUSTOM_GIFT + * Rendered Content: Special embed rendered from embeds[0].url and gift_info + * Deletable: true + */ + CUSTOM_GIFT = 41, + /** + * Value: 42 + * Name: GUILD_GAMING_STATS_PROMPT + * Rendered Content: "{content}" + * Deletable: true + */ + GUILD_GAMING_STATS_PROMPT = 42, + /** + * A message sent when a user purchases a guild product + * + * Value: 44 + * Name: PURCHASE_NOTIFICATION + * Rendered Content: "{author} has purchased {purchase_notification.guild_product_purchase.product_name}!" + * Deletable: true + */ + PURCHASE_NOTIFICATION = 44, + /** + * A message sent when a poll is finalized + * + * Value: 46 + * Name: POLL_RESULT + * Rendered Content: Special embed rendered from embeds[0] + * Deletable: true + */ + POLL_RESULT = 46, + /** + * A message sent by the Discord Updates account when a new changelog is posted + * + * Value: 47 + * Name: CHANGELOG + * Rendered Content: "{content}" + * Deletable: true + */ + CHANGELOG = 47, + /** + * A message sent when a Nitro promotion is triggered + * + * Value: 48 + * Name: NITRO_NOTIFICATION + * Rendered Content: Special embed rendered from content + * Deletable: true + */ + NITRO_NOTIFICATION = 48, + /** + * A message sent when a voice channel is linked to a lobby + * + * Value: 49 + * Name: CHANNEL_LINKED_TO_LOBBY + * Rendered Content: "{content}" + * Deletable: true + */ + CHANNEL_LINKED_TO_LOBBY = 49, + /** + * A local-only ephemeral message sent when a user is prompted to gift Nitro to a friend on their friendship anniversary + * + * Value: 50 + * Name: GIFTING_PROMPT + * Rendered Content: Special embed + * Deletable: true + */ + GIFTING_PROMPT = 50, + /** + * A local-only message sent when a user receives an in-game message NUX + * + * Value: 51 + * Name: IN_GAME_MESSAGE_NUX + * Rendered Content: "{author} messaged you from {application.name}. In-game chat may not include rich messaging features such as images, polls, or apps. Learn More " + * Deletable: true + */ + IN_GAME_MESSAGE_NUX = 51, + /** + * A message sent when a user accepts a guild join request + * + * Value: 52 + * Name: GUILD_JOIN_REQUEST_ACCEPT_NOTIFICATION 2 + * Rendered Content: "{join_request.user}'s application to {content} was approved! Welcome!" + * Deletable: true + */ + GUILD_JOIN_REQUEST_ACCEPT_NOTIFICATION = 52, + /** + * A message sent when a user rejects a guild join request + * + * Value: 53 + * Name: GUILD_JOIN_REQUEST_REJECT_NOTIFICATION 2 + * Rendered Content: "{join_request.user}'s application to {content} was rejected." + * Deletable: true + */ + GUILD_JOIN_REQUEST_REJECT_NOTIFICATION = 53, + /** + * A message sent when a user withdraws a guild join request + * + * Value: 54 + * Name: GUILD_JOIN_REQUEST_WITHDRAWN_NOTIFICATION 2 + * Rendered Content: "{join_request.user}'s application to {content} has been withdrawn." + * Deletable: true + */ + GUILD_JOIN_REQUEST_WITHDRAWN_NOTIFICATION = 54, + /** + * A message sent when a user upgrades to HD streaming + * + * Value: 55 + * Name: HD_STREAMING_UPGRADED + * Rendered Content: "{author} activated HD Splash Potion " + * Deletable: true + */ + HD_STREAMING_UPGRADED = 55, + /** + * A message sent when a user resolves a moderation report by deleting the offending message + * + * Value: 58 + * Name: REPORT_TO_MOD_DELETED_MESSAGE + * Rendered Content: "{author} deleted the message" + * Deletable: true + */ + REPORT_TO_MOD_DELETED_MESSAGE = 58, + /** + * A message sent when a user resolves a moderation report by timing out the offending user + * + * Value: 59 + * Name: REPORT_TO_MOD_TIMEOUT_USER + * Rendered Content: "{author} timed out {mentions [0] }" + * Deletable: true + */ + REPORT_TO_MOD_TIMEOUT_USER = 59, + /** + * A message sent when a user resolves a moderation report by kicking the offending user + * + * Value: 60 + * Name: REPORT_TO_MOD_KICK_USER + * Rendered Content: "{author} kicked {mentions [0] }" + * Deletable: true + */ + REPORT_TO_MOD_KICK_USER = 60, + /** + * A message sent when a user resolves a moderation report by banning the offending user + * + * Value: 61 + * Name: REPORT_TO_MOD_BAN_USER + * Rendered Content: "{author} banned {mentions [0] }" + * Deletable: true + */ + REPORT_TO_MOD_BAN_USER = 61, + /** + * A message sent when a user resolves a moderation report + * + * Value: 62 + * Name: REPORT_TO_MOD_CLOSED_REPORT + * Rendered Content: "{author} resolved this flag" + * Deletable: true + */ + REPORT_TO_MOD_CLOSED_REPORT = 62, + /** + * A message sent when a user adds a new emoji to a guild + * + * Value: 63 + * Name: EMOJI_ADDED + * Rendered Content: "{author} added a new emoji, {content} :{emoji.name}: " + * Deletable: true + */ + EMOJI_ADDED = 63, +} + +export const enum MessageFlags { + /** + * Message has been published to subscribed channels (via Channel Following) + * + * Value: 1 << 0 + */ + CROSSPOSTED = 1 << 0, + /** + * Message originated from a message in another channel (via Channel Following) + */ + IS_CROSSPOST = 1 << 1, + /** + * Embeds will not be included when serializing this message + */ + SUPPRESS_EMBEDS = 1 << 2, + /** + * Source message for this crosspost has been deleted (via Channel Following) + */ + SOURCE_MESSAGE_DELETED = 1 << 3, + /** + * Message came from the urgent message system + */ + URGENT = 1 << 4, + /** + * Message has an associated thread, with the same ID as the message + */ + HAS_THREAD = 1 << 5, + /** + * Message is only visible to the user who invoked the interaction + */ + EPHEMERAL = 1 << 6, + /** + * Message is an interaction response and the bot is "thinking" + */ + LOADING = 1 << 7, + /** + * Some roles were not mentioned and added to the thread + */ + FAILED_TO_MENTION_SOME_ROLES_IN_THREAD = 1 << 8, + /** + * Message is hidden from the guild's feed + */ + GUILD_FEED_HIDDEN = 1 << 9, + /** + * Message contains a link that impersonates Discord + */ + SHOULD_SHOW_LINK_NOT_DISCORD_WARNING = 1 << 10, + /** + * Message will not trigger push and desktop notifications + */ + SUPPRESS_NOTIFICATIONS = 1 << 12, + /** + * Message's audio attachment is rendered as a voice message + */ + IS_VOICE_MESSAGE = 1 << 13, + /** + * Message has a forwarded message snapshot attached + */ + HAS_SNAPSHOT = 1 << 14, + /** + * Message contains components from version 2 of the UI kit + */ + IS_COMPONENTS_V2 = 1 << 15, + /** + * Message was triggered by the social layer integration + */ + SENT_BY_SOCIAL_LAYER_INTEGRATION = 1 << 16, +} diff --git a/packages/discord-types/enums/misc.ts b/packages/discord-types/enums/misc.ts new file mode 100644 index 00000000..d1419ba3 --- /dev/null +++ b/packages/discord-types/enums/misc.ts @@ -0,0 +1,4 @@ +export const enum CloudUploadPlatform { + REACT_NATIVE = 0, + WEB = 1, +} 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..a7260048 --- /dev/null +++ b/packages/discord-types/src/classes.d.ts @@ -0,0 +1,16 @@ +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/Activity.d.ts b/packages/discord-types/src/common/Activity.d.ts new file mode 100644 index 00000000..d513780a --- /dev/null +++ b/packages/discord-types/src/common/Activity.d.ts @@ -0,0 +1,36 @@ +import { ActivityFlags, ActivityStatusDisplayType, ActivityType } from "../../enums"; + +export interface ActivityAssets { + large_image?: string; + large_text?: string; + small_image?: string; + small_text?: string; +} + +export interface ActivityButton { + label: string; + url: string; +} + +export interface Activity { + name: string; + application_id: string; + type: ActivityType; + state?: string; + state_url?: string; + details?: string; + details_url?: string; + url?: string; + flags: ActivityFlags; + status_display_type?: ActivityStatusDisplayType; + timestamps?: { + start?: number; + end?: number; + }; + assets?: ActivityAssets; + buttons?: string[]; + metadata?: { + button_urls?: Array; + }; +} + 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/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; + 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; + 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; + }; + premiumProgressBarEnabled: boolean; + premiumSubscriberCount: number; + premiumTier: number; + profile: { + badge: string | undefined; + tag: string | undefined; + } | undefined; + publicUpdatesChannelId: string | undefined; + roles: Record; + 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; + + set(key: string, value: any): this; + merge(data: Record): 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..07eb4718 --- /dev/null +++ b/packages/discord-types/src/common/User.d.ts @@ -0,0 +1,65 @@ +// 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 | null | undefined; + bio: string; + bot: boolean; + desktop: boolean; + discriminator: string; + email: string | undefined; + flags: number; + globalName: string | undefined; + guildMemberAvatars: Record; + 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; + + 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..65ad8856 --- /dev/null +++ b/packages/discord-types/src/common/index.d.ts @@ -0,0 +1,9 @@ +export * from "./Activity"; +export * from "./Application"; +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; +} + +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; +} 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; + 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..c2af2496 --- /dev/null +++ b/packages/discord-types/src/common/messages/Message.d.ts @@ -0,0 +1,204 @@ +import { CommandOption } from './Commands'; +import { User, UserJSON } from '../User'; +import { Embed, EmbedJSON } from './Embed'; +import { DiscordRecord } from "../Record"; +import { MessageFlags, MessageType, StickerFormatType } from "../../../enums"; + +/* + * 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: MessageFlags; + 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; + messageSnapshots: { + message: Message; + }[]; + nick: unknown; // probably a string + nonce: string | undefined; + pinned: boolean; + reactions: MessageReaction[]; + state: string; + stickerItems: { + format_type: StickerFormatType; + id: string; + name: string; + }[]; + stickers: unknown[]; + timestamp: moment.Moment; + tts: boolean; + type: MessageType; + 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: MessageFlags): boolean; + isCommandType(): boolean; + isEdited(): boolean; + isSystemDM(): boolean; + + /** Vencord added */ + deleted?: 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; +} + +// Object.keys(findByProps("REPLYABLE")).map(JSON.stringify).join("|") +export type MessageTypeSets = Record< + "UNDELETABLE" | "GUILD_DISCOVERY_STATUS" | "USER_MESSAGE" | "NOTIFIABLE_SYSTEM_MESSAGE" | "REPLYABLE" | "FORWARDABLE" | "REFERENCED_MESSAGE_AVAILABLE" | "AVAILABLE_IN_GUILD_FEED" | "DEADCHAT_PROMPTS" | "NON_COLLAPSIBLE" | "NON_PARSED" | "AUTOMOD_INCIDENT_ACTIONS" | "SELF_MENTIONABLE_SYSTEM" | "SCHEDULABLE", + Set +>; diff --git a/packages/discord-types/src/common/messages/Sticker.d.ts b/packages/discord-types/src/common/messages/Sticker.d.ts new file mode 100644 index 00000000..744b0623 --- /dev/null +++ b/packages/discord-types/src/common/messages/Sticker.d.ts @@ -0,0 +1,35 @@ +import { StickerFormatType, StickerType } from "../../../enums"; + +interface BaseSticker { + asset: string; + available: boolean; + description: string; + format_type: StickerFormatType; + id: string; + name: string; + sort_value?: number; + /** a comma separated string */ + tags: string; +} + +export interface PackSticker extends BaseSticker { + pack_id: string; + type: StickerType.STANDARD; +} + +export interface GuildSticker extends BaseSticker { + guild_id: string; + type: StickerType.GUILD; +} + +export type Sticker = PackSticker | GuildSticker; + +export interface PremiumStickerPack { + banner_asset_id?: string; + cover_sticker_id?: string; + description: string; + id: string; + name: string; + sku_id: string; + stickers: PackSticker[]; +} 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..23987546 --- /dev/null +++ b/packages/discord-types/src/common/messages/index.d.ts @@ -0,0 +1,5 @@ +export * from "./Commands"; +export * from "./Message"; +export * from "./Embed"; +export * from "./Emoji"; +export * from "./Sticker"; diff --git a/src/webpack/common/types/components.d.ts b/packages/discord-types/src/components.d.ts similarity index 80% rename from src/webpack/common/types/components.d.ts rename to packages/discord-types/src/components.d.ts index 7a9e848b..f9e778d8 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 . -*/ - 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}`; @@ -61,12 +43,7 @@ export type FormDivider = ComponentType<{ }>; -export type FormText = ComponentType & TextProps> & { Types: FormTextTypes; }; +export type FormText = ComponentType; export type Tooltip = ComponentType<{ text: ReactNode | ComponentType; @@ -262,8 +239,10 @@ export type TextInput = ComponentType; }; +// FIXME: this is wrong, it's not actually just HTMLTextAreaElement export type TextArea = ComponentType, "onChange"> & { onChange(v: string): void; + inputRef?: Ref; }>; interface SelectOption { @@ -490,19 +469,66 @@ export type MaskedLink = ComponentType>; -export type ScrollerThin = ComponentType>; +interface BaseListItem { + anchorId: any; + listIndex: number; + offsetTop: number; + section: number; +} +interface ListSection extends BaseListItem { + type: "section"; +} +interface ListRow extends BaseListItem { + type: "row"; + row: number; + rowIndex: number; +} + +export type ListScrollerThin = ComponentType React.ReactNode; + renderRow: (item: ListRow) => React.ReactNode; + renderFooter?: (item: any) => React.ReactNode; + renderSidebar?: (listVisible: boolean, sidebarVisible: boolean) => React.ReactNode; + wrapSection?: (section: number, children: React.ReactNode) => React.ReactNode; + + sectionHeight: number; + rowHeight: number; + footerHeight?: number; + sidebarHeight?: number; + + chunkSize?: number; + + paddingTop?: number; + paddingBottom?: number; + fade?: boolean; + onResize?: Function; + getAnchorId?: any; + + innerTag?: string; + innerId?: string; + innerClassName?: string; + innerRole?: string; + innerAriaLabel?: string; + // Yes, Discord uses this casing + innerAriaMultiselectable?: boolean; + innerAriaOrientation?: "vertical" | "horizontal"; +}>; + export type Clickable = (props: PropsWithChildren> & { tag?: T; }) => ReactNode; @@ -536,3 +562,10 @@ export type Icon = ComponentType>; +export type ColorPicker = ComponentType<{ + color: number | null; + showEyeDropper?: boolean; + suggestedColors?: string[]; + label?: ReactNode; + onChange(value: number | null): void; +}>; 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; + isBatchEmitting: boolean; + isDispatching: boolean; + isPaused: boolean; + pauseTimer: NodeJS.Timeout | null; + reactChangedStores: Set; + + 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..fdbd65f1 --- /dev/null +++ b/packages/discord-types/src/index.d.ts @@ -0,0 +1,10 @@ +export * from "./common"; +export * from "./classes"; +export * from "./components"; +export * from "./flux"; +export * from "./fluxEvents"; +export * from "./menu"; +export * from "./modules"; +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 . -*/ - import type { ComponentType, CSSProperties, MouseEvent, PropsWithChildren, ReactNode, UIEvent } from "react"; type RC = ComponentType>>; @@ -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/modules/CloudUpload.d.ts b/packages/discord-types/src/modules/CloudUpload.d.ts new file mode 100644 index 00000000..02192ed5 --- /dev/null +++ b/packages/discord-types/src/modules/CloudUpload.d.ts @@ -0,0 +1,74 @@ +import EventEmitter from "events"; +import { CloudUploadPlatform } from "../../enums"; + +interface BaseUploadItem { + platform: CloudUploadPlatform; + id?: string; + origin?: string; + isThumbnail?: boolean; + clip?: unknown; +} + +export interface ReactNativeUploadItem extends BaseUploadItem { + platform: CloudUploadPlatform.REACT_NATIVE; + uri: string; + filename?: string; + mimeType?: string; + durationSecs?: number; + waveform?: string; + isRemix?: boolean; +} + +export interface WebUploadItem extends BaseUploadItem { + platform: CloudUploadPlatform.WEB; + file: File; +} + +export type CloudUploadItem = ReactNativeUploadItem | WebUploadItem; + +export class CloudUpload extends EventEmitter { + constructor(item: CloudUploadItem, channelId: string, showLargeMessageDialog?: boolean, reactNativeFileIndex?: number); + + channelId: string; + classification: string; + clip: unknown; + contentHash: unknown; + currentSize: number; + description: string | null; + durationSecs: number | undefined; + etag: string | undefined; + error: unknown; + filename: string; + id: string; + isImage: boolean; + isRemix: boolean | undefined; + isThumbnail: boolean; + isVideo: boolean; + item: { + file: File; + platform: CloudUploadPlatform; + origin: string; + }; + loaded: number; + mimeType: string; + origin: string; + postCompressionSize: number | undefined; + preCompressionSize: number; + responseUrl: string; + sensitive: boolean; + showLargeMessageDialog: boolean; + spoiler: boolean; + startTime: number; + status: "NOT_STARTED" | "STARTED" | "UPLOADING" | "ERROR" | "COMPLETED" | "CANCELLED" | "REMOVED_FROM_MSG_DRAFT"; + uniqueId: string; + uploadedFilename: string; + waveform: string | undefined; + + // there are many more methods than just these but I didn't find them particularly useful + upload(): Promise; + cancel(): void; + delete(): Promise; + getSize(): number; + maybeConvertToWebP(): Promise; + removeFromMsgDraft(): void; +} diff --git a/packages/discord-types/src/modules/index.d.ts b/packages/discord-types/src/modules/index.d.ts new file mode 100644 index 00000000..fe0c1e24 --- /dev/null +++ b/packages/discord-types/src/modules/index.d.ts @@ -0,0 +1 @@ +export * from "./CloudUpload"; diff --git a/packages/discord-types/src/stores/AuthenticationStore.d.ts b/packages/discord-types/src/stores/AuthenticationStore.d.ts new file mode 100644 index 00000000..3ad2354f --- /dev/null +++ b/packages/discord-types/src/stores/AuthenticationStore.d.ts @@ -0,0 +1,11 @@ +import { FluxStore } from ".."; + +export class AuthenticationStore extends FluxStore { + /** + * Gets the id of the current user + */ + getId(): string; + + // This Store has a lot more methods related to everything Auth, but they really should + // not be needed, so they are not typed +} 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; + getMutableGuildChannelsForGuild(guildId: string): Record; + getAllThreadsForGuild(guildId: string): Channel[]; + getAllThreadsForParent(channelId: string): Channel[]; + + getDMFromUserId(userId: string): string; + getDMChannelFromUserId(userId: string): Channel | undefined; + getDMUserIds(): string[]; + getMutableDMsByUserIds(): Record; + getMutablePrivateChannels(): Record; + getSortedPrivateChannels(): Channel[]; + + getGuildChannelsVersion(guildId: string): number; + getPrivateChannelsVersion(): number; + getInitialOverlayState(): Record; +} 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]: Draft; +}; + +export type UserDrafts = Partial>; +export type DraftState = Partial>; + +export class DraftStore extends FluxStore { + getState(): DraftState; + getRecentlyEditedDrafts(type: DraftType): Array; + 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; + 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; + customEmojis: Record; + emojisById: Record; + emojisByName: Record; + emoticonRegex: RegExp | null; + emoticonsByName: Record; + escapedEmoticonNames: string; + favoriteNamesAndIds?: any; + favorites?: any; + frequentlyUsed?: any; + groupedCustomEmojis: Record; + guildId?: string; + isFavoriteEmojiWithoutFetchingLatest(e: Emoji): boolean; + newlyAddedEmoji: Record; + topEmojis?: any; + unicodeAliases: Record; + 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>; + +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; + getCommunicationDisabledVersion(): number; + + getMutableAllGuildsAndMembers(): Record>; + + 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; + 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..faf586a0 --- /dev/null +++ b/packages/discord-types/src/stores/GuildRoleStore.d.ts @@ -0,0 +1,8 @@ +import { FluxStore, Role } from ".."; + +// TODO: add the rest of the methods for GuildRoleStore +export class GuildRoleStore extends FluxStore { + getRole(guildId: string, roleId: string): Role; + getSortedRoles(guildId: string): Role[]; + getRolesSnapshot(guildId: string): Record; +} 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; + 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; + 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..9aceac47 --- /dev/null +++ b/packages/discord-types/src/stores/RelationshipStore.d.ts @@ -0,0 +1,26 @@ +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; + /** + * @see {@link isBlocked} + * @see {@link isIgnored} + */ + isBlockedOrIgnored(userId: string): boolean; + getSince(userId: string): string; + + getMutableRelationships(): Map; +} 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; + 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/StickersStore.d.ts b/packages/discord-types/src/stores/StickersStore.d.ts new file mode 100644 index 00000000..fdfb012c --- /dev/null +++ b/packages/discord-types/src/stores/StickersStore.d.ts @@ -0,0 +1,15 @@ +import { FluxStore, GuildSticker, PremiumStickerPack, Sticker } from ".."; + +export type StickerGuildMap = Map; + +export class StickersStore extends FluxStore { + getAllGuildStickers(): StickerGuildMap; + getRawStickersByGuild(): StickerGuildMap; + getPremiumPacks(): PremiumStickerPack[]; + + getStickerById(id: string): Sticker | undefined; + getStickerPack(id: string): PremiumStickerPack | undefined; + getStickersByGuildId(guildId: string): Sticker[] | undefined; + + isPremiumPack(id: string): boolean; +} diff --git a/packages/discord-types/src/stores/StreamerModeStore.d.ts b/packages/discord-types/src/stores/StreamerModeStore.d.ts new file mode 100644 index 00000000..efa6cfc9 --- /dev/null +++ b/packages/discord-types/src/stores/StreamerModeStore.d.ts @@ -0,0 +1,11 @@ +import { FluxStore } from "@vencord/discord-types"; + +export class StreamerModeStore extends FluxStore { + get autoToggle(): boolean; + get disableNotifications(): boolean; + get disableSounds(): boolean; + get enableContentProtection(): boolean; + get enabled(): boolean; + get hideInstantInvites(): boolean; + get hidePersonalInformation(): boolean; +} 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; +} +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/TypingStore.d.ts b/packages/discord-types/src/stores/TypingStore.d.ts new file mode 100644 index 00000000..0ebe994f --- /dev/null +++ b/packages/discord-types/src/stores/TypingStore.d.ts @@ -0,0 +1,9 @@ +import { FluxStore } from ".."; + +export class TypingStore extends FluxStore { + /** + * returns a map of user ids to timeout ids + */ + getTypingUsers(channelId: string): Record; + isTyping(channelId: string, userId: string): boolean; +} 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; +} + +export interface ProfileApplication { + id: string; + customInstallUrl: string | undefined; + installParams: ApplicationInstallParams | undefined; + flags: number; + popularApplicationCommandIds?: string[]; + integrationTypesConfig: Record>; + primarySkuId: string | undefined; + storefront_available: boolean; +} + +export interface UserProfileBase extends Pick { + 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; + metadata: Record; + platform_name: string; + platform_username: string; +} + +export interface UserProfile extends UserProfileBase, Pick { + /** 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/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; + findByTag(username: string, discriminator: string): User; + forEach(action: (user: User) => void): void; + getCurrentUser(): User; + getUser(userId: string): User; + getUsers(): Record; +} diff --git a/packages/discord-types/src/stores/VoiceStateStore.d.ts b/packages/discord-types/src/stores/VoiceStateStore.d.ts new file mode 100644 index 00000000..84540d99 --- /dev/null +++ b/packages/discord-types/src/stores/VoiceStateStore.d.ts @@ -0,0 +1,42 @@ +import { DiscordRecord } from "../common"; +import { FluxStore } from "./FluxStore"; + +export type UserVoiceStateRecords = Record; +export type VoiceStates = Record; + +export interface VoiceState extends DiscordRecord { + userId: string; + channelId: string | null | undefined; + sessionId: string | null | undefined; + mute: boolean; + deaf: boolean; + selfMute: boolean; + selfDeaf: boolean; + selfVideo: boolean; + selfStream: boolean | undefined; + suppress: boolean; + requestToSpeakTimestamp: string | null | undefined; + discoverable: boolean; + + isVoiceMuted(): boolean; + isVoiceDeafened(): boolean; +} + +export class VoiceStateStore extends FluxStore { + getAllVoiceStates(): VoiceStates; + + getVoiceStates(guildId?: string | null): UserVoiceStateRecords; + getVoiceStatesForChannel(channelId: string): UserVoiceStateRecords; + getVideoVoiceStatesForChannel(channelId: string): UserVoiceStateRecords; + + getVoiceState(guildId: string | null, userId: string): VoiceState | undefined; + getUserVoiceChannelId(guildId: string | null, userId: string): string | undefined; + getVoiceStateForChannel(channelId: string, userId?: string): VoiceState | undefined; + getVoiceStateForUser(userId: string): VoiceState | undefined; + + getCurrentClientVoiceChannelId(guildId: string | null): string | undefined; + isCurrentClientInVoiceChannel(): boolean; + + isInChannel(channelId: string, userId?: string): boolean; + hasVideo(channelId: string): boolean; +} 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..a843445b --- /dev/null +++ b/packages/discord-types/src/stores/index.d.ts @@ -0,0 +1,38 @@ +// please keep in alphabetical order +export * from "./AuthenticationStore"; +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 "./StickersStore"; +export * from "./StreamerModeStore"; +export * from "./ThemeStore"; +export * from "./TypingStore"; +export * from "./UserProfileStore"; +export * from "./UserStore"; +export * from "./VoiceStateStore"; +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 = ( + 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 90% rename from src/webpack/common/types/utils.d.ts rename to packages/discord-types/src/utils.d.ts index cfea5d76..14b8fa50 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 . -*/ - -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"; @@ -24,13 +6,15 @@ import type { FluxEvents } from "./fluxEvents"; export { FluxEvents }; +type FluxEventsAutoComplete = LiteralUnion; + export interface FluxDispatcher { _actionHandlers: any; _subscriptions: any; - dispatch(event: { [key: string]: unknown; type: FluxEvents; }): Promise; + dispatch(event: { [key: string]: unknown; type: FluxEventsAutoComplete; }): Promise; isDispatching(): boolean; - subscribe(event: FluxEvents, callback: (data: any) => void): void; - unsubscribe(event: FluxEvents, callback: (data: any) => void): void; + subscribe(event: FluxEventsAutoComplete, callback: (data: any) => void): void; + unsubscribe(event: FluxEventsAutoComplete, callback: (data: any) => void): void; wait(callback: () => void): void; } @@ -335,3 +319,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> & { - /** The module factories, where all modules that have been loaded are stored (pre-loaded or loaded by lazy chunks) */ - m: Record; -}; - -/** 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; -}; - -export type PatchedModuleFactory = AnyModuleFactory & { - [SYM_ORIGINAL_FACTORY]: AnyModuleFactory; - [SYM_PATCHED_SOURCE]?: string; - [SYM_PATCHED_BY]?: Set; -}; - -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 7d21cd24..db0a1ce0 100755 --- a/scripts/build/build.mjs +++ b/scripts/build/build.mjs @@ -31,6 +31,7 @@ const defines = stringifyValues({ IS_UPDATER_DISABLED, IS_WEB: false, IS_EXTENSION: false, + IS_USERSCRIPT: false, VERSION, BUILD_TIMESTAMP }); @@ -50,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/buildWeb.mjs b/scripts/build/buildWeb.mjs index 824194cf..b22df8ab 100644 --- a/scripts/build/buildWeb.mjs +++ b/scripts/build/buildWeb.mjs @@ -43,6 +43,7 @@ const commonOptions = { define: stringifyValues({ IS_WEB: true, IS_EXTENSION: false, + IS_USERSCRIPT: false, IS_STANDALONE: true, IS_DEV, IS_REPORTER, @@ -98,6 +99,7 @@ const buildConfigs = [ inject: ["browser/GMPolyfill.js", ...(commonOptions?.inject || [])], define: { ...commonOptions.define, + IS_USERSCRIPT: "true", window: "unsafeWindow", }, outfile: "dist/Vencord.user.js", 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/Vencord.ts b/src/Vencord.ts index 48ecce97..00f29347 100644 --- a/src/Vencord.ts +++ b/src/Vencord.ts @@ -16,6 +16,9 @@ * along with this program. If not, see . */ +// DO NOT REMOVE UNLESS YOU WISH TO FACE THE WRATH OF THE CIRCULAR DEPENDENCY DEMON!!!!!!! +import "~plugins"; + export * as Api from "./api"; export * as Components from "./components"; export * as Plugins from "./plugins"; @@ -29,7 +32,8 @@ export { PlainSettings, Settings }; import "./utils/quickCss"; import "./webpack/patchWebpack"; -import { openUpdaterModal } from "@components/VencordSettings/UpdaterTab"; +import { openUpdaterModal } from "@components/settings/tabs/updater"; +import { IS_WINDOWS } from "@utils/constants"; import { StartAt } from "@utils/types"; import { get as dsGet } from "./api/DataStore"; @@ -134,7 +138,11 @@ async function init() { if (!IS_WEB && !IS_UPDATER_DISABLED) { runUpdateCheck(); - setInterval(runUpdateCheck, 1000 * 60 * 30); // 30 minutes + + // this tends to get really annoying, so only do this if the user has auto-update without notification enabled + if (Settings.autoUpdate && !Settings.autoUpdateNotification) { + setInterval(runUpdateCheck, 1000 * 60 * 30); // 30 minutes + } } if (IS_DEV) { @@ -157,7 +165,7 @@ init(); document.addEventListener("DOMContentLoaded", () => { startAllPlugins(StartAt.DOMContentLoaded); - if (IS_DISCORD_DESKTOP && Settings.winNativeTitleBar && navigator.platform.toLowerCase().startsWith("win")) { + if (IS_DISCORD_DESKTOP && Settings.winNativeTitleBar && IS_WINDOWS) { document.head.append(Object.assign(document.createElement("style"), { id: "vencord-native-titlebar-style", textContent: "[class*=titleBar]{display: none!important}" diff --git a/src/VencordNative.ts b/src/VencordNative.ts index 3bed5a59..048b30c7 100644 --- a/src/VencordNative.ts +++ b/src/VencordNative.ts @@ -5,6 +5,7 @@ */ import type { Settings } from "@api/Settings"; +import { CspRequestResult } from "@main/csp/manager"; import { PluginIpcMappings } from "@main/ipcPlugins"; import type { UserThemeHeader } from "@main/themes"; import { IpcEvents } from "@shared/IpcEvents"; @@ -33,10 +34,11 @@ export default { themes: { uploadTheme: (fileName: string, fileData: string) => invoke(IpcEvents.UPLOAD_THEME, fileName, fileData), deleteTheme: (fileName: string) => invoke(IpcEvents.DELETE_THEME, fileName), - getThemesDir: () => invoke(IpcEvents.GET_THEMES_DIR), getThemesList: () => invoke>(IpcEvents.GET_THEMES_LIST), getThemeData: (fileName: string) => invoke(IpcEvents.GET_THEME_DATA, fileName), getSystemValues: () => invoke>(IpcEvents.GET_THEME_SYSTEM_VALUES), + + openFolder: () => invoke(IpcEvents.OPEN_THEMES_FOLDER), }, updater: { @@ -49,7 +51,8 @@ export default { settings: { get: () => sendSync(IpcEvents.GET_SETTINGS), set: (settings: Settings, pathToNotify?: string) => invoke(IpcEvents.SET_SETTINGS, settings, pathToNotify), - getSettingsDir: () => invoke(IpcEvents.GET_SETTINGS_DIR), + + openFolder: () => invoke(IpcEvents.OPEN_SETTINGS_FOLDER), }, quickCss: { @@ -73,5 +76,17 @@ export default { openExternal: (url: string) => invoke(IpcEvents.OPEN_EXTERNAL, url) }, + csp: { + /** + * Note: Only supports full explicit matches, not wildcards. + * + * If `*.example.com` is allowed, `isDomainAllowed("https://sub.example.com")` will return false. + */ + isDomainAllowed: (url: string, directives: string[]) => invoke(IpcEvents.CSP_IS_DOMAIN_ALLOWED, url, directives), + removeOverride: (url: string) => invoke(IpcEvents.CSP_REMOVE_OVERRIDE, url), + requestAddOverride: (url: string, directives: string[], callerName: string) => + invoke(IpcEvents.CSP_REQUEST_ADD_OVERRIDE, url, directives, callerName), + }, + pluginHelpers: PluginHelpers }; diff --git a/src/api/Badges.ts b/src/api/Badges.ts index ee2f3a30..1345b26d 100644 --- a/src/api/Badges.ts +++ b/src/api/Badges.ts @@ -17,10 +17,9 @@ */ import ErrorBoundary from "@components/ErrorBoundary"; +import BadgeAPIPlugin from "plugins/_api/badges"; import { ComponentType, HTMLProps } from "react"; -import Plugins from "~plugins"; - export const enum BadgePosition { START, END @@ -35,7 +34,9 @@ export interface ProfileBadge { image?: string; link?: string; /** Action to perform when you click the badge */ - onClick?(event: React.MouseEvent, props: BadgeUserArgs): void; + onClick?(event: React.MouseEvent, props: ProfileBadge & BadgeUserArgs): void; + /** Action to perform when you right click the badge */ + onContextMenu?(event: React.MouseEvent, props: BadgeUserArgs & BadgeUserArgs): void; /** Should the user display this badge? */ shouldShow?(userInfo: BadgeUserArgs): boolean; /** Optional props (e.g. style) for the badge, ignored for component badges */ @@ -77,21 +78,34 @@ export function removeProfileBadge(badge: ProfileBadge) { export function _getBadges(args: BadgeUserArgs) { const badges = [] as ProfileBadge[]; for (const badge of Badges) { - if (!badge.shouldShow || badge.shouldShow(args)) { - const b = badge.getBadges - ? badge.getBadges(args).map(b => { - b.component &&= ErrorBoundary.wrap(b.component, { noop: true }); - return b; - }) - : [{ ...badge, ...args }]; + if (badge.shouldShow && !badge.shouldShow(args)) { + continue; + } - badge.position === BadgePosition.START - ? badges.unshift(...b) - : badges.push(...b); + const b = badge.getBadges + ? badge.getBadges(args).map(badge => ({ + ...args, + ...badge, + component: badge.component && ErrorBoundary.wrap(badge.component, { noop: true }) + })) + : [{ ...args, ...badge }]; + + if (badge.position === BadgePosition.START) { + badges.unshift(...b); + } else { + badges.push(...b); } } - const donorBadges = (Plugins.BadgeAPI as unknown as typeof import("../plugins/_api/badges").default).getDonorBadges(args.userId); - if (donorBadges) badges.unshift(...donorBadges); + + const donorBadges = BadgeAPIPlugin.getDonorBadges(args.userId); + if (donorBadges) { + badges.unshift( + ...donorBadges.map(badge => ({ + ...args, + ...badge, + })) + ); + } return badges; } 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) * @param fallbackValue Fallback value in case this option wasn't passed * @returns Value */ -export function findOption(args: Argument[], name: string): T & {} | undefined; -export function findOption(args: Argument[], name: string, fallbackValue: T): T & {}; -export function findOption(args: Argument[], name: string, fallbackValue?: any) { +export function findOption(args: CommandArgument[], name: string): T & {} | undefined; +export function findOption(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; +export let BUILT_IN: VencordCommand[]; +export const commands = {} as Record; // 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(opt: O): O { +export function prepareOption(opt: O): O { opt.displayName ||= opt.name; opt.displayDescription ||= opt.description; opt.options?.forEach((opt, i, opts) => { @@ -109,7 +110,7 @@ export function prepareOption(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(command: C, plugin: string) { +export function registerCommand(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 . -*/ + * 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; -} - -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; } 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( request: IDBRequest | IDBTransaction, ): Promise { return new Promise((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/MessageAccessories.tsx b/src/api/MessageAccessories.tsx index 71664e93..d2bc081e 100644 --- a/src/api/MessageAccessories.tsx +++ b/src/api/MessageAccessories.tsx @@ -48,7 +48,7 @@ export function _modifyAccessories( ) { for (const [key, accessory] of accessories.entries()) { const res = ( - + ); 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..54d40000 100644 --- a/src/api/MessageEvents.ts +++ b/src/api/MessageEvents.ts @@ -17,9 +17,8 @@ */ import { Logger } from "@utils/Logger"; +import type { Channel, CloudUpload, 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"); @@ -31,30 +30,6 @@ export interface MessageObject { tts: boolean; } -export interface Upload { - classification: string; - currentSize: number; - description: string | null; - filename: string; - id: string; - isImage: boolean; - isVideo: boolean; - item: { - file: File; - platform: number; - }; - loaded: number; - mimeType: string; - preCompressionSize: number; - responseUrl: string; - sensitive: boolean; - showLargeMessageDialog: boolean; - spoiler: boolean; - status: "NOT_STARTED" | "STARTED" | "UPLOADING" | "ERROR" | "COMPLETED" | "CANCELLED"; - uniqueId: string; - uploadedFilename: string; -} - export interface MessageReplyOptions { messageReference: Message["messageReference"]; allowedMentions?: { @@ -63,9 +38,9 @@ export interface MessageReplyOptions { }; } -export interface MessageExtra { +export interface MessageOptions { stickers?: string[]; - uploads?: Upload[]; + uploads?: CloudUpload[]; replyOptions: MessageReplyOptions; content: string; channel: Channel; @@ -73,17 +48,17 @@ export interface MessageExtra { openWarningPopout: (props: any) => any; } -export type MessageSendListener = (channelId: string, messageObj: MessageObject, extra: MessageExtra) => Promisable; +export type MessageSendListener = (channelId: string, messageObj: MessageObject, options: MessageOptions) => Promisable; export type MessageEditListener = (channelId: string, messageId: string, messageObj: MessageObject) => Promisable; const sendListeners = new Set(); const editListeners = new Set(); -export async function _handlePreSend(channelId: string, messageObj: MessageObject, extra: MessageExtra, replyOptions: MessageReplyOptions) { - extra.replyOptions = replyOptions; +export async function _handlePreSend(channelId: string, messageObj: MessageObject, options: MessageOptions, replyOptions: MessageReplyOptions) { + options.replyOptions = replyOptions; for (const listener of sendListeners) { try { - const result = await listener(channelId, messageObj, extra); + const result = await listener(channelId, messageObj, options); if (result?.cancel) { return true; } 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..afbb04f0 100644 --- a/src/api/MessageUpdater.ts +++ b/src/api/MessageUpdater.ts @@ -4,9 +4,8 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +import { 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 @@ -25,5 +24,5 @@ export function updateMessage(channelId: string, messageId: string, fields?: Par }); MessageCache.commit(newChannelMessageCache); - (MessageStore as unknown as FluxStore).emitChange(); + MessageStore.emitChange(); } diff --git a/src/api/Notices.ts b/src/api/Notices.tsx similarity index 73% rename from src/api/Notices.ts rename to src/api/Notices.tsx index 6d20087a..b4c44b88 100644 --- a/src/api/Notices.ts +++ b/src/api/Notices.tsx @@ -16,7 +16,10 @@ * along with this program. If not, see . */ +import ErrorBoundary from "@components/ErrorBoundary"; +import { isPrimitiveReactNode } from "@utils/react"; import { waitFor } from "@webpack"; +import { ReactNode } from "react"; let NoticesModule: any; waitFor(m => m.show && m.dismiss && !m.suppressAll, m => NoticesModule = m); @@ -36,7 +39,11 @@ export function nextNotice() { } } -export function showNotice(message: string, buttonText: string, onOkClick: () => void) { - noticesQueue.push(["GENERIC", message, buttonText, onOkClick]); +export function showNotice(message: ReactNode, buttonText: string, onOkClick: () => void) { + const notice = isPrimitiveReactNode(message) + ? message + : "Error Showing Notice"}>{message}; + + noticesQueue.push(["GENERIC", notice, buttonText, onOkClick]); if (!currentNotice) nextNotice(); } diff --git a/src/api/Notifications/NotificationComponent.tsx b/src/api/Notifications/NotificationComponent.tsx index d07143c4..52e56d5d 100644 --- a/src/api/Notifications/NotificationComponent.tsx +++ b/src/api/Notifications/NotificationComponent.tsx @@ -104,9 +104,7 @@ export default ErrorBoundary.wrap(function NotificationComponent({ -
- {richBody ??

{body}

} -
+ {richBody ??

{body}

} {image && } diff --git a/src/api/Notifications/notificationLog.tsx b/src/api/Notifications/notificationLog.tsx index 5df31d4c..dca7679e 100644 --- a/src/api/Notifications/notificationLog.tsx +++ b/src/api/Notifications/notificationLog.tsx @@ -20,10 +20,10 @@ import * as DataStore from "@api/DataStore"; import { Settings } from "@api/Settings"; import { classNameFactory } from "@api/Styles"; import { Flex } from "@components/Flex"; -import { openNotificationSettingsModal } from "@components/VencordSettings/NotificationSettings"; -import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal"; +import { openNotificationSettingsModal } from "@components/settings/tabs/vencord/NotificationSettings"; +import { closeModal, ModalCloseButton, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal"; import { useAwaiter } from "@utils/react"; -import { Alerts, Button, Forms, React, Text, Timestamp, useEffect, useReducer, useState } from "@webpack/common"; +import { Alerts, Button, Forms, ListScrollerThin, React, Text, Timestamp, useEffect, useReducer, useState } from "@webpack/common"; import { nanoid } from "nanoid"; import type { DispatchWithoutAction } from "react"; @@ -103,21 +103,9 @@ export function useLogs() { function NotificationEntry({ data }: { data: PersistentNotificationData; }) { const [removing, setRemoving] = useState(false); - const ref = React.useRef(null); - - useEffect(() => { - const div = ref.current!; - - const setHeight = () => { - if (div.clientHeight === 0) return requestAnimationFrame(setHeight); - div.style.height = `${div.clientHeight}px`; - }; - - setHeight(); - }, []); return ( -
+
deleteNotification(data.timestamp), 200); }} richBody={ -
- {data.body} +
+
{data.body}
} /> -
+
); } @@ -151,9 +139,14 @@ export function NotificationLog({ log, pending }: { log: PersistentNotificationD ); return ( -
- {log.map(n => )} -
+ null} + renderRow={item => } + /> ); } @@ -161,15 +154,15 @@ function LogModal({ modalProps, close }: { modalProps: ModalProps; close(): void const [log, pending] = useLogs(); return ( - + Notification Log - +
- +
diff --git a/src/api/Notifications/styles.css b/src/api/Notifications/styles.css index ad5c9cbc..471fbf01 100644 --- a/src/api/Notifications/styles.css +++ b/src/api/Notifications/styles.css @@ -3,18 +3,14 @@ all: unset; display: flex; flex-direction: column; - color: var(--text-normal); - background-color: var(--background-secondary-alt); + color: var(--text-default); + background-color: var(--background-base-low); border-radius: 6px; overflow: hidden; cursor: pointer; width: 100%; } -.visual-refresh .vc-notification-root { - background-color: var(--bg-overlay-floating, var(--background-base-low)); -} - .vc-notification-root:not(.vc-notification-log-wrapper > .vc-notification-root) { position: absolute; z-index: 2147483647; @@ -32,6 +28,7 @@ .vc-notification-content { width: 100%; + overflow: hidden; } .vc-notification-header { @@ -81,6 +78,11 @@ width: 100%; } +.vc-notification-log-modal { + max-width: 962px; + width: clamp(var(--modal-width-large, 800px), 962px, 85vw); +} + .vc-notification-log-empty { height: 218px; background: url("/assets/b36de980b174d7b798c89f35c116e5c6.svg") center no-repeat; @@ -88,19 +90,23 @@ } .vc-notification-log-container { - display: flex; - flex-direction: column; padding: 1em; - overflow: hidden; + max-height: min(750px, 75vh); + width: 100%; } .vc-notification-log-wrapper { + height: 120px; + width: 100%; + padding-bottom: 16px; + box-sizing: border-box; transition: 200ms ease; transition-property: height, opacity; -} -.vc-notification-log-wrapper:not(:last-child) { - margin-bottom: 1em; + /* stylelint-disable-next-line no-descending-specificity */ + .vc-notification-root { + height: 104px; + } } .vc-notification-log-removing { @@ -109,9 +115,18 @@ margin-bottom: 1em; } -.vc-notification-log-body { +.vc-notification-log-body-wrapper { display: flex; flex-direction: column; + width: 100%; + box-sizing: border-box; +} + +.vc-notification-log-body { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + line-height: 1.2em; } .vc-notification-log-timestamp { @@ -123,4 +138,4 @@ .vc-notification-log-danger-btn { color: var(--white-500); background-color: var(--button-danger-background); -} +} \ No newline at end of file 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 = { [Key in keyof T]: Key extends string ? T[Key] extends Record - // @ts-ignore "Type instantiation is excessively deep and possibly infinite" + // @ts-expect-error "Type instantiation is excessively deep and possibly infinite" ? UseSettings extends string ? `${Key}.${UseSettings}` : never : Key : never; diff --git a/src/components/CheckedTextInput.tsx b/src/components/CheckedTextInput.tsx index cf4aa119..8d37a560 100644 --- a/src/components/CheckedTextInput.tsx +++ b/src/components/CheckedTextInput.tsx @@ -18,7 +18,6 @@ import { React, TextInput } from "@webpack/common"; -// TODO: Refactor settings to use this as well interface TextInputProps { /** * WARNING: Changing this between renders will have no effect! diff --git a/src/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx index 0ca20440..7058b5fd 100644 --- a/src/components/ErrorBoundary.tsx +++ b/src/components/ErrorBoundary.tsx @@ -75,10 +75,15 @@ const ErrorBoundary = LazyComponent(() => { logger.error(`${this.props.message || "A component threw an Error"}\n`, error, errorInfo.componentStack); } + get isNoop() { + if (IS_DEV) return false; + return this.props.noop; + } + render() { if (this.state.error === NO_ERROR) return this.props.children; - if (this.props.noop) return null; + if (this.isNoop) return null; if (this.props.fallback) return ( diff --git a/src/components/ErrorCard.css b/src/components/ErrorCard.css index 5146aa03..2eea2f06 100644 --- a/src/components/ErrorCard.css +++ b/src/components/ErrorCard.css @@ -3,5 +3,9 @@ background-color: #e7828430; border: 1px solid #e78284; border-radius: 5px; - color: var(--text-normal, white); + color: var(--text-default, white); + + & a:hover { + text-decoration: underline; + } } diff --git a/src/components/Icons.tsx b/src/components/Icons.tsx index 4c5b0ca0..9862c1b4 100644 --- a/src/components/Icons.tsx +++ b/src/components/Icons.tsx @@ -27,7 +27,6 @@ interface BaseIconProps extends IconProps { } type IconProps = JSX.IntrinsicElements["svg"]; -type ImageProps = JSX.IntrinsicElements["img"]; function Icon({ height = 24, width = 24, className, children, viewBox, ...svgProps }: PropsWithChildren) { return ( diff --git a/src/components/Link.tsx b/src/components/Link.tsx index 0f4eb07d..2eb7ab00 100644 --- a/src/components/Link.tsx +++ b/src/components/Link.tsx @@ -28,6 +28,9 @@ export function Link(props: React.PropsWithChildren) { props.style.pointerEvents = "none"; props["aria-disabled"] = true; } + + props.rel ??= "noreferrer"; + return ( {props.children} diff --git a/src/components/PluginSettings/components/SettingBooleanComponent.tsx b/src/components/PluginSettings/components/SettingBooleanComponent.tsx deleted file mode 100644 index e5219e45..00000000 --- a/src/components/PluginSettings/components/SettingBooleanComponent.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -import { wordsFromCamel, wordsToTitle } from "@utils/text"; -import { PluginOptionBoolean } from "@utils/types"; -import { Forms, React, Switch } from "@webpack/common"; - -import { ISettingElementProps } from "."; - -export function SettingBooleanComponent({ option, pluginSettings, definedSettings, id, onChange, onError }: ISettingElementProps) { - const def = pluginSettings[id] ?? option.default; - - const [state, setState] = React.useState(def ?? false); - const [error, setError] = React.useState(null); - - React.useEffect(() => { - onError(error !== null); - }, [error]); - - function handleChange(newValue: boolean): void { - const isValid = option.isValid?.call(definedSettings, newValue) ?? true; - if (typeof isValid === "string") setError(isValid); - else if (!isValid) setError("Invalid input provided."); - else { - setError(null); - setState(newValue); - onChange(newValue); - } - } - - return ( - - - {wordsToTitle(wordsFromCamel(id))} - - {error && {error}} - - ); -} - diff --git a/src/components/PluginSettings/components/index.ts b/src/components/PluginSettings/components/index.ts deleted file mode 100644 index c38f209b..00000000 --- a/src/components/PluginSettings/components/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -import { DefinedSettings, PluginOptionBase } from "@utils/types"; - -interface ISettingElementPropsBase { - option: T; - onChange(newValue: any): void; - pluginSettings: { - [setting: string]: any; - enabled: boolean; - }; - id: string; - onError(hasError: boolean): void; - definedSettings?: DefinedSettings; -} - -export type ISettingElementProps = ISettingElementPropsBase; -export type ISettingCustomElementProps> = ISettingElementPropsBase; - -export * from "../../Badge"; -export * from "./SettingBooleanComponent"; -export * from "./SettingCustomComponent"; -export * from "./SettingNumericComponent"; -export * from "./SettingSelectComponent"; -export * from "./SettingSliderComponent"; -export * from "./SettingTextComponent"; - diff --git a/src/components/VencordSettings/PatchHelperTab.tsx b/src/components/VencordSettings/PatchHelperTab.tsx deleted file mode 100644 index 55822069..00000000 --- a/src/components/VencordSettings/PatchHelperTab.tsx +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -import { CodeBlock } from "@components/CodeBlock"; -import { debounce } from "@shared/debounce"; -import { copyToClipboard } from "@utils/clipboard"; -import { Margins } from "@utils/margins"; -import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches"; -import { makeCodeblock } from "@utils/text"; -import { Patch, ReplaceFn } from "@utils/types"; -import { search } from "@webpack"; -import { Button, Forms, Parser, React, Switch, TextArea, TextInput } from "@webpack/common"; - -import { SettingsTab, wrapTab } from "./shared"; - -// Do not include diff in non dev builds (side effects import) -if (IS_DEV) { - var differ = require("diff") as typeof import("diff"); -} - -const findCandidates = debounce(function ({ find, setModule, setError }) { - const candidates = search(find); - const keys = Object.keys(candidates); - const len = keys.length; - if (len === 0) - setError("No match. Perhaps that module is lazy loaded?"); - else if (len !== 1) - setError("Multiple matches. Please refine your filter"); - else - setModule([keys[0], candidates[keys[0]]]); -}); - -interface ReplacementComponentProps { - module: [id: number, factory: Function]; - match: string; - replacement: string | ReplaceFn; - setReplacementError(error: any): void; -} - -function ReplacementComponent({ module, match, replacement, setReplacementError }: ReplacementComponentProps) { - const [id, fact] = module; - const [compileResult, setCompileResult] = React.useState<[boolean, string]>(); - - const [patchedCode, matchResult, diff] = React.useMemo(() => { - const src: string = fact.toString().replaceAll("\n", ""); - - try { - new RegExp(match); - } catch (e) { - return ["", [], []]; - } - const canonicalMatch = canonicalizeMatch(new RegExp(match)); - try { - const canonicalReplace = canonicalizeReplace(replacement, 'Vencord.Plugins.plugins["YourPlugin"]'); - var patched = src.replace(canonicalMatch, canonicalReplace as string); - setReplacementError(void 0); - } catch (e) { - setReplacementError((e as Error).message); - return ["", [], []]; - } - const m = src.match(canonicalMatch); - return [patched, m, makeDiff(src, patched, m)]; - }, [id, match, replacement]); - - function makeDiff(original: string, patched: string, match: RegExpMatchArray | null) { - if (!match || original === patched) return null; - - const changeSize = patched.length - original.length; - - // Use 200 surrounding characters of context - const start = Math.max(0, match.index! - 200); - const end = Math.min(original.length, match.index! + match[0].length + 200); - // (changeSize may be negative) - const endPatched = end + changeSize; - - const context = original.slice(start, end); - const patchedContext = patched.slice(start, endPatched); - - return differ.diffWordsWithSpace(context, patchedContext); - } - - function renderMatch() { - if (!matchResult) - return Regex doesn't match!; - - const fullMatch = matchResult[0] ? makeCodeblock(matchResult[0], "js") : ""; - const groups = matchResult.length > 1 - ? makeCodeblock(matchResult.slice(1).map((g, i) => `Group ${i + 1}: ${g}`).join("\n"), "yml") - : ""; - - return ( - <> -
{Parser.parse(fullMatch)}
-
{Parser.parse(groups)}
- - ); - } - - function renderDiff() { - return diff?.map((p, idx) => { - const color = p.added ? "lime" : p.removed ? "red" : "grey"; - return
{p.value}
; - }); - } - - return ( - <> - Module {id} - - {!!matchResult?.[0]?.length && ( - <> - Match - {renderMatch()} - ) - } - - {!!diff?.length && ( - <> - Diff - {renderDiff()} - - )} - - {!!diff?.length && ( - - )} - - {compileResult && - - {compileResult[1]} - - } - - ); -} - -function ReplacementInput({ replacement, setReplacement, replacementError }) { - const [isFunc, setIsFunc] = React.useState(false); - const [error, setError] = React.useState(); - - function onChange(v: string) { - setError(void 0); - - if (isFunc) { - try { - const func = (0, eval)(v); - if (typeof func === "function") - setReplacement(() => func); - else - setError("Replacement must be a function"); - } catch (e) { - setReplacement(v); - setError((e as Error).message); - } - } else { - setReplacement(v); - } - } - - React.useEffect( - () => void (isFunc ? onChange(replacement) : setError(void 0)), - [isFunc] - ); - - return ( - <> - {/* FormTitle adds a class if className is not set, so we set it to an empty string to prevent that */} - replacement - - {!isFunc && ( -
- Cheat Sheet - {Object.entries({ - "\\i": "Special regex escape sequence that matches identifiers (varnames, classnames, etc.)", - "$$": "Insert a $", - "$&": "Insert the entire match", - "$`\u200b": "Insert the substring before the match", - "$'": "Insert the substring after the match", - "$n": "Insert the nth capturing group ($1, $2...)", - "$self": "Insert the plugin instance", - }).map(([placeholder, desc]) => ( - - {Parser.parse("`" + placeholder + "`")}: {desc} - - ))} -
- )} - - - Treat as Function - - - ); -} - -interface FullPatchInputProps { - setFind(v: string): void; - setParsedFind(v: string | RegExp): void; - setMatch(v: string): void; - setReplacement(v: string | ReplaceFn): void; -} - -function FullPatchInput({ setFind, setParsedFind, setMatch, setReplacement }: FullPatchInputProps) { - const [fullPatch, setFullPatch] = React.useState(""); - const [fullPatchError, setFullPatchError] = React.useState(""); - - function update() { - if (fullPatch === "") { - setFullPatchError(""); - - setFind(""); - setParsedFind(""); - setMatch(""); - setReplacement(""); - return; - } - - try { - const parsed = (0, eval)(`([${fullPatch}][0])`) as Patch; - - if (!parsed.find) throw new Error("No 'find' field"); - if (!parsed.replacement) throw new Error("No 'replacement' field"); - - if (parsed.replacement instanceof Array) { - if (parsed.replacement.length === 0) throw new Error("Invalid replacement"); - - parsed.replacement = { - match: parsed.replacement[0].match, - replace: parsed.replacement[0].replace - }; - } - - if (!parsed.replacement.match) throw new Error("No 'replacement.match' field"); - if (!parsed.replacement.replace) throw new Error("No 'replacement.replace' field"); - - setFind(parsed.find instanceof RegExp ? parsed.find.toString() : parsed.find); - setParsedFind(parsed.find); - setMatch(parsed.replacement.match instanceof RegExp ? parsed.replacement.match.source : parsed.replacement.match); - setReplacement(parsed.replacement.replace); - setFullPatchError(""); - } catch (e) { - setFullPatchError((e as Error).message); - } - } - - return <> - Paste your full JSON patch here to fill out the fields -