Compare commits

..

482 commits

Author SHA1 Message Date
Vendicated
64647e8ab6
1.14.6 2026-04-07 20:50:39 -07:00
Vendicated
dd93f27499
ci: fix resource exhaustion errors 2026-04-07 20:50:39 -07:00
Vendicated
432c045044
add vesktop vs vencord explainer to updater & improve cards 2026-04-07 20:50:39 -07:00
Elvy
ce33a15bcb
fix SpotifyControls, GameActivityToggle & AccPanelServerProfile (#4059) 2026-04-07 20:50:39 -07:00
thororen
75352feacc
ReviewDB: various fixes (#4062)
* fix regression that only showed 4 reviews per page
* Newest to oldest review sort
* filter out system on preview
* fix broken pfps rendering as error image
* fix contrast on white profiles

---------

Co-authored-by: Vendicated <vendicated@riseup.net>
2026-04-07 20:50:39 -07:00
Vendicated
3caed057f6
AnonymiseFilenames: use hex alphabet to remove chance to generate bad words 2026-04-07 20:50:39 -07:00
Vendicated
9ef41602c5
ReviewDB: make profile review button like game collection button 2026-04-07 20:50:39 -07:00
Vendicated
4a2c23ea24
CustomCommands: fix replying with commands 2026-04-07 20:50:39 -07:00
Vendicated
483d564782
fix PlatformIndicator badge 2026-04-07 20:50:39 -07:00
Vendicated
ae49ac4067
fix Decor & Message decorations 2026-04-07 20:50:39 -07:00
Vendicated
de98079c65
fix toolbox 2026-04-07 20:50:39 -07:00
Vendicated
355b78a52d
MessageTags: rename to CustomCommands & fix some logic errors 2026-04-07 20:50:39 -07:00
Vendicated
f261a75cd5
MessageTags: add argument support & considerably improve UX 2026-04-07 20:50:39 -07:00
Vendicated
d99b84c7ce
TextReplace: fix rule section closing when changing find 2026-04-07 20:50:39 -07:00
Vendicated
4f629294c3
Improve TextReplace settings UX 2026-04-07 20:50:39 -07:00
Vendicated
0f74e798d4
1.14.5 2026-04-07 20:50:39 -07:00
Vendicated
189c00f014
fix Settings crash 2026-04-07 20:50:39 -07:00
Mashiro-chan
46d41059b8
add back NoDefaultHangStatus (#4014)
Discord re-added this feature
2026-04-07 20:50:39 -07:00
Vendicated
96b194fcad
Toolbox: fix icon being too big 2026-04-07 20:50:39 -07:00
thororen
6590bf32bb
PlatformIndicators: support VR status (#4036) 2026-04-07 20:50:39 -07:00
thororen
8e04e1ac40
fix ReviewDB/Vencloud auth, NoMosaic, BetterSettings (#4025)
Co-authored-by: V <vendicated@riseup.net>
2026-04-07 20:50:39 -07:00
Unknown
8e0ac73745
Revert "Delete MoreCommands plugin"
This reverts commit 76b1fe9a87.
2026-03-07 20:54:20 -07:00
Unknown
0c7b3f1a8e
Revert "Remove NSFWGateBypass"
This reverts commit 9a3c66abfd.
2026-03-07 20:54:20 -07:00
Vendicated
15e92a49a1
1.14.4 2026-03-06 06:08:51 +01:00
thororen1234
c6e0ef1a11
fix BetterFolders, SpotifyControls, GameActivityToggle 2026-03-06 06:05:03 +01:00
Vendicated
12da7a08fb
bump to 1.14.3 2026-02-26 04:29:47 +01:00
Marina 🧊
a6b624a77d
not quite spring cleaning
Co-Authored-By: Marina <icedmarina@proton.me>
Co-Authored-By: prism <snawalt420@proton.me>
Co-Authored-By: nin0 <personal@nin0.dev>
2026-02-26 04:21:07 +01:00
KITFC
0e7757666d
BetterSettings: fix "Disable Fade" feature (#4007)
Closes #3970
Co-authored-by: V <vendicated@riseup.net>
2026-02-26 03:07:09 +01:00
sadan4
710c391697
fix VolumeBooster & UserVoiceShow (#4003) 2026-02-25 00:41:37 +01:00
Jeongmin
bf799f79b6
Translate: add Korean to DeepL language list (#4002) 2026-02-21 15:45:39 +00:00
Elvyra
dc25c8f046
fix SpotifyControls, GameActivityToggle, AccountPanelServerProfile (#3999) 2026-02-20 09:20:43 +01:00
thororen
5fc677bb26
fix AccountPanelServerProfile (#3995) 2026-02-16 20:34:51 +01:00
Vendicated
38c490533b
remove some legacy code 2026-02-10 01:30:30 +01:00
thororen
f9c404c229
fix StartupTimings & Decor (#3963) 2026-02-10 01:19:17 +01:00
Vendicated
50c5124e1c
bump to v1.14.2 2026-02-06 03:51:46 +01:00
Vendicated
00728074a2
BetterSettings: fix context menu organisation 2026-02-06 03:46:25 +01:00
Vendicated
07d63e31ad
fix Translate & VcNarrator 2026-02-06 03:34:29 +01:00
sadan4
61b916cab3
fix a few more things (#3969) 2026-02-06 03:25:59 +01:00
Vendicated
e40189e365
fix PinDMs & DisableCallIdle; remove some legacy code 2026-02-05 23:45:29 +01:00
sadan4
3d4cf25659
fix remaining things broken by recent Discord update (#3966)
Co-authored-by: V <vendicated@riseup.net>
Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
2026-02-05 22:50:16 +01:00
Vendicated
577407bab9
fix some things broken by a recent Discord update 2026-02-05 04:19:11 +01:00
Vendicated
dc27c4da76
plugin settings: fix not removing dummy user after load 2026-02-02 04:09:07 +01:00
MrCRACK
1515319b96
HideAttachments: support bot components v2 (#3944) 2026-02-01 16:05:23 +00:00
Nuckyz
0799be1b62
ShowConnections: Fix broken patch 2026-01-28 20:18:20 -03:00
Nuckyz
22e9730888
ChatInputButtonAPI: Fix broken patch 2026-01-28 18:43:02 -03:00
Nuckyz
3a000a5705
CopyFileContents: Fix broken patch 2026-01-28 18:32:42 -03:00
Nuckyz
41116f75b4
StartupTimings: Fix duplicate find 2026-01-28 13:27:37 -03:00
Vũ Minh Nguyên
0126090c8f
Translate: update DeepL language list (#3919) 2026-01-28 03:57:31 +00:00
sadan4
38a9f12296
CrashHandler: log component stack on crash (#3933) 2026-01-28 03:56:05 +00:00
Vendicated
d86423cae3
VcNarrator: only narrate events of current session 2026-01-28 04:53:09 +01:00
Vendicated
781a2f7c60
misc Settings ui improvements 2026-01-28 04:42:17 +01:00
Vendicated
816243e702
Settings: add textarea options 2026-01-28 04:15:39 +01:00
Vendicated
d8dbbf0c81
fix VoiceMessages plugin 2026-01-28 03:27:19 +01:00
Dog
2ffa14fe2b
fix(SupportHelper): make update button check case-insensitive (#3939) 2026-01-27 03:54:44 +00:00
sadan4
f32b68e373
Fix patches for latest Discord update (#3943)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2026-01-27 00:51:07 -03:00
Nuckyz
b9640433c8
WebContextMenus: Fix restoring Copy & Save Image 2026-01-26 16:07:33 -03:00
Nuckyz
8ecae352fd
NoBlockedMessages: Fix extra space between messages 2026-01-24 12:43:52 -03:00
Nuckyz
cdff1ae79e
ReviewDB: Fix viewing reviews with new CSS mangling 2026-01-24 12:43:09 -03:00
sadan4
fbfc38a1a6
RoleColorEverywhere: Fix not working on voice channel and chat (#3934)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2026-01-24 02:28:49 +00:00
Nuckyz
1e284c7cdf
Decor: Fix change decoration modal being unable to be opened 2026-01-23 23:09:41 -03:00
Vendicated
e03bb9a6e6
ExpressionCloner: fix cloning animated emojis 2026-01-24 02:53:30 +01:00
Vendicated
28b40534d1
WebScreenshareFixes: remove codec changes
This causes too many issues unfortunately
2026-01-24 02:50:23 +01:00
Vendicated
cd03aee484
bump to v1.14.1 2026-01-24 02:01:40 +01:00
sadan4
575421f4d0
fix everything (#3925)
Co-authored-by: prism <69634294+imjustprism@users.noreply.github.com>
Co-authored-by: sadan4 <117494111+sadan4@users.noreply.github.com>
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: V <vendicated@riseup.net>
Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
Co-authored-by: prism <snawalt420@proton.me>
Co-authored-by: wearrrrr <contact@wearr.dev>
Co-authored-by: Elvyra <88881326+EepyElvyra@users.noreply.github.com>
2026-01-24 01:59:53 +01:00
Vendicated
702a71dee8
fix plugin settings UI 2026-01-23 17:51:30 +01:00
Nuckyz
8c81e5d27e
webpack patcher: support new Discord bundler changes 2026-01-23 17:01:26 +01:00
thororen
44bdb60bb6
Fix AlwaysExpandRoles, PermissionsViewer, ShowConnections (#3916)
Co-authored-by: prism <69634294+imjustprism@users.noreply.github.com>
2026-01-22 02:48:24 +01:00
Vendicated
799ecc38dd
FixImageQuality: fix webps not animating in chat 2026-01-15 00:22:45 +01:00
Artavazd
e70747ce39
FakeNitro: improve emoji quality via lossless=true (#3907) 2026-01-14 23:21:38 +00:00
Vendicated
ca5c58bfa8
VoiceMessages: fix 'Failed to finish recording' error 2026-01-15 00:19:45 +01:00
Vendicated
1047f5b24e
Merge remote-tracking branch 'origin/main' into dev 2026-01-14 23:59:50 +01:00
thororen
8b4a2afeee
fix message hover buttons, BetterSessions & FavGifSearch (#3911) 2026-01-14 22:58:51 +00:00
Vendicated
5c7a90c05f
bump to v1.13.12 2026-01-09 23:25:40 +01:00
u32
353a699481
UserVoiceShow: fix showing in wrong location (#3884)
Co-authored-by: V <vendicated@riseup.net>
2026-01-09 22:11:34 +00:00
Elvyra
58815b642e
RoleColorEverywhere: only colour sent messages (ignore pending/failed) (#3895)
Co-authored-by: V <vendicated@riseup.net>
2026-01-09 21:53:30 +00:00
thororen
98a38642c7
fix PetPet & RoleColorEverywhere, (#3893) 2026-01-09 22:47:11 +01:00
Vendicated
658ff5b216
FixImagesQuality: fix always making GIF embeds in chat animate 2026-01-09 21:00:15 +01:00
d
d4d3514dcc
ReplaceGoogleSearch: add startpage (#3438) 2026-01-08 15:48:56 +00:00
Diode-exe
f9d8c07055
VoiceMessages: make text capitalisation consistent with Discord options (#3611) 2026-01-08 15:31:31 +00:00
u32
a3c64d90c3
Fix vencord badges not showing if user has no Discord badges (#3874)
Co-authored-by: Vendicated <vendicated@riseup.net>
2026-01-08 16:11:47 +01:00
Vendicated
b4eff3b62b
Try to fix Screenshare loading issues on Vesktop 2026-01-08 15:54:40 +01:00
Vendicated
ad491a370c
fix plugins using intl messages 2026-01-06 22:56:12 +01:00
prism
1af7eb62f1
Fix overlay theming issues & improve components (#3880)
Co-authored-by: V <vendicated@riseup.net>
2026-01-06 00:24:54 +01:00
Vendicated
5d56820a5d
FixImagesQuality: fix not applying to embed images 2026-01-05 17:32:15 +01:00
prism
5b7b033df7
Settings: fix panel title (#3879) 2026-01-02 04:00:02 +01:00
Vendicated
819bee2a88
fix message edit hooking (ClearURLs, Unindent) 2026-01-01 23:52:32 +01:00
nexpid
de019f7f17
Settings: support disabled for boolean settings (#3876) 2026-01-01 01:10:42 +00:00
u32
f7152a3982
WhoReacted: improve guild pfp support (#3875)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-12-31 23:26:16 +00:00
Joona
525f596826
add Vencord styles to Discord popout windows (#3080)
Co-authored-by: prism <snawalt420@proton.me>
Co-authored-by: V <vendicated@riseup.net>
2025-12-31 18:35:59 +01:00
u32
ed1acc3baa
FakeNitro, ExpressionCloner: fix issues with webp emojis (#3873) 2025-12-30 01:32:09 +00:00
Aztup
eb1edef868
fix(openInApp): Tidal regex (again) (#3753)
* fix tidal regex to support listen and strip the /u

* remove unnecessary $

---------

Co-authored-by: lewisakura <lewi@lewisakura.moe>
2025-12-28 20:50:49 +00:00
thororen
2fb549457b
USRBG: fix missing background in VC (#3851) 2025-12-28 01:47:29 +00:00
Vendicated
c123efd659
fix & future proof tooltips 2025-12-28 02:28:22 +01:00
u32
58ef6585af
PetPet: fix dark colours being transparent in the output (#3571)
Co-authored-by: V <vendicated@riseup.net>
2025-12-28 01:39:24 +01:00
iamme
3e036d1612
add new plugin MoreQuickReactions (#3865)
Co-authored-by: V <vendicated@riseup.net>
2025-12-28 00:25:52 +00:00
sadan4
fcb8276a81
PatchHelper: Fix incorrect escape handling (#3194)
Co-authored-by: V <vendicated@riseup.net>
2025-12-28 00:04:00 +00:00
thororen
746f31e412
Type a bunch of stores (#3861)
Co-authored-by: prism <snawalt420@proton.me>
2025-12-27 23:22:20 +01:00
Levi
d70d05b6c7
WebScreenShareFixes: improve video codec selection (#3867)
Co-authored-by: V <vendicated@riseup.net>
2025-12-27 17:34:23 +00:00
Nuckyz
a018e9fa95
Fix incorrectly force loading css debugging chunk 2025-12-26 23:38:50 -03:00
Vendicated
2d51b7cc40
FixImageQuality: fix embed images 2025-12-20 20:49:08 +01:00
V
ce8e48bb6d
Unify styles into single root node & support preload sandboxing (#3797) 2025-12-20 01:46:14 +01:00
Vendicated
e5df9b394e
fix PlatformIndicators 2025-12-20 01:44:57 +01:00
Vendicated
59eb057995
bump to v1.13.10 2025-12-20 01:25:57 +01:00
lewisakura
bfc356b69e
Cloud Sync: Add sync direction option for single source of truth (#3834)
Co-authored-by: V <vendicated@riseup.net>
2025-12-20 00:02:05 +01:00
Instellate
ea271496a3
PlatformIndicators: fix & refactor (#3827)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-12-19 18:30:58 +00:00
Vendicated
bf3edaed6a
Fix GameActivityToggle 2025-12-19 19:22:25 +01:00
Vendicated
a819d35ac3
ExpressionCloner: fix "Failed to resize asset below the maximum size" error 2025-12-17 23:34:52 +01:00
Vendicated
5f5e7c34f8
remove stray console.log 2025-12-17 22:57:53 +01:00
Vendicated
74f106c9fc
ImageZoom: load attachments from cdn instead of media proxy 2025-12-17 22:57:04 +01:00
Vendicated
16f343be52
FixImageQuality: fix videos & don't animate gifs if app unfocused 2025-12-17 22:56:07 +01:00
Vendicated
e8fd3dc3ef
Fix MemberCount 2025-12-17 22:31:13 +01:00
Vendicated
dc03ab9e82
Fix BlurNSFW 2025-12-16 20:30:41 +01:00
Vendicated
21e61784bc
remove unused style 2025-12-16 01:52:41 +01:00
Vendicated
a95ec43a99
fix styles 2025-12-16 01:49:53 +01:00
Vendicated
e94ea48a8b
FixImagesQuality: add option to load original image from cdn 2025-12-15 00:25:16 +01:00
Vendicated
4398665b9a
fix FixImageQuality 2025-12-14 20:54:45 +01:00
Vendicated
6827b8a3a6
bump to 1.13.9 2025-12-14 15:33:26 +01:00
Vendicated
ad173d7003
remove legacy css colour variable fallback 2025-12-14 15:32:47 +01:00
Vendicated
5b369dbed1
remove legacy intl compatibility 2025-12-14 15:22:44 +01:00
Vendicated
40b0976c35
FriendsSince: fix in dms profile sidebar 2025-12-14 14:58:35 +01:00
Vendicated
b910b3d147
fix FriendsSince & own CustomRPC buttons not showing for yourself 2025-12-14 14:42:37 +01:00
Vendicated
b0115598ba
RoleColorEverwhere: fix poll vote list 2025-12-12 02:47:16 +01:00
Vendicated
c36c750106
fix PermissionViewer & css variables again 2025-12-12 02:43:24 +01:00
sadan4
6662647472
ConsoleShortcuts: Add functions to switch branch on vesktop (#3204)
Co-authored-by: V <vendicated@riseup.net>
2025-12-11 15:25:55 +00:00
Sophie
4c8a734233
FakeNitro: fix animated webp emojis not animating (#3830) 2025-12-11 15:22:04 +00:00
Vendicated
6e11973a30
fix FavEmojiFirst & a SHC feature 2025-12-11 00:53:39 +01:00
Vendicated
d716727e45
fix settings - again 2025-12-11 00:45:45 +01:00
Vendicated
dd9a14a4ad
bump to 1.13.8 2025-12-10 20:17:20 +01:00
V
6b64cf38b0
update discord css colour variables (#3832)
Co-authored-by: V <vendicated@riseup.net>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: thororen <78185467+thororen1234@users.noreply.github.com>
2025-12-10 19:46:23 +01:00
Vendicated
e28f86a979
fix settings ui on canary 2025-12-10 17:03:27 +01:00
Vendicated
c8ccf4bfb7
fix PlatformIndicator badges 2025-12-10 04:00:23 +01:00
thororen
57091cfa02
FakeNitro: fix fake emoji conversion (#3829) 2025-12-10 03:23:36 +01:00
Vendicated
7098f41c5b
fix Vencord missing from Settings right click menu & BetterSettings 2025-12-06 23:43:30 +01:00
Vendicated
960f49bab6
bump to 1.13.7 2025-12-06 21:58:13 +01:00
Vendicated
ed51391efc
fix ShowHiddenChannels patch 2025-12-06 21:43:25 +01:00
Vendicated
fa46c4c4d2
settings sync: disallow possibly insecure settings
realistically this shouldn't matter too much, but still good to have
2025-12-06 21:33:58 +01:00
Vendicated
45ba135034
LastFM: add api key guide back. our shared key may get ratelimited 2025-12-06 21:11:57 +01:00
nin0
941e11b6fd
MessageClickActions: allow deleting one's own user app messages (#3806) 2025-12-06 20:54:13 +01:00
Vendicated
5fc903d323
RoleColorEverwhere: fix reaction list 2025-12-06 02:49:32 +01:00
Vendicated
9aa3f38033
PreviewMessage, SendTimestamps: add chat bar button in split view 2025-12-06 02:42:36 +01:00
thororen
192d6a2237
ShikiCodeBlocks: Update assets (#3785)
Co-authored-by: V <vendicated@riseup.net>
2025-12-06 02:33:17 +01:00
nin0
3ea80c254a
LastFmRPC: ignore custom status (#3814) 2025-12-06 00:45:04 +00:00
Dan
b07db6c500
SendTimestamps: support s and S timestamp formats (#3792) 2025-12-06 00:37:42 +00:00
VV
b8ab6a7470
support new Settings UI (#3803)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-12-06 01:32:51 +01:00
Vendicated
d8fe9f0c76
fix some text being wrong colour 2025-12-05 21:44:32 +01:00
thororen
0718b56f59
Decor: Fix not displaying in multiple places (#3773) 2025-12-03 17:22:40 +00:00
VV
ef0d85a367
NoUnblockToJump: Fix broken patch (#3815) 2025-12-03 13:03:04 +00:00
Vendicated
5f1a4db7e1
fix regression that broke some ui spacing 2025-11-25 17:37:58 +01:00
thororen
a824452333
BetterSettings: fix menu organisation (#3793) 2025-11-22 14:58:31 +00:00
V
eb5a42dd87
Add the option to toggle plugin chatbar & message hover buttons (#3693) 2025-11-21 13:53:30 +01:00
V
52e76a9cfc
useSettings: add prefix/wildcard settings path matching (#3783)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-21 12:09:07 +00:00
sadan4
f87a513150
improve build watcher to also detect newly created files (#3791) 2025-11-21 13:07:42 +01:00
V
ed1060b400
improve Vencord Toolbox (#3787) 2025-11-21 13:04:09 +01:00
sadan4
bb3f333ac8
fix ShowConnections (#3790) 2025-11-19 02:59:51 +01:00
Vendicated
f91c6d983a
upgrade dependencies 2025-11-19 02:57:12 +01:00
Vendicated
ddc1b34150
Plugin settings: add api/user plugins filter 2025-11-19 02:37:16 +01:00
Vendicated
3452a722b4
remake and improve Card/Flex components 2025-11-19 02:21:24 +01:00
Vendicated
78a2add1a5
USRBG: improve settings ui 2025-11-18 01:56:34 +01:00
V
6afcce39dd
refactor: fix circular dependency issues & improve organisation (#3729)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-11-16 15:17:35 +01:00
Vendicated
40fe13feda
LastFMRichPresence: fix duplicating spotify presence 2025-11-15 13:39:36 +01:00
Vendicated
9c3163da5e
RoleColorEverywhere: fix reactions 2025-11-15 12:44:58 +01:00
αλφρεδ
fb3d927f8c
fix Badges not showing; fix IrcColors in group DM list (#3781)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-11-15 11:25:23 +00:00
Vendicated
efe6f5c697
bump to v1.13.6 2025-11-12 22:16:13 +01:00
Vendicated
b3c070bca2
ViewIcons: fix viewing icon in dm header 2025-11-12 22:08:18 +01:00
Vendicated
e90b31e717
fix chat bar buttons not showing 2025-11-12 22:05:20 +01:00
Vendicated
ed1baadac3
LastFMRichPresence: linkify track/artist/album & make api key optional 2025-11-12 16:56:27 +01:00
Vendicated
00ae603884
VoiceMessages: fix crash when uploading invalid audio files 2025-11-12 16:16:33 +01:00
thororen
c9ebece84d
FakeProfileThemes: Fix broken ProfileModal find (#3766) 2025-11-05 13:29:37 -03:00
thororen
6bbc4783cd
Experiments: Fix Link Embeds (#3763) 2025-11-04 15:18:30 -03:00
Vendicated
7c708acf0b
bump to v1.13.5 2025-11-02 18:35:01 +01:00
thororen
44a75e4e94
fix Decor & NoTrack (#3752)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-11-02 17:28:53 +00:00
Vendicated
3992f971d0
fix missing Toolbox 2025-11-02 18:21:54 +01:00
hich4t
b6d727607f
CustomRPC: add detail/state and image URL fields (#3758)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-11-02 17:24:16 +01:00
Vendicated
cf8db5df6f
Merge remote-tracking branch 'origin/main' into dev 2025-11-02 17:04:37 +01:00
Aztup
6f16f1312c
fix(openInApp): Tidal regex (#3747)
Tidal no longer requires /browse/ in its URLs

Co-authored-by: lewisakura <lewi@lewisakura.moe>
2025-10-30 13:14:43 +00:00
Andrew
0f258731db
ReplaceGoogleSearch: add option to replace engine with single option (#3737)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-10-28 17:46:07 +00:00
Vendicated
556a27704a
ExpressionCloner: fix crash when in a server with 0 emojis 2025-10-27 22:39:55 +01:00
Elvyra
ebe2b2769c
BetterSettings: remove duplicate "Other options" menu entries (#3727)
Co-authored-by: V <vendicated@riseup.net>
2025-10-22 20:33:14 +00:00
Vendicated
e9fd7db6e6
GameActivityToggle: fix panel overflow 2025-10-22 22:22:49 +02:00
Vendicated
db5e507951
fix NoBlockedMessages 2025-10-22 22:11:00 +02:00
Vendicated
8eb252ad1e
fix: force disable new Discord settings ui 2025-10-22 00:13:31 +02:00
Nuckyz
9918bff479
NoServerEmojis: Fix broken patch 2025-10-16 22:04:11 -03:00
Vendicated
f4cb4ed39e
fix BetterFolders and various strings 2025-10-15 19:50:41 +02:00
Vendicated
b1edb6c156
bump to v1.13.4 2025-10-15 19:34:42 +02:00
Vendicated
647c824d93
fix: update intl hash function
e8598c6dde
2025-10-15 19:17:04 +02:00
Nuckyz
9c5eebe583
Decor: Fix decoration modal not opening 2025-10-14 19:04:10 -03:00
Vendicated
40e67ad7a6
CustomRPC: add README 2025-10-12 06:18:32 +02:00
Vendicated
dcefa49d34
CustomRPC: add party option & overhaul settings ui 2025-10-12 06:13:36 +02:00
Thomas White
dfbffd1342
VcNarrator: make nickname fallback to displayName instead of username (#3564) 2025-10-12 02:03:06 +00:00
Vendicated
b881b60ff7
FormSwitch: make entire Switch clickable & add focus rings 2025-10-11 18:54:01 +02:00
Vendicated
c1556f0949
bump to v1.13.3 2025-10-11 01:46:31 +02:00
V
cc01bb70cb
Replace Forms with our own independent components (#3618)
Vastly improves resilience of Settings Ui against Discord changes. Should now never break even if hell breaks loose

Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-10-11 01:42:14 +02:00
Nuckyz
732f7dd4b4
ReviewDB: Fix patch for latest canary changes 2025-10-10 18:51:46 -03:00
Nuckyz
e8ea561e71
StartupTimings: Move section to developer options 2025-10-10 18:42:51 -03:00
sadan4
4486d3a4b8
Experiments: Fix warning patch (#3714) 2025-10-10 21:42:12 +00:00
Vendicated
61c32a9deb
fix SearchableSelect 2025-10-10 00:08:59 +02:00
Vendicated
ba0f39a7ba
fix stable compatibility 2025-10-09 21:26:32 +02:00
Vendicated
ae65883335
fix broken Settings ui 2025-10-09 21:17:17 +02:00
Vendicated
db077f307b
bump to v1.13.2 2025-10-07 16:06:58 +02:00
Vendicated
6b66856b5c
BetterSettings: fix context menu organising 2025-10-07 16:06:40 +02:00
Vendicated
54813f2dc3
WebContextMenus: fix crashing when clicking images
Co-Authored-By: rini <nil@dissoc.cc>
2025-10-07 03:17:41 +02:00
Vendicated
8ea9a08c70
update & publish types packages 2025-10-07 00:43:03 +02:00
정현수
d77fa7c206
RevealAllSpoilers: use cmd key on macOS (#3697) 2025-10-06 20:52:35 +00:00
thororen
66a8eb4854
fix ShowHiddenThings, BetterSessions, ShowTimeoutDuration (#3701)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-10-06 20:48:17 +00:00
sadan4
18af2e1148
TypingTweaks: use pointer cursor for clickable elements (#3705) 2025-10-05 22:05:31 +02:00
nin0
061cac08dd
AppleMusicRPC: fix album art fetching (#3702) 2025-10-05 22:02:39 +02:00
Vendicated
887911c1d3
fix FixImagesQuality 2025-10-05 21:02:55 +02:00
Vendicated
467da909d6
export new form components 2025-10-03 00:57:40 +02:00
Vendicated
163e716dca
fix lint 2025-10-03 00:53:02 +02:00
Vendicated
1d1e5f3756
bump to v1.13.1 2025-10-03 00:52:01 +02:00
Vendicated
a748ad2085
fix FormSwitch 2025-10-03 00:48:29 +02:00
V
7aa1d47193
fix reporter (#3699) 2025-10-01 23:12:33 +02:00
thororen
fd461045b9
new plugin AutoDNDWhilePlaying (#3652)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-09-30 00:51:37 +00:00
thororen
c26fb03849
QuickReply: Ignore messages by blocked/ignored users (#3659)
Co-authored-by: V <vendicated@riseup.net>
2025-09-29 18:16:00 +02:00
Vendicated
b1cdf7a35d
add vesktop protocol to csp whitelist 2025-09-29 03:47:28 +02:00
sadan4
8943c90cb0
arRPC: increase connection timeout to 5s (#3680)
Co-authored-by: V <vendicated@riseup.net>
2025-09-28 21:34:23 +00:00
V
f040133412
QuickReply/MessageClickActions: ignore non-replyable & ephemeral messages (#3692)
Co-authored-by: YashRaj <91825864+YashRajCodes@users.noreply.github.com>
2025-09-28 23:18:23 +02:00
TheRealClarity
631c763fc4
YoutubeAdblock: fix blocking in watch together activity (#3690) 2025-09-28 22:46:14 +02:00
sadan4
79c5cf5304
fix plugins for latest Discord update (#3681)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-09-27 21:59:18 +02:00
Vendicated
c5a1bbd7db
GameActivityToggle: fix background colour when using nameplate 2025-09-25 15:19:45 +02:00
thororen
7c839be64f
BetterFolders: close folder if the last server is removed (#3658)
Co-authored-by: V <vendicated@riseup.net>
2025-09-24 14:49:50 +00:00
Vendicated
cb845b5224
PlatformIndicators: update indicators in real time if status changes
Closes #3516
2025-09-23 23:58:47 +02:00
Vendicated
746c824020
Fix Debug Logging toggle not working
Closes #3268
2025-09-23 22:24:58 +02:00
Vendicated
228b85a0c8
bump to v1.13.0 2025-09-22 05:18:10 +02:00
thororen
2e9d67f0b4
add Vencord badges to user settings section (#3667)
Co-authored-by: V <vendicated@riseup.net>
2025-09-22 05:15:14 +02:00
nin0
edd68fe08e
AppleMusicRichPresence: add status display type (#3669)
Co-authored-by: V <vendicated@riseup.net>
2025-09-22 03:08:08 +00:00
quarty
80872f4ab9
MessageLatency: add option to ignore own messages (#3677)
Co-authored-by: V <vendicated@riseup.net>
2025-09-22 02:44:13 +00:00
thororen
8c2dc84f3b
Settings: fix debug info layout (#3673) 2025-09-22 04:38:57 +02:00
Vendicated
3005906a28
CallTimer: fix horizontal text cutoff 2025-09-20 20:37:28 +02:00
Gabriel
56d25b03f9
UserVoiceShow: Improve tooltip & add icons for muted/deafened (#3630)
Co-authored-by: V <vendicated@riseup.net>
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-09-17 03:35:01 +02:00
sadan4
fbc2dbe781
FakeNitro: fix nitro themes not working for some users (#3666) 2025-09-10 04:36:34 +02:00
thororen
9c0af5adee
Fix broken MessagePopoverAPI not working (#3661) 2025-09-09 16:28:37 +00:00
Vendicated
479d01a1b9
fix FavGifSearch regression 2025-09-09 03:57:00 +02:00
thororen
8eabb11125
ClearURLs: use rules from ClearURLs browser extension (#3657)
Co-authored-by: V <vendicated@riseup.net>
2025-09-09 01:35:01 +00:00
Nuckyz
98058f0cae
Fix mistakes 2025-09-08 22:27:41 -03:00
Nuckyz
50eb62045a
Fix FavoriteGifSearch & broken Menu component find 2025-09-08 22:18:39 -03:00
Nuckyz
4e8d22b4d5
NoPendingCount: Improve slow patch 2025-09-08 22:02:04 -03:00
sadan4
51c23ff796
FakeNitro: Add custom client theme color picker (#3534) 2025-09-08 21:51:03 -03:00
Vendicated
dc72ee3809
GameActivityToggle: fix overflow 2025-09-09 02:23:57 +02:00
thororen1234
4c7acbbbc7
fix NoPendingCount 2025-09-09 02:08:44 +02:00
thororen
0f29eab3ea
MemberCount: use circle svg instead of css hacks (#3653)
fixes some deformations
2025-09-09 02:03:12 +02:00
V
c38aac23fd
improve various types (#3663)
Co-authored-by: V <vendicated@riseup.net>
Co-authored-by: John Davis <70701251+gobuster@users.noreply.github.com>
Co-authored-by: sadan4 <117494111+sadan4@users.noreply.github.com>
2025-09-08 23:48:53 +00:00
Ryan Cao
84957b0e88
improve wordsFromCamel correctness (#3621)
Co-authored-by: V <vendicated@riseup.net>
2025-09-09 00:49:24 +02:00
ww
a4e1d026ea
VolumeBooster: make multiplier option more flexible (#3656) 2025-09-08 01:30:08 +00:00
Vendicated
b225f2ec6c
SpotifyControls: add copy song/artist/album name options 2025-09-08 02:55:02 +02:00
nin0
efecbae75b
LastFMRPC: add setting to show artist/song name in member list (#3629) 2025-09-08 00:14:38 +00:00
thororen
1cfc3fb8f8
fix OnePingPerDM (#3648)
also removes a now obsolete patch from FakeNitro
2025-09-06 18:27:29 +02:00
u32
26074b7f18
MessageLatency: fix bot check (#3523) 2025-09-05 02:04:08 +00:00
Vendicated
e857f6806f
ShowMeYourName: respect streamer mode 2025-09-05 03:55:38 +02:00
Gleb P
b6e96a4d3b
MemberCount: also show members in voice (#2937)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-09-05 03:37:13 +02:00
sadan4
1d00ba4161
fix patches for Experiments and Vencord Toolbox (#3647) 2025-09-04 21:59:30 +02:00
union
77b016de36
ReverseImageSearch: add Bing (#2793) 2025-09-04 02:46:02 +02:00
union
b7f19bbe37
NoReplyMention: add role whitelist / blacklist (#2794)
Co-authored-by: V <vendicated@riseup.net>
2025-09-04 02:41:06 +02:00
Vendicated
9700ec9cd2
fix minor bugs 2025-09-03 04:37:38 +02:00
Vendicated
65c85a5222
CallTimer: fix overflow when using aligned chat input
Co-Authored-By: sadan4 <117494111+sadan4@users.noreply.github.com>
Co-Authored-By: God
2025-09-03 04:26:33 +02:00
sadan4
8789973bf5
WhoReacted: remove ugly more users tooltip (#3640)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-09-03 03:41:46 +02:00
ayuxia
4ff3614dc0
ShowMeYourName: support friend nicknames (#3639)
Co-authored-by: V <vendicated@riseup.net>
2025-09-03 03:19:12 +02:00
thororen
5c69d340d9
Fix MutualGroupDMs & Decor broken patches (#3644) 2025-09-02 23:44:25 +00:00
Etorix
75a2506c51
ViewRaw: Adjust icon size to match other icons (#3605) 2025-09-02 16:42:17 +00:00
jamesbt365
9b0ae0fd90
Translate: support automod & forwarded messages (#3367)
Co-authored-by: V <vendicated@riseup.net>
2025-09-02 04:20:56 +02:00
sadan4
f0f75aa918
AlwaysAnimate: Add nameplates support (#3641) 2025-09-01 23:59:15 +00:00
Nuckyz
8ebfd9a190
NoTypingAnimation: Fix not working due to broken patches 2025-09-01 20:53:43 -03:00
Vendicated
17b90beee1
add context menu options to vencord badges 2025-08-31 05:18:47 +02:00
Nuckyz
8807564053
ConsoleJanitor: Fix outdated settings margin 2025-08-29 16:23:23 -03:00
sadan4
aca30bcb9a
ShowHiddenChannels: Fix broken patch (#3635) 2025-08-29 19:02:45 +00:00
thororen
67aff64fed
MutualGroupDMs: Fix broken patch (#3634) 2025-08-29 16:01:27 -03:00
Vendicated
c5888c25f7
bump to v1.12.13 2025-08-29 02:52:44 +02:00
thororen
19c1eaed18 fix failing to find the Select component (#3631) 2025-08-28 04:55:03 +02:00
Nuckyz
5dee746986 Fix IgnoreActivities 2025-08-28 04:55:03 +02:00
Vendicated
76a60e07e9
fix SuperReactionTweaks 2025-08-23 02:16:32 +02:00
Vendicated
abe910d80d
fix not being able to dismiss Vencord Notices 2025-08-23 02:02:02 +02:00
Vendicated
4a35cf1769
Toolbox: fix & move to the titlebar 2025-08-23 01:57:27 +02:00
fawn
643656d798
new plugin ImageFilename: displays image filename tooltips on hover (#3617)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-08-19 16:41:02 +02:00
Vendicated
0bb2ed6b72
bump to v1.12.12 2025-08-18 18:58:40 +02:00
Nuckyz
330c3cead7
Fix plugins broken by latest Discord update (#3609) 2025-08-17 17:33:23 -03:00
Vendicated
93294673de
bump to v1.12.11 2025-08-14 21:48:28 +02:00
sadan4
204f916b2a
fix Settings UI and various plugins (#3608)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-08-14 21:42:58 +02:00
Vendicated
f356f647ff
bump to v1.12.10 2025-08-13 12:58:29 +02:00
Vendicated
aad88fe9cd
fix plugins sending messages 2025-08-13 12:55:24 +02:00
sadan4
72329f901c
AccountPanelServerProfile: fix right click menu (#3600)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-08-12 03:28:19 +02:00
Vendicated
27b2e97e3f
ReviewDB: fix input 2025-08-12 03:00:47 +02:00
Nuckyz
d9e2732a8d
Fix MessageEventsAPI broken patch 2025-08-11 15:35:29 -03:00
Vendicated
0c89314d49
PermissionFreeWill: don't break permission toggles 2025-08-07 23:38:37 +02:00
byeoon
4403aee3c1
New plugin CopyStickerLinks: adds Copy/Open Link option to stickers (#3191)
Co-authored-by: V <vendicated@riseup.net>
2025-08-07 22:24:13 +02:00
sadan4
7e028267f1
SpotifyShareCommands: correctly handle local tracks (#3592) 2025-08-07 21:04:59 +02:00
Nuckyz
c7e799e935
ShowHiddenChannels: Fix incorrect allowed users and roles component 2025-08-07 09:29:37 -03:00
Vendicated
98efe13b97
ShowHiddenThings: fix crash when viewing Mod View 2025-08-07 04:24:34 +02:00
Vendicated
164fd43cc4
Fix IgnoreActivities 2025-08-06 22:01:24 -03:00
Nuckyz
fe2ed0776f
ShowHiddenChannels: Fix showing allowed roles 2025-08-06 22:01:24 -03:00
sadan4
74d78d89ed
fix TypingTweaks (#3586)
Co-authored-by: V <vendicated@riseup.net>
2025-08-07 02:11:38 +02:00
sadan4
6a66b7f54f
fix plugins broken by Discord update (#3583)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: V <vendicated@riseup.net>
2025-08-06 22:16:07 +02:00
Zordan
36c15d619e
HideAttachments: correctly support forwarded Messages (#3587)
Co-authored-by: V <vendicated@riseup.net>
2025-08-06 16:26:00 +02:00
V
a2253cb4ae
remove old discord ui workarounds & legacy code (#3585)
Co-authored-by: sadan <117494111+sadan4@users.noreply.github.com>
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-08-05 23:57:51 +02:00
V
6380111f32
Notification Log: fix lag if there are too many entries (#3584)
Use Discord's lazy list implementation for only rendering what's on screen
2025-08-05 19:20:28 +02:00
Vendicated
1ebd412392
BetterUploadButton: don't affect other chat buttons 2025-08-03 17:04:50 +02:00
Vendicated
a02d1afdf0
bump to v1.12.8 2025-08-03 16:26:08 +02:00
Vendicated
38e46f89cf
BetterUploadButton: fix right click action not working 2025-08-03 16:24:00 +02:00
sadan4
22d3fb10e9
fix plugins broken by latest Discord update (#3574)
Co-authored-by: V <vendicated@riseup.net>
2025-08-03 13:05:26 +00:00
Vendicated
fa672a347d
BetterSessions: fix ui 2025-08-01 01:51:38 +02:00
sadan4
cb36cf5706
fix Plugins broken by recent Discord changes (#3569)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-07-31 22:31:33 +02:00
Nuckyz
29a2bcbf07
Fix BetterUploadButton not working 2025-07-26 11:31:30 -03:00
Vendicated
03fe7d15cf
bump to v1.12.7 2025-07-22 22:45:28 +02:00
Vendicated
6fb685b959
Fix Plugin settings page
Co-Authored-By: sadan <117494111+sadan4@users.noreply.github.com>
2025-07-22 22:43:31 +02:00
sadan4
8b36013264
fix GreetStickerPicker (#3561) 2025-07-22 22:35:35 +02:00
Vendicated
50e2ad776b
Plugin Settings: improve headings 2025-07-21 12:32:20 +02:00
Vendicated
4ab084c0ac
make ShowMeYourName patch safer 2025-07-21 12:13:13 +02:00
Vendicated
113a1f4b86
fix ShowMeYourName 2025-07-21 12:09:36 +02:00
Nuckyz
25cd6b7069
Remove unused and non unique webpack common style classes find 2025-07-17 22:06:22 -03:00
Nuckyz
f6f0624e52
Fix broken Decor style classes find 2025-07-17 22:05:42 -03:00
Nuckyz
cdda1224ff
UserVoiceShow: Improve icon in User Profile Modal V2 2025-07-16 20:23:06 -03:00
Nuckyz
d0869c41cd
Settings: Improve layout of a setting section and error 2025-07-16 18:15:52 -03:00
Nuckyz
828358bd2e
IrcColors: Fix chat colors broken patch 2025-07-15 15:52:48 -03:00
V
3f51ee1b2a
refactor Settings UI (#3545)
Much improved file structure and cleaner code. Also gets rid of temporary settings & saving and instead applies all changes immediately.

Besides that, this change only changes code and doesn't change the ui
2025-07-15 15:57:24 +02:00
Nuckyz
a33e81d1cb
Bump to v1.12.6 2025-07-14 21:05:04 -03:00
Nuckyz
f3874d0a26
Fix Plugin Settings broken webpack find 2025-07-14 21:02:44 -03:00
Nuckyz
ad810df978
Attempt to make OverrideForumDefaults not always slow 2025-07-14 17:09:21 -03:00
Nuckyz
1a98d54e3a
Fix Experiments embed patches 2025-07-14 17:07:43 -03:00
Nuckyz
5dd6722528
Fix MessagePopoverAPI incorrectly hiding the emoji button 2025-07-14 17:07:22 -03:00
sadan4
6787e98003
FakeProfileThemes: fix error when own profile is not loaded (#3514)
Co-authored-by: V <vendicated@riseup.net>
2025-07-10 22:38:27 +02:00
sadan4
18f083b7e6
fix ImageZoom & FakeProfileThemes (#3546)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-07-10 19:56:12 +00:00
Vendicated
19f4d7cdac
fix various plugins still using outdated Discord classes 2025-07-10 01:37:32 +02:00
Vendicated
8e446e44ab
Online Themes: fix & improve ui 2025-07-10 01:37:13 +02:00
Cookie
a17803c1c4
Settings: remove outdated style (#3490) 2025-07-09 22:42:38 +00:00
V
dc9064326b
refactor discord types into separate npm package (#3520)
Co-authored-by: V <vendicated@riseup.net>
Co-authored-by: sadan <117494111+sadan4@users.noreply.github.com>
Co-authored-by: ezzud <contact@ezzud.fr>
2025-07-10 00:38:39 +02:00
nyx
c55833d95f
ShowMeYourName: fix gradient role compatibility (#3495)
Co-authored-by: V <vendicated@riseup.net>
2025-07-08 01:05:56 +02:00
Amia
44f7ccafcb
MutualGroupDMs: fix member count label (#3541) 2025-07-08 01:04:14 +02:00
Etorix
643122e323
Experiments: fix edge case in experiment rollout detection (#3497)
Co-authored-by: V <vendicated@riseup.net>
2025-07-04 16:09:10 +02:00
Amia
310d8e6140
Fix ImplicitRelationships & RelationshipNotifier (#3539) 2025-07-04 15:04:12 +02:00
Vendicated
1142cab05c
Merge remote-tracking branch 'origin/main' into dev 2025-07-04 14:59:44 +02:00
sadan4
c653e36137
fix Expression Cloner, ServerInfo & SeeSummaries plugins (#3536) 2025-07-04 02:14:59 +02:00
Vendicated
93f28fe984
TypingTweaks: fix typo 2025-07-01 23:30:29 +02:00
Vendicated
4b0ff3ee5f
bump to v1.12.5 2025-07-01 23:27:54 +02:00
Vendicated
43ba1a4a5e
TypingIndicator: fix TypingTweaks compatibility 2025-07-01 23:18:12 +02:00
Vendicated
23eb85e898
AppleMusicRichPresence: fix broken album covers 2025-07-01 23:13:38 +02:00
Vendicated
9e22ab305c
Fix plugins using Message Popover buttons 2025-07-01 23:06:06 +02:00
Vendicated
1b2bc07592
TypingTweaks: fix several users are typing display 2025-07-01 22:57:28 +02:00
Vendicated
18274e4f0e
Fix TypingTweaks 2025-07-01 22:36:25 +02:00
Damian
468b290d28
FakeNitro: add 96 to available emoji sizes (#3526) 2025-06-29 20:56:20 +02:00
Vendicated
f6d92e5024
Update more Discord css variables 2025-06-28 03:56:49 +02:00
Vendicated
a25d26e921
Update to new Discord css variable names
Co-Authored-By: sadan <117494111+sadan4@users.noreply.github.com>
Co-Authored-By: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-06-28 03:47:58 +02:00
Vendicated
65f41cb7bd
Update GuildStore -> GuildRoleStore 2025-06-27 21:36:31 +02:00
sadan4
864ee7c7ad
Fix BlurNSFW and ShowMeYourName for latest version (#3517) 2025-06-27 13:45:22 -03:00
Vendicated
decb49fc0a
v1.12.4 2025-06-25 03:27:34 +02:00
sadan4
b6ffb33adc
Fix plugins for latest discord update (#3509)
Co-authored-by: Etorix <92535668+EtorixDev@users.noreply.github.com>
Co-authored-by: V <vendicated@riseup.net>
2025-06-25 03:25:36 +02:00
sadan4
9b24535d44
FakeNitro: fix crash when embed.url is undefined (#3510) 2025-06-25 02:44:11 +02:00
sadan4
658a62860e
BetterFolders: Fix sidebar filter patch (#3498) 2025-06-20 13:45:52 -03:00
Vendicated
f6bfd18816
ViewIcons: fix viewing animated icons/banners 2025-06-19 23:03:15 +02:00
Vendicated
ba76c43a26
ServerInfo: fix Blocked & Ignored tabs 2025-06-19 22:50:53 +02:00
Vendicated
96516f113a
ReplaceGoogleSearch: fix broken icons 2025-06-18 15:48:07 +02:00
Etorix
e4b1a196ae
fix Settings::onChange being fired twice (#3496) 2025-06-18 03:55:10 +02:00
Vendicated
7779e5a1ec
fix IrcColors 2025-06-17 22:37:56 +02:00
Vendicated
0444831073
RoleColorEverywhere: fix chat mentions 2025-06-17 22:15:11 +02:00
Vendicated
a6c1f97d12
Fix AnonymiseFileNames 2025-06-17 22:03:13 +02:00
Vendicated
8d97863db6
Fix ImplicitRelationships, RelationshipNotifier & ServerInfo 2025-06-17 21:58:12 +02:00
Vendicated
3a1e17e04d
remove redundant methods 2025-06-14 18:55:12 +02:00
Vendicated
78d3330ccf
make Open Themes/Settings folder properly open the folder 2025-06-14 18:51:40 +02:00
Vendicated
2a398985cf
fix: correctly allow resources from localhost 2025-06-14 00:55:27 +02:00
T1ckbase
b35b72c066
Translate: Make translation more readable (#3252) 2025-06-12 02:29:50 +02:00
Randomuser8219
a366693e96
ServerInfo: rename "Nitro Boosts" -> "Server Boosts" (#3364) 2025-06-12 02:24:24 +02:00
Vending Machine
ed5ed4b80a
Allow users to manually whitelist Domains for use in themes (#3476) 2025-06-12 02:19:45 +02:00
Nuckyz
7f2c4a3566
Delete Banger plugin ~ Ban modal no longer contains a gif
Discord removed the gifs displayed in the ban modal, so this plugin serves no purpose anymore.
2025-06-11 19:17:25 -03:00
Nuckyz
7112caaedd
Experiments: Fix toolbar help menu dev icon patch 2025-06-11 19:17:24 -03:00
Vendicated
18f2b49b67
fix loading themes with spaces in their name 2025-06-09 01:56:19 +02:00
Vending Machine
b19bb2b7af
Update README (#3472) 2025-06-08 20:10:30 +02:00
Vending Machine
6d47a340b1
QuickReply: correctly handle new & deleted messages (#3473) 2025-06-08 19:45:52 +02:00
Cookie
a386736dcc
WebScreenShareFixes: only apply stereo parameter to video audio (#3474) 2025-06-08 17:47:59 +02:00
Mia
bf68a8a3e8
MessageClickActions: make delete key detection consistent on lost focus (#3470)
Co-authored-by: Vending Machine <vendicated@riseup.net>
2025-06-08 16:55:12 +02:00
Vendicated
bb106b7c49
whitelist catbox for use in themes 2025-06-07 01:31:04 +02:00
Vendicated
3a2a16a09c
whitelist tenor and pinterest for use in themes 2025-06-07 01:18:14 +02:00
Vendicated
5f21eaabf8
bump to v1.12.3 2025-06-07 01:02:57 +02:00
Vanilla
4436e6d81d
Fix missing background on notifications (#3386)
Co-authored-by: Vending Machine <vendicated@riseup.net>
2025-06-07 00:53:58 +02:00
Vending Machine
47856a26f1
Updater: fix network errors triggering popups (#3436) 2025-06-07 00:46:49 +02:00
Nuckyz
9430803f36
TypingTweaks: Fix typing avatars and names disappearing 2025-06-06 19:11:06 -03:00
Vendicated
c19827a0e5
UserScript: disable theme ui, instead recommend Stylus 2025-06-07 00:06:01 +02:00
Vendicated
fae15dbdfe
avoid showing ugly red error cards to users 2025-06-06 18:51:05 +02:00
Vending Machine
e7076f5aee
Use much stricter, whitelist based CSP (#3162) 2025-06-06 18:30:19 +02:00
Nuckyz
0ce7772500
FakeNitro: Fix sending animated stickers 2025-06-05 15:42:00 -03:00
Henry
503c90c201
ShowHiddenChannels: Fix showing lock icon for special channels (#3460) 2025-06-05 00:24:04 +00:00
Elvyra
db0bcf7da3
WebContextMenus: Fix copying and saving images (#3459) 2025-06-05 00:18:20 +00:00
Nuckyz
0e90bda3c7
Fix AnonymiseFileNames
Also fix issues with User Profile Modal v2 MutualGroupDMs patches
2025-06-04 20:53:43 -03:00
Nuckyz
f0fcaf734e
ShowHiddenChannels: Fix erroring when avoiding fetching channel messages 2025-05-30 11:49:36 -03:00
Vendicated
eafbc0d15a
WhoReacted: fix crashing (app reloading) 2025-05-29 23:10:58 +02:00
Nuckyz
2a4314efc9
ShowHiddenChannels: Fix incorrectly fetching messages 2025-05-29 17:01:12 -03:00
Ataraxis
b706d53998
Fix not respecting contributor badge preference (#3443) 2025-05-28 11:24:48 -03:00
Nuckyz
76b1fe9a87
Delete MoreCommands plugin
This plugin is useless and the commands it adds have almost no use or can be replaced using the TextReplace plugin
2025-05-28 10:38:20 -03:00
Vendicated
a9dc81e600
Delete Partymode plugin
This plugin is useless. You can just enable party mode via the easter egg
2025-05-24 18:39:36 +02:00
Vendicated
0985d2c8cd
Delete NoRPC plugin
This plugin is incredibly niche and leads to a lot of confusion for
users enabling it by mistake. If you want to avoid Discord scanning
processes on your system, consider using third party desktop clients
like Vesktop or Legcord
2025-05-24 18:36:17 +02:00
Vendicated
600a95f751
Delete Moyai plugin
This plugin is funny but ultimately useless and leads to a
lot of confusion from users enabling it by mistake
2025-05-24 18:34:42 +02:00
Vendicated
d7e6fcd3ae
Delete MoreKaomoji plugin
This plugin is very niche and can easily be replicated using the TextReplace plugin
2025-05-24 18:33:55 +02:00
Vendicated
f030937bfa
clean up some misleading plugin names 2025-05-24 18:33:30 +02:00
sadan4
6ea960cf90
NoUnblockToJump: Fix outdated plugin description (#3422) 2025-05-24 01:14:36 +00:00
Nuckyz
1fdfd6f305
Fix broken UserSettingsAPI patch 2025-05-23 22:07:48 -03:00
Nuckyz
bbeaa461e5
Fix AnonymiseFileNames 2025-05-21 17:29:01 -03:00
Nuckyz
bd4519a816
Fix VencordToolbox & PermissionsViewer
Fixes components using popups as they now require you to pass a targetElementRef
2025-05-21 00:05:58 -03:00
Nuckyz
e487529f06
OpenInApp: Fix for User Profile Modal V2 2025-05-20 19:12:04 -03:00
Vendicated
a7eb3cd072
WebScreenShareFixes: add stereo stream audio 2025-05-20 01:43:58 +02:00
Nuckyz
eeec088354
ShowHiddenChannels: Fix stage channels hidden screen 2025-05-17 12:23:38 -03:00
Nuckyz
b4dddfda47
Webpack: Make findStore compatible with libdiscore stores 2025-05-16 17:07:38 -03:00
Vendicated
e447dec67b
UserScript: fix 'headers.get is not a function' error 2025-05-16 21:33:41 +02:00
Vendicated
c7f3889713
bump to v1.12.2 2025-05-16 21:23:20 +02:00
Nuckyz
c1074cb8f7
Fix quick css not overriding themes 2025-05-16 15:54:43 -03:00
Nuckyz
88c4dab0c9
WebpackPatcher: Avoid patching libDiscore without relying on name 2025-05-16 08:54:16 -03:00
Vendicated
94b258af4d
fix canary 2025-05-16 03:55:49 +02:00
Suffocate
8023b1be95
Fix jumping to patched module source for new React Dev Tools (#3418) 2025-05-15 23:16:51 +00:00
Nuckyz
c2e5dcc384
Fix MessageLogger edit history & misc SHC patches 2025-05-15 19:54:09 -03:00
Nuckyz
cb8e8bd407
AccountPanelServerProfile: Fix plugin not working 2025-05-14 17:48:28 -03:00
Nuckyz
c1f19d5288
Fix initializing custom themes with ThemeStore too early 2025-05-14 17:48:28 -03:00
Nuckyz
707d688887
WebpackPatcher: Try catch more code prone to errors 2025-05-14 16:24:18 -03:00
Nuckyz
98b1b11dfa
Fix NoServerEmojis, InvisibleChat & other patches 2025-05-13 20:59:13 -03:00
Vendicated
8473b593a7
bump to v1.12.1 2025-05-13 22:59:01 +02:00
Vendicated
59ddf55b99
updater: periodically check for updates while open 2025-05-13 22:39:56 +02:00
Nuckyz
8c7225d106
Clean up circular imports fixes 2025-05-13 22:24:19 +02:00
Vendicated
d542095993
fix ContextMenus on canary 2025-05-13 21:40:28 +02:00
Vendicated
e69575f273
fix canary 2025-05-13 21:15:03 +02:00
Nuckyz
92ff9c1ca4
Fix IrcColors for gradient roles and other patches 2025-05-12 20:38:58 -03:00
Vendicated
690574376b
update to latest React Devtools 2025-05-09 02:19:02 +02:00
Nuckyz
a8b2b0ca64
AlwaysAnimate: Fix animating status emojis 2025-05-07 09:41:45 -03:00
Nuckyz
97af9f8d98
NoUnblockToJump: Fix for latest changes 2025-05-06 18:16:15 -03:00
Nuckyz
89ef26e719
Fix ImageZoom, Vencord Notifications & ReactErrorDecoder 2025-05-05 19:39:34 -03:00
Vendicated
9a3c66abfd
Remove NSFWGateBypass
This plugin was always meant as a tool for adults who don't want to give Discord their birthday/ID.
But obviously there's nothing stopping minors from using this which is troublesome legally and possibly
could lead to me being legally liable for distributing it.

Bypassing it is also becoming progressively harder with the changes Discord is making to abide with UK and
Australia law.

As such, I no longer feel comfortable providing this plugin. If you rely on this plugin (as an adult), find
a suitable third party replacement from elsewhere.
2025-05-05 03:42:38 +02:00
Nuckyz
73f68fe0b7
MutualGroupDMs: Fix overlap in V2 User Profile Modal 2025-05-04 22:03:42 -03:00
Nuckyz
133e924425
BetterFolders: Add className to Sidebar component 2025-05-04 17:05:48 -03:00
Nuckyz
0a2d4a2ab2
Fix plugins for new V2 User Profile Modal 2025-05-04 16:32:23 -03:00
Nuckyz
b0b616d92a
ClientTheme: Fix startup freeze & clean-up plugin (#3413)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-05-04 14:01:08 -03:00
sadan4
235bdee061
BetterFolders: Fix hang (#3412)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-05-04 12:42:13 -03:00
Nuckyz
578aa5f107
Experiments: Fix client crash with new experiment embed 2025-05-03 08:55:40 -03:00
Nuckyz
15fa0ff7a7
PlainFolderIcon: Fix folder colors changing with other themes 2025-05-03 08:20:32 -03:00
Nuckyz
34269e2339
Bump to 1.12.0 2025-05-02 22:54:37 -03:00
Nuckyz
8aa92873b9
Fix MutualGroupDMs duplicate find 2025-05-02 22:52:51 -03:00
Mufaro
3b53ad0c91
Experiments: Support new experiment link embeds & fix toolbar patch (#3372) 2025-05-02 22:46:34 -03:00
sadan4
59974a162e
PlainFolderIcon: Fix plugin not working (#3409) 2025-05-03 01:30:10 +00:00
hexa
bebf3dd068
ImageZoom: Fix for animated WebP images (#3407) 2025-05-03 01:28:53 +00:00
sadan4
838a90831f
Fix BetterFolders, ReviewDB and minor ShowHiddenChannels patch (#3396)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-05-03 00:40:07 +00:00
Vendicated
b954bf3c9d
MutualGroupDMs: fix DM sidebar (again) 2025-04-30 22:33:20 +02:00
Vendicated
096f848385
MutualGroupDMs: fix weird spacing 2025-04-30 04:14:03 +02:00
Vendicated
9fa91c193d
Fix ServerInfo, ShowMeYourName & WebContextMenus 2025-04-30 04:12:42 +02:00
Vendicated
dad69e0d0f
Fix Vencord Notifications & ImageZoom causing crashes 2025-04-30 03:11:56 +02:00
Vendicated
700b971e7d
MutualGroupDMs: fix display in dm profile sidebar 2025-04-25 00:45:17 +02:00
sadan4
cf78ddcfe2
fix plugins for latest discord update (#3387)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-04-23 20:36:43 +02:00
khcrysalis
e99e89e964
MessageLogger: correctly ignore venbot in all vc support channels (#3384)
Co-authored-by: Vending Machine <vendicated@riseup.net>
2025-04-16 20:57:49 +02:00
sadan4
524202e49d
Fix clipboard api, IrcColors, and Memberlist Decorators (#3383)
Co-authored-by: Vending Machine <vendicated@riseup.net>
2025-04-16 20:34:16 +02:00
Elvyra
82f9cd1d3a
Fix: RoleColorEverywhere, AccountPanelServerProfile, BANger (#3378)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: Vending Machine <vendicated@riseup.net>
2025-04-15 01:43:50 +02:00
Vending Machine
0f4d3dfd3a
SpotifyControls: fix SeekBar not updating (#3381)
Also slightly reworks LazyComponents for more useful typing
2025-04-14 15:21:30 +02:00
Vendicated
a8c01a2a05
ConsoleShortcuts: fix module preloader 2025-04-14 14:45:21 +02:00
iilwy
fe0309ffaa
fix "Disable minimum window size" option (#3335)
Fixes #3330
Fixes #878
2025-04-14 13:41:50 +02:00
Vendicated
1fa6181f7e
Translate: use newer google api with better results 2025-04-11 18:14:17 +02:00
Vendicated
77bed92c57
bump to 1.11.9 2025-04-10 17:14:05 +02:00
Vendicated
6f23c9e67a
ReadAllNotificationsButton: adjust look for new ui 2025-04-10 16:56:15 +02:00
sadan4
3dd58c2551
fix RoleColorEverywhere (#3370) 2025-04-10 14:45:22 +00:00
sadan4
8ad33db6c2
fix plugins using the image modal (#3368) 2025-04-10 16:44:04 +02:00
Vendicated
64dadcce4c
DisableDeepLinks Plugin: disables deep links on web/vesktop 2025-04-08 00:50:22 +02:00
Vending Machine
e5f6605c01
VcNarrator: Fix voice selection setting (#3365) 2025-04-07 00:58:07 +02:00
sadan4
d753478097
BetterFolders: Fix folder bottom margin in main sidebar (#3352) 2025-04-05 00:53:06 +00:00
Vendicated
0e7d7541bb
fix theme flickering on certain actions 2025-04-05 02:10:52 +02:00
Cassie
ab38e59550
ClientTheme: Fix for visual refresh (#3313) 2025-04-04 23:06:42 +00:00
jamesbt365
4f11316a8b
PauseInvitesForever: Avoid adding button if missing permissions (#3306) 2025-04-04 22:47:24 +00:00
sadan4
71f352a611
AccountPanelServerProfile: Fix patch issue with onPopoutClose (#3304) 2025-04-04 22:45:19 +00:00
sadan4
9d2f2460e1
BetterFolders: Fix for visual refresh (#3314) 2025-04-04 22:33:59 +00:00
sadan4
094a7852b1
Fix size of chat bar buttons on new ui (#3351) 2025-04-05 00:32:15 +02:00
James McKee
cdd8f30962
oneko: Fix oneko being hidden under some elements (#3274) 2025-04-04 22:22:43 +00:00
rini c
7eeb719eac
Update Plugin Settings, GameActivityToggle & TypingTweaks for new ui (#3326) 2025-04-04 23:55:08 +02:00
Ethan
c8b54234fa
SpotifyShareCommands: add message argument like inbuilt commands (#3320)
also cleans up the plugin's code

Co-authored-by: Vendicated <vendicated@riseup.net>
2025-04-04 23:19:03 +02:00
dolfies
7450ecd6f3
ImplicitRelationships: update logic (#3338) 2025-04-04 23:04:20 +02:00
Vendicated
7246bface3
update vesktop build target name 2025-04-04 22:59:21 +02:00
Vendicated
8d0256bde8
Vesktop: force disable broken DeepLinks experiment 2025-04-04 22:54:27 +02:00
sadan4
478699d1b0
Fix broken stuff for discord update (#3349)
Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
Co-authored-by: Vending Machine <vendicated@riseup.net>
2025-04-04 22:46:01 +02:00
Elvyra
eeea8d9291
fix IrcColors and ShowMeYourName (#3343) 2025-04-04 16:22:46 +02:00
fawn
96ee0c1351
fix notification background on new ui (#3344) 2025-04-04 14:01:41 +00:00
Vendicated
22b50f03ca
bump to 1.11.8 2025-04-04 06:16:11 +02:00
sadan4
599c33769c
Fix crashing when opening settings (#3350)
Co-authored-by: Vendicated <vendicated@riseup.net>
2025-04-04 04:12:17 +00:00
Vendicated
93f98cee2c
use correct card background colour on new ui 2025-04-02 05:49:15 +02:00
OutCraft
dcb31ca849
Fix inconsistency in VcNarrator default options (#3246) 2025-04-02 03:24:24 +00:00
khcrysalis
dcd4531327
Settings: make donor message less misleading for people without a badge (#3264) 2025-04-02 05:04:38 +02:00
Vendicated
188fd48659
pnpm patch: pass through cli args 2025-04-02 04:55:24 +02:00
khcrysalis
1126dc6e66
Settings: update addon cards for new ui (#3311) 2025-04-02 02:35:08 +00:00
nin0dev
f075fed236
SpotifyControls: make panel look more in line with visual refresh (#3312) 2025-04-02 04:30:10 +02:00
sadan4
cef806a243
PlainFolderIcon: Fix on new UI (#3317) 2025-04-02 02:22:47 +00:00
Vendicated
95bd8c831c
NSFWGateBypass: bypass new UK/Australia gate
Co-Authored-By: dotle31 <abacubabacus@gmail.com>
2025-04-02 03:41:55 +02:00
sadan4
8ca91354ac
fix MessageDecorationsApi (#3337) 2025-04-02 03:09:45 +02:00
sadan4
b980320d0a
ThemeAttributes: Fix null handling (#3308) 2025-04-02 02:43:17 +02:00
Vendicated
d563b66842
fix: do not limit text settings to 999 chars
Fixes https://github.com/Vendicated/Vencord/issues/3322
2025-03-27 02:18:20 +01:00
Vendicated
d62be1b94a
SupportHelper: Enable in more channels 2025-03-27 02:18:19 +01:00
605 changed files with 23090 additions and 12785 deletions

View file

@ -44,12 +44,6 @@ jobs:
run: |
pnpm install --frozen-lockfile
- name: Install Google Chrome
id: setup-chrome
uses: browser-actions/setup-chrome@82b9ce628cc5595478a9ebadc480958a36457dc2
with:
chrome-version: stable
- name: Build Vencord Reporter Version
run: pnpm buildReporter
@ -57,7 +51,7 @@ jobs:
timeout-minutes: 10
run: |
export PATH="$PWD/node_modules/.bin:$PATH"
export CHROMIUM_BIN=${{ steps.setup-chrome.outputs.chrome-path }}
export CHROMIUM_BIN=/usr/bin/google-chrome
esbuild scripts/generateReport.ts > dist/report.mjs

2
.gitignore vendored
View file

@ -22,4 +22,4 @@ lerna-debug.log*
src/userplugins
ExtensionCache/
settings/
/settings

View file

@ -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"
}
}

View file

@ -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)

View file

@ -17,9 +17,10 @@
*/
function parseHeaders(headers) {
const result = new Headers();
if (!headers)
return {};
const result = {};
return result;
const headersArr = headers.trim().split("\n");
for (var i = 0; i < headersArr.length; i++) {
var row = headersArr[i];
@ -27,13 +28,7 @@ function parseHeaders(headers) {
, key = row.slice(0, index).trim().toLowerCase()
, value = row.slice(index + 1).trim();
if (result[key] === undefined) {
result[key] = value;
} else if (Array.isArray(result[key])) {
result[key].push(value);
} else {
result[key] = [result[key], value];
}
result.append(key, value);
}
return result;
}

View file

@ -19,17 +19,16 @@
/// <reference path="../src/modules.d.ts" />
/// <reference path="../src/globals.d.ts" />
// Be very careful with imports in this file to avoid circular dependency issues.
// Only import pure modules that don't import other parts of Vencord.
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 { 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 * as DataStore from "@api/DataStore";
import type { Settings } from "@api/Settings";
import { getThemeInfo } from "@main/themes";
import { debounce } from "@shared/debounce";
import { localStorage } from "@utils/localStorage";
import { getStylusWebStoreUrl } from "@utils/web";
import { EXTENSION_BASE_URL, metaReady, RENDERER_CSS_URL } from "@utils/web-metadata";
// listeners for ipc.on
const cssListeners = new Set<(css: string) => void>();
@ -45,17 +44,29 @@ 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: {
getVersions: () => ({}),
openExternal: async (url) => void open(url, "_blank")
openExternal: async (url) => void open(url, "_blank"),
getRendererCss: async () => {
if (IS_USERSCRIPT)
// need to wait for next tick for _vcUserScriptRendererCss to be set
return Promise.resolve().then(() => window._vcUserScriptRendererCss);
await metaReady;
return fetch(RENDERER_CSS_URL)
.then(res => res.text());
},
onRendererCssUpdate: NOOP,
},
updater: {
@ -77,6 +88,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) {
@ -87,13 +106,17 @@ window.VencordNative = {
win.baseUrl = EXTENSION_BASE_URL;
win.setCss = setCssDebounced;
win.getCurrentCss = () => VencordNative.quickCss.get();
win.getTheme = () =>
getTheme() === Theme.Light
? "vs-light"
: "vs-dark";
win.getTheme = this.getEditorTheme;
win.document.write(IS_EXTENSION ? monacoHtmlLocal : monacoHtmlCdn);
win.document.write(monacoHtmlLocal);
},
getEditorTheme: () => {
const { getTheme, Theme } = require("@utils/discord");
return getTheme() === Theme.Light
? "vs-light"
: "vs-dark";
}
},
settings: {
@ -106,8 +129,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,
};

View file

@ -12,7 +12,7 @@ chrome.webRequest.onHeadersReceived.addListener(
({ responseHeaders, type, url }) => {
if (!responseHeaders) return;
if (type === "main_frame") {
if (type === "main_frame" && url.includes("discord.com")) {
// In main frame requests, the CSP needs to be removed to enable fetching of custom css
// as desired by the user
removeFirst(responseHeaders, h => h.name.toLowerCase() === "content-security-policy");

View file

@ -2,20 +2,15 @@ if (typeof browser === "undefined") {
var browser = chrome;
}
const style = document.createElement("link");
style.type = "text/css";
style.rel = "stylesheet";
style.href = browser.runtime.getURL("dist/Vencord.css");
document.addEventListener(
"DOMContentLoaded",
() => {
document.documentElement.append(style);
window.postMessage({
type: "vencord:meta",
meta: {
EXTENSION_VERSION: browser.runtime.getManifest().version,
EXTENSION_BASE_URL: browser.runtime.getURL(""),
RENDERER_CSS_URL: browser.runtime.getURL("dist/Vencord.css"),
}
});
},

View file

@ -15,7 +15,8 @@
]
},
"condition": {
"resourceTypes": ["main_frame", "sub_frame"]
"resourceTypes": ["main_frame", "sub_frame"],
"urlFilter": "||discord.com^"
}
},
{
@ -32,7 +33,7 @@
},
"condition": {
"resourceTypes": ["stylesheet"],
"urlFilter": "https://raw.githubusercontent.com/*"
"urlFilter": "||raw.githubusercontent.com^"
}
}
]

View file

@ -9,6 +9,7 @@
// @license GPL-3.0
// @match *://*.discord.com/*
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @run-at document-start
// @compatible chrome Chrome + Tampermonkey or Violentmonkey
// @compatible firefox Firefox Tampermonkey

View file

@ -90,7 +90,7 @@ export default tseslint.config(
"@stylistic/no-extra-semi": "error",
// TS Rules
"@stylistic/func-call-spacing": ["error", "never"],
"@stylistic/function-call-spacing": ["error", "never"],
// ESLint Rules
"yoda": "error",
@ -115,7 +115,7 @@ export default tseslint.config(
"no-useless-escape": [
"error",
{
"extra": "i"
"allowRegexCharacters": ["i"]
}
],
"no-fallthrough": "error",

View file

@ -1,7 +1,7 @@
{
"name": "vencord",
"private": "true",
"version": "1.11.7",
"version": "1.14.6",
"description": "The cutest Discord client mod",
"homepage": "https://github.com/Vendicated/Vencord#readme",
"bugs": {
@ -25,8 +25,8 @@
"watchWeb": "pnpm buildWeb --watch",
"generatePluginJson": "tsx scripts/generatePluginList.ts",
"generateTypes": "tspc --emitDeclarationOnly --declaration --outDir packages/vencord-types --allowJs false",
"inject": "node scripts/runInstaller.mjs",
"uninject": "node scripts/runInstaller.mjs",
"inject": "node scripts/runInstaller.mjs -- --install",
"uninject": "node scripts/runInstaller.mjs -- --uninstall",
"lint": "eslint",
"lint-styles": "stylelint \"src/**/*.css\" --ignore-pattern src/userplugins",
"lint:fix": "pnpm lint --fix",
@ -40,49 +40,49 @@
"@vap/shiki": "0.10.5",
"fflate": "^0.8.2",
"gifenc": "github:mattdesl/gifenc#64842fca317b112a8590f8fef2bf3825da8f6fe3",
"monaco-editor": "^0.52.2",
"nanoid": "^5.0.9",
"monaco-editor": "^0.54.0",
"nanoid": "^5.1.6",
"virtual-merge": "^1.0.1"
},
"devDependencies": {
"@stylistic/eslint-plugin": "^4.0.0",
"@types/chrome": "^0.0.304",
"@types/diff": "^7.0.1",
"@types/lodash": "^4.17.14",
"@types/node": "^22.10.5",
"@stylistic/eslint-plugin": "^5.6.0",
"@types/chrome": "^0.1.30",
"@types/lodash": "^4.17.20",
"@types/node": "^24.10.1",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@types/yazl": "^2.4.5",
"diff": "^7.0.0",
"discord-types": "^1.3.26",
"esbuild": "^0.25.0",
"eslint": "^9.20.1",
"@types/yazl": "^3.3.0",
"@vencord/discord-types": "link:packages/discord-types",
"diff": "^8.0.2",
"esbuild": "^0.27.0",
"eslint": "9.39.1",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-path-alias": "2.1.0",
"eslint-plugin-react": "^7.37.3",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-simple-header": "^1.2.1",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-unused-imports": "^4.1.4",
"eslint-plugin-unused-imports": "^4.3.0",
"highlight.js": "11.11.1",
"html-minifier-terser": "^7.2.0",
"moment": "^2.22.2",
"puppeteer-core": "^24.2.1",
"p-limit": "^7.3.0",
"puppeteer-core": "^24.30.0",
"standalone-electron-types": "^34.2.0",
"stylelint": "^16.12.0",
"stylelint-config-standard": "^37.0.0",
"stylelint": "^16.25.0",
"stylelint-config-standard": "^39.0.1",
"svgo": "^4.0.0",
"ts-patch": "^3.3.0",
"ts-pattern": "^5.6.0",
"tsx": "^4.19.2",
"type-fest": "^4.31.0",
"typescript": "^5.7.2",
"typescript-eslint": "^8.19.0",
"typescript-transform-paths": "^3.5.3",
"tsx": "^4.20.6",
"type-fest": "^5.2.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.47.0",
"typescript-transform-paths": "^3.5.5",
"zip-local": "^0.3.5"
},
"packageManager": "pnpm@10.4.1",
"pnpm": {
"patchedDependencies": {
"eslint@9.20.1": "patches/eslint@9.20.1.patch",
"eslint-plugin-path-alias@2.1.0": "patches/eslint-plugin-path-alias@2.1.0.patch"
},
"peerDependencyRules": {

View file

@ -0,0 +1 @@
node_modules

View file

@ -0,0 +1 @@
Hint: https://docs.discord.food is an incredible resource and allows you to copy paste complete enums and interfaces

View file

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View file

@ -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.

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -0,0 +1,6 @@
export * from "./activity";
export * from "./channel";
export * from "./commands";
export * from "./messages";
export * from "./misc";
export * from "./user";

View file

@ -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,
}

View file

@ -0,0 +1,103 @@
export const enum CloudUploadPlatform {
REACT_NATIVE = 0,
WEB = 1,
}
export const enum DraftType {
ChannelMessage = 0,
ThreadSettings = 1,
FirstThreadMessage = 2,
ApplicationLauncherCommand = 3,
Poll = 4,
SlashCommand = 5,
ForwardContextMessage = 6,
}
export const enum GuildScheduledEventStatus {
SCHEDULED = 1,
ACTIVE = 2,
COMPLETED = 3,
CANCELED = 4,
}
export const enum GuildScheduledEventEntityType {
STAGE_INSTANCE = 1,
VOICE = 2,
EXTERNAL = 3,
}
export const enum GuildScheduledEventPrivacyLevel {
GUILD_ONLY = 2,
}
export const enum ParticipantType {
STREAM = 0,
HIDDEN_STREAM = 1,
USER = 2,
ACTIVITY = 3,
}
export const enum RTCPlatform {
DESKTOP = 0,
MOBILE = 1,
XBOX = 2,
PLAYSTATION = 3,
}
export const enum VideoSourceType {
VIDEO = 0,
CAMERA_PREVIEW = 1,
}
export const enum EmojiIntention {
REACTION = 0,
STATUS = 1,
COMMUNITY_CONTENT = 2,
CHAT = 3,
GUILD_STICKER_RELATED_EMOJI = 4,
GUILD_ROLE_BENEFIT_EMOJI = 5,
SOUNDBOARD = 6,
VOICE_CHANNEL_TOPIC = 7,
GIFT = 8,
AUTO_SUGGESTION = 9,
POLLS = 10,
PROFILE = 11,
MESSAGE_CONFETTI = 12,
GUILD_PROFILE = 13,
CHANNEL_NAME = 14,
DEFAULT_REACT_EMOJI = 15,
}
export const enum LoadState {
NOT_LOADED = 0,
LOADING = 1,
LOADED = 2,
ERROR = 3,
}
export const enum ConnectionStatsFlags {
TRANSPORT = 1,
OUTBOUND = 2,
INBOUND = 4,
ALL = 7,
}
export const enum SpeakingFlags {
NONE = 0,
VOICE = 1,
SOUNDSHARE = 2,
PRIORITY = 4,
HIDDEN = 8,
}
export const enum GoLiveQualityMode {
AUTO = 1,
FULL = 2,
}
export const enum VoiceProcessingStateReason {
CPU_OVERUSE = 1,
FAILED = 2,
VAD_CPU_OVERUSE = 3,
INITIALIZED = 4,
}

View file

@ -0,0 +1,22 @@
export const enum RelationshipType {
NONE = 0,
FRIEND = 1,
BLOCKED = 2,
INCOMING_REQUEST = 3,
OUTGOING_REQUEST = 4,
IMPLICIT = 5,
SUGGESTION = 6
}
export enum GiftIntentType {
FRIEND_ANNIVERSARY = 0
}
export const enum ReadStateType {
CHANNEL = 0,
GUILD_EVENT = 1,
NOTIFICATION_CENTER = 2,
GUILD_HOME = 3,
GUILD_ONBOARDING_QUESTION = 4,
MESSAGE_REQUESTS = 5,
}

View file

@ -0,0 +1,22 @@
{
"name": "@vencord/discord-types",
"author": "Vencord Contributors",
"private": false,
"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": {
"moment": "^2.22.2",
"type-fest": "^4.41.0"
},
"peerDependencies": {
"@types/react": "^19.0.10"
}
}

View file

@ -0,0 +1,43 @@
import { ActivityFlags, ActivityStatusDisplayType, ActivityType } from "../../enums";
export interface ActivityAssets {
large_image?: string;
large_text?: string;
large_url?: string;
small_image?: string;
small_text?: string;
small_url?: 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<string>;
};
party?: {
id?: string;
size?: [number, number];
};
}
export type OnlineStatus = "online" | "idle" | "dnd" | "invisible" | "offline" | "unknown" | "streaming";

View file

@ -0,0 +1,89 @@
import { Guild } from "./Guild";
import { User } from "./User";
export interface ApplicationExecutable {
os: "win32" | "darwin" | "linux";
name: string;
isLauncher: boolean;
}
export interface ApplicationThirdPartySku {
id: string;
sku: string;
distributor: string;
}
export interface ApplicationDeveloper {
id: string;
name: string;
}
export interface ApplicationInstallParams {
permissions: string | null;
scopes: string[];
}
export interface Application {
id: string;
name: string;
icon: string | null;
description: string;
type: number | null;
coverImage: string | null;
primarySkuId: string | undefined;
bot: User | null;
splash: string | undefined;
thirdPartySkus: ApplicationThirdPartySku[];
isMonetized: boolean;
isVerified: boolean;
roleConnectionsVerificationUrl: string | undefined;
parentId: string | undefined;
connectionEntrypointUrl: string | undefined;
overlay: boolean;
overlayWarn: boolean;
overlayCompatibilityHook: boolean;
overlayMethods: number;
hook: boolean;
aliases: string[];
publishers: ApplicationDeveloper[];
developers: ApplicationDeveloper[];
storeListingSkuId: string | undefined;
guildId: string | null;
guild: Guild | undefined;
executables: ApplicationExecutable[];
hashes: string[];
eulaId: string | undefined;
slug: string | undefined;
flags: number;
maxParticipants: number | undefined;
tags: string[];
embeddedActivityConfig: Record<string, unknown> | undefined;
team: ApplicationTeam | undefined;
integrationTypesConfig: Record<string, Record<string, unknown>>;
storefront_available: boolean;
termsOfServiceUrl: string | undefined;
privacyPolicyUrl: string | undefined;
isDiscoverable: boolean;
customInstallUrl: string | undefined;
installParams: ApplicationInstallParams | undefined;
directoryEntry: Record<string, unknown> | undefined;
categories: string[] | undefined;
linkedGames: string[] | undefined;
deepLinkUri: string | undefined;
}
export interface ApplicationTeam {
id: string;
name: string;
icon: string | null;
members: ApplicationTeamMember[];
ownerUserId: string;
}
export interface ApplicationTeamMember {
user: User;
teamId: string;
membershipState: number;
permissions: string[];
role: string;
}

View file

@ -0,0 +1,83 @@
import { DiscordRecord } from "./Record";
export class Channel extends DiscordRecord {
constructor(channel: object);
application_id: number | undefined;
bitrate: number;
defaultAutoArchiveDuration: number | undefined;
flags: number;
guild_id: string;
icon: string;
id: string;
lastMessageId: string;
lastPinTimestamp: string | undefined;
member: unknown;
memberCount: number | undefined;
memberIdsPreview: string[] | undefined;
memberListId: unknown;
messageCount: number | undefined;
name: string;
nicks: Record<string, unknown>;
nsfw: boolean;
originChannelId: unknown;
ownerId: string;
parent_id: string;
permissionOverwrites: {
[role: string]: {
id: string;
type: number;
deny: bigint;
allow: bigint;
};
};
position: number;
rateLimitPerUser: number;
rawRecipients: {
id: string;
avatar: string;
username: string;
public_flags: number;
discriminator: string;
}[];
recipients: string[];
rtcRegion: string;
threadMetadata: {
locked: boolean;
archived: boolean;
invitable: boolean;
createTimestamp: string | undefined;
autoArchiveDuration: number;
archiveTimestamp: string | undefined;
};
topic: string;
type: number;
userLimit: number;
videoQualityMode: undefined;
get accessPermissions(): bigint;
get lastActiveTimestamp(): number;
computeLurkerPermissionsAllowList(): unknown;
getApplicationId(): unknown;
getGuildId(): string;
getRecipientId(): unknown;
hasFlag(flag: number): boolean;
isActiveThread(): boolean;
isArchivedThread(): boolean;
isCategory(): boolean;
isDM(): boolean;
isDirectory(): boolean;
isForumChannel(): boolean;
isGroupDM(): boolean;
isGuildStageVoice(): boolean;
isGuildVoice(): boolean;
isListenModeCapable(): boolean;
isManaged(): boolean;
isMultiUserDM(): boolean;
isNSFW(): boolean;
isOwner(): boolean;
isPrivate(): boolean;
isSystemDM(): boolean;
isThread(): boolean;
isVocal(): boolean;
}

View file

@ -0,0 +1,64 @@
import { Role } from './Role';
import { DiscordRecord } from './Record';
// copy(Object.keys(findByProps("CREATOR_MONETIZABLE")).map(JSON.stringify).join("|"))
export type GuildFeatures =
"INVITE_SPLASH" | "VIP_REGIONS" | "VANITY_URL" | "MORE_EMOJI" | "MORE_STICKERS" | "MORE_SOUNDBOARD" | "VERIFIED" | "COMMERCE" | "DISCOVERABLE" | "COMMUNITY" | "FEATURABLE" | "NEWS" | "HUB" | "PARTNERED" | "ANIMATED_ICON" | "BANNER" | "ENABLED_DISCOVERABLE_BEFORE" | "WELCOME_SCREEN_ENABLED" | "MEMBER_VERIFICATION_GATE_ENABLED" | "PREVIEW_ENABLED" | "ROLE_SUBSCRIPTIONS_ENABLED" | "ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE" | "CREATOR_MONETIZABLE" | "CREATOR_MONETIZABLE_PROVISIONAL" | "CREATOR_MONETIZABLE_WHITEGLOVE" | "CREATOR_MONETIZABLE_DISABLED" | "CREATOR_MONETIZABLE_RESTRICTED" | "CREATOR_STORE_PAGE" | "CREATOR_MONETIZABLE_PENDING_NEW_OWNER_ONBOARDING" | "PRODUCTS_AVAILABLE_FOR_PURCHASE" | "GUILD_WEB_PAGE_VANITY_URL" | "THREADS_ENABLED" | "THREADS_ENABLED_TESTING" | "NEW_THREAD_PERMISSIONS" | "ROLE_ICONS" | "TEXT_IN_STAGE_ENABLED" | "TEXT_IN_VOICE_ENABLED" | "HAS_DIRECTORY_ENTRY" | "ANIMATED_BANNER" | "LINKED_TO_HUB" | "EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT" | "GUILD_HOME_DEPRECATION_OVERRIDE" | "GUILD_HOME_TEST" | "GUILD_HOME_OVERRIDE" | "GUILD_ONBOARDING" | "GUILD_ONBOARDING_EVER_ENABLED" | "GUILD_ONBOARDING_HAS_PROMPTS" | "GUILD_SERVER_GUIDE" | "INTERNAL_EMPLOYEE_ONLY" | "AUTO_MODERATION" | "INVITES_DISABLED" | "BURST_REACTIONS" | "SOUNDBOARD" | "SHARD" | "ACTIVITY_FEED_ENABLED_BY_USER" | "ACTIVITY_FEED_DISABLED_BY_USER" | "SUMMARIES_ENABLED_GA" | "LEADERBOARD_ENABLED" | "SUMMARIES_ENABLED_BY_USER" | "SUMMARIES_OPT_OUT_EXPERIENCE" | "CHANNEL_ICON_EMOJIS_GENERATED" | "NON_COMMUNITY_RAID_ALERTS" | "RAID_ALERTS_DISABLED" | "AUTOMOD_TRIGGER_USER_PROFILE" | "ENABLED_MODERATION_EXPERIENCE_FOR_NON_COMMUNITY" | "GUILD_PRODUCTS_ALLOW_ARCHIVED_FILE" | "CLAN" | "MEMBER_VERIFICATION_MANUAL_APPROVAL" | "FORWARDING_DISABLED" | "MEMBER_VERIFICATION_ROLLOUT_TEST" | "AUDIO_BITRATE_128_KBPS" | "AUDIO_BITRATE_256_KBPS" | "AUDIO_BITRATE_384_KBPS" | "VIDEO_BITRATE_ENHANCED" | "MAX_FILE_SIZE_50_MB" | "MAX_FILE_SIZE_100_MB" | "GUILD_TAGS" | "ENHANCED_ROLE_COLORS" | "PREMIUM_TIER_3_OVERRIDE" | "REPORT_TO_MOD_PILOT" | "TIERLESS_BOOSTING_SYSTEM_MESSAGE";
export type GuildPremiumFeatures =
"ANIMATED_ICON" | "STAGE_CHANNEL_VIEWERS_150" | "ROLE_ICONS" | "GUILD_TAGS" | "BANNER" | "MAX_FILE_SIZE_50_MB" | "VIDEO_QUALITY_720_60FPS" | "STAGE_CHANNEL_VIEWERS_50" | "VIDEO_QUALITY_1080_60FPS" | "MAX_FILE_SIZE_100_MB" | "VANITY_URL" | "VIDEO_BITRATE_ENHANCED" | "STAGE_CHANNEL_VIEWERS_300" | "AUDIO_BITRATE_128_KBPS" | "ANIMATED_BANNER" | "TIERLESS_BOOSTING" | "ENHANCED_ROLE_COLORS" | "INVITE_SPLASH" | "AUDIO_BITRATE_256_KBPS" | "AUDIO_BITRATE_384_KBPS";
export class Guild extends DiscordRecord {
constructor(guild: object);
afkChannelId: string | undefined;
afkTimeout: number;
applicationCommandCounts: {
0: number;
1: number;
2: number;
};
application_id: unknown;
banner: string | undefined;
defaultMessageNotifications: number;
description: string | undefined;
discoverySplash: string | undefined;
explicitContentFilter: number;
features: Set<GuildFeatures>;
homeHeader: string | undefined;
hubType: unknown;
icon: string | undefined;
id: string;
joinedAt: Date;
latestOnboardingQuestionId: string | undefined;
maxMembers: number;
maxStageVideoChannelUsers: number;
maxVideoChannelUsers: number;
mfaLevel: number;
moderatorReporting: unknown;
name: string;
nsfwLevel: number;
ownerConfiguredContentLevel: number;
ownerId: string;
preferredLocale: string;
premiumFeatures: {
additionalEmojiSlots: number;
additionalSoundSlots: number;
additionalStickerSlots: number;
features: Array<GuildPremiumFeatures>;
};
premiumProgressBarEnabled: boolean;
premiumSubscriberCount: number;
premiumTier: 0 | 1 | 2 | 3;
profile: {
badge: string | undefined;
tag: string | undefined;
} | undefined;
publicUpdatesChannelId: string | undefined;
roles: Record<string, Role>;
rulesChannelId: string | undefined;
safetyAlertsChannelId: string | undefined;
splash: string | undefined;
systemChannelFlags: number;
systemChannelId: string | undefined;
vanityURLCode: string | undefined;
verificationLevel: number;
}

View file

@ -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;
}

View file

@ -0,0 +1,12 @@
type Updater = (value: any) => any;
/**
* Common Record class extended by various Discord data structures, like User, Channel, Guild, etc.
*/
export class DiscordRecord {
toJS(): Record<string, any>;
set(key: string, value: any): this;
merge(data: Record<string, any>): this;
update(key: string, defaultValueOrUpdater: Updater | any, updater?: Updater): this;
}

View file

@ -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;
}

View file

@ -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<string, string>;
id: string;
mfaEnabled: boolean;
mobile: boolean;
nsfwAllowed: boolean | undefined;
phone: string | undefined;
premiumType: number | undefined;
premiumUsageFlags: number;
publicFlags: number;
purchasedFlags: number;
system: boolean;
username: string;
verified: boolean;
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;
}

View file

@ -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";

View file

@ -0,0 +1,61 @@
import { Channel } from "../Channel";
import { Guild } from "../Guild";
import { Promisable } from "type-fest";
import { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType } from "../../../enums";
export interface CommandContext {
channel: Channel;
guild?: Guild;
}
export interface CommandOption {
name: string;
displayName?: string;
type: ApplicationCommandOptionType;
description: string;
displayDescription?: string;
required?: boolean;
options?: CommandOption[];
choices?: Array<ChoicesOption>;
}
export interface ChoicesOption {
label: string;
value: string;
name: string;
displayName?: string;
}
export interface CommandReturnValue {
content: string;
// TODO: implement
// cancel?: boolean;
}
export interface CommandArgument {
type: ApplicationCommandOptionType;
name: string;
value: string;
focused: undefined;
options: CommandArgument[];
}
export interface Command {
id?: string;
applicationId?: string;
type?: ApplicationCommandType;
inputType?: ApplicationCommandInputType;
plugin?: string;
name: string;
untranslatedName?: string;
displayName?: string;
description: string;
untranslatedDescription?: string;
displayDescription?: string;
options?: CommandOption[];
predicate?(ctx: CommandContext): boolean;
execute(args: CommandArgument[], ctx: CommandContext): Promisable<void | CommandReturnValue>;
}

View file

@ -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;
};
}

View file

@ -0,0 +1,114 @@
/** Union type for both custom (guild) emojis and unicode emojis. */
export type Emoji = CustomEmoji | UnicodeEmoji;
/**
* Custom emoji uploaded to a guild.
*/
export interface CustomEmoji {
/** Discriminator for custom emojis. */
type: 1;
/** Whether the emoji is animated (GIF). */
animated: boolean;
/** Whether the emoji is available for use. */
available: boolean;
/** Guild id this emoji belongs to. */
guildId: string;
/** Unique emoji id (snowflake). */
id: string;
/** Whether the emoji is managed by an integration (e.g. Twitch). */
managed: boolean;
/** Emoji name without colons. */
name: string;
/** Original name before any modifications. */
originalName?: string;
/** Whether the emoji requires colons to use. */
require_colons: boolean;
/** Role ids that can use this emoji (empty array means everyone). */
roles: string[];
/** Version number, incremented when emoji is updated. */
version?: number;
}
/**
* Built-in unicode emoji.
*/
export interface UnicodeEmoji {
/** Discriminator for unicode emojis. */
type: 0;
/** Skin tone variant emojis keyed by diversity surrogate code (e.g. "1f3fb" for light skin). */
diversityChildren: Record<string, UnicodeEmoji>;
/** Raw emoji data from Discord's emoji dataset. */
emojiObject: EmojiObject;
/** Index position in the emoji list. */
index: number;
/** Unicode surrogate pair(s) for this emoji. */
surrogates: string;
/** Unique name identifier for this emoji. */
uniqueName: string;
/** Whether to render using sprite sheet. */
useSpriteSheet: boolean;
/** Original name if renamed in context. */
originalName?: string;
/** Emoji id when used in custom emoji context. */
id?: string;
/** Guild id when used in guild context. */
guildId?: string;
/** Formatted string of all emoji names. */
get allNamesString(): string;
/** Always false for unicode emojis. */
get animated(): false;
/** Default skin tone variant or undefined if no diversity. */
get defaultDiversityChild(): UnicodeEmoji | undefined;
/** Whether this emoji supports skin tone modifiers. */
get hasDiversity(): boolean | undefined;
/** Whether this emoji is a skin tone variant of another. */
get hasDiversityParent(): boolean | undefined;
/** Whether this emoji supports multiple diversity modifiers (e.g. handshake with two skin tones). */
get hasMultiDiversity(): boolean | undefined;
/** Whether this emoji is a multi-diversity variant of another. */
get hasMultiDiversityParent(): boolean | undefined;
/** Always true for unicode emojis. */
get managed(): true;
/** Primary emoji name. */
get name(): string;
/** All names/aliases for this emoji. */
get names(): string[];
/** Surrogate sequence with optional diversity modifier. */
get optionallyDiverseSequence(): string | undefined;
/** Unicode version when this emoji was added. */
get unicodeVersion(): number;
/** CDN url for emoji image. */
get url(): string;
/**
* Iterates over all diversity variants of this emoji.
* @param callback Function called for each diversity variant.
*/
forEachDiversity(callback: (emoji: UnicodeEmoji) => void): void;
/**
* Iterates over all names/aliases of this emoji.
* @param callback Function called for each name.
*/
forEachName(callback: (name: string) => void): void;
}
/**
* Raw emoji data from Discord's emoji dataset.
*/
export interface EmojiObject {
/** All names/aliases for this emoji. */
names: string[];
/** Unicode surrogate pair(s). */
surrogates: string;
/** Unicode version when this emoji was added. */
unicodeVersion: number;
/** Index in the sprite sheet for rendering. */
spriteIndex?: number;
/** Whether this emoji supports multiple skin tone modifiers. */
hasMultiDiversity?: boolean;
/** Whether this emoji is a diversity variant with a multi-diversity parent. */
hasMultiDiversityParent?: boolean;
/** Skin tone modifier codes for this variant (e.g. ["1f3fb"] or ["1f3fb", "1f3fc"]). */
diversity?: string[];
/** Sprite indices of diversity children for parent emojis. */
diversityChildren?: number[];
}

View file

@ -0,0 +1,217 @@
import { CommandOption } from './Commands';
import { User, UserJSON } from '../User';
import { Embed, EmbedJSON } from './Embed';
import { DiscordRecord } from "../Record";
import { ApplicationIntegrationType, 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;
}[];
interactionMetadata?: {
id: string;
type: number;
name?: string;
command_type?: number;
ephemerality_reason?: number;
user: User;
authorizing_integration_owners: Record<ApplicationIntegrationType, string>;
original_response_message_id?: string;
interacted_message_id?: string;
target_user?: User;
target_message_id?: 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<MessageType>
>;

View file

@ -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[];
}

View file

@ -0,0 +1,5 @@
export * from "./Commands";
export * from "./Message";
export * from "./Embed";
export * from "./Emoji";
export * from "./Sticker";

View file

@ -1,84 +1,53 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2023 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import type { ComponentPropsWithRef, ComponentType, CSSProperties, FunctionComponent, HtmlHTMLAttributes, HTMLProps, JSX, KeyboardEvent, MouseEvent, PointerEvent, PropsWithChildren, PropsWithRef, ReactNode, Ref } from "react";
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";
export type FormTextTypes = Record<"DEFAULT" | "INPUT_PLACEHOLDER" | "DESCRIPTION" | "LABEL_BOLD" | "LABEL_SELECTED" | "LABEL_DESCRIPTOR" | "ERROR" | "SUCCESS", string>;
// #region Old compability
export type HeadingTag = `h${1 | 2 | 3 | 4 | 5 | 6}`;
export type Margins = Record<"marginTop16" | "marginTop8" | "marginBottom8" | "marginTop20" | "marginBottom20", string>;
// 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" | "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";
export type TextProps = PropsWithChildren<HtmlHTMLAttributes<HTMLDivElement> & {
variant?: TextVariant;
tag?: "div" | "span" | "p" | "strong" | HeadingTag;
selectable?: boolean;
lineClamp?: number;
}>;
export type Text = ComponentType<TextProps>;
export type Heading = ComponentType<TextProps>;
export type FormTitle = ComponentType<HTMLProps<HTMLTitleElement> & PropsWithChildren<{
/** default is h5 */
tag?: HeadingTag;
faded?: boolean;
disabled?: boolean;
required?: boolean;
error?: ReactNode;
}>>;
export interface ButtonProps extends PropsWithChildren<Omit<HTMLProps<HTMLButtonElement>, "size">> {
/** Button.Looks.FILLED */
look?: string;
/** Button.Colors.BRAND */
color?: string;
/** Button.Sizes.MEDIUM */
size?: string;
export type FormSection = ComponentType<PropsWithChildren<{
/** default is h5 */
tag?: HeadingTag;
className?: string;
titleClassName?: string;
titleId?: string;
title?: ReactNode;
disabled?: boolean;
htmlFor?: unknown;
}>>;
}
export type FormDivider = ComponentType<{
className?: string;
style?: CSSProperties;
}>;
export type Button = ComponentType<ButtonProps> & {
Colors: Record<"BRAND" | "RED" | "GREEN" | "PRIMARY" | "LINK" | "WHITE" | "TRANSPARENT" | "CUSTOM", string>;
Looks: Record<"FILLED" | "LINK", string>;
Sizes: Record<"NONE" | "SMALL" | "MEDIUM" | "LARGE" | "XLARGE" | "MIN", string>;
};
// #endregion
export type FormText = ComponentType<PropsWithChildren<{
disabled?: boolean;
selectable?: boolean;
/** defaults to FormText.Types.DEFAULT */
type?: string;
}> & TextProps> & { Types: FormTextTypes; };
export interface TooltipChildrenProps {
onClick(): void;
onMouseEnter(): void;
onMouseLeave(): void;
onContextMenu(): void;
onFocus(): void;
onBlur(): void;
"aria-label"?: string;
}
export type Tooltip = ComponentType<{
export interface TooltipProps {
text: ReactNode | ComponentType;
children: FunctionComponent<{
onClick(): void;
onMouseEnter(): void;
onMouseLeave(): void;
onContextMenu(): void;
onFocus(): void;
onBlur(): void;
"aria-label"?: string;
}>;
children: FunctionComponent<TooltipChildrenProps>;
"aria-label"?: string;
allowOverflow?: boolean;
@ -95,7 +64,9 @@ export type Tooltip = ComponentType<{
tooltipClassName?: string;
tooltipContentClassName?: string;
}> & {
}
export type Tooltip = ComponentType<TooltipProps> & {
Colors: Record<"BLACK" | "BRAND" | "CUSTOM" | "GREEN" | "GREY" | "PRIMARY" | "RED" | "YELLOW", string>;
};
@ -144,7 +115,6 @@ export type ComboboxPopout = ComponentType<PropsWithChildren<{
className?: string;
listClassName?: string;
autoFocus?: boolean;
multiSelect?: boolean;
maxVisibleItems?: number;
@ -152,51 +122,6 @@ export type ComboboxPopout = ComponentType<PropsWithChildren<{
}>>;
export interface ButtonProps extends PropsWithChildren<Omit<HTMLProps<HTMLButtonElement>, "size">> {
/** Button.Looks.FILLED */
look?: string;
/** Button.Colors.BRAND */
color?: string;
/** Button.Sizes.MEDIUM */
size?: string;
/** Button.BorderColors.BLACK */
borderColor?: string;
wrapperClassName?: string;
className?: string;
innerClassName?: string;
buttonRef?: Ref<HTMLButtonElement>;
focusProps?: any;
submitting?: boolean;
submittingStartedLabel?: string;
submittingFinishedLabel?: string;
}
export type Button = ComponentType<ButtonProps> & {
BorderColors: Record<"BLACK" | "BRAND" | "BRAND_NEW" | "GREEN" | "LINK" | "PRIMARY" | "RED" | "TRANSPARENT" | "WHITE" | "YELLOW", string>;
Colors: Record<"BRAND" | "RED" | "GREEN" | "YELLOW" | "PRIMARY" | "LINK" | "WHITE" | "BLACK" | "TRANSPARENT" | "BRAND_NEW" | "CUSTOM", string>;
Hovers: Record<"DEFAULT" | "BRAND" | "RED" | "GREEN" | "YELLOW" | "PRIMARY" | "LINK" | "WHITE" | "BLACK" | "TRANSPARENT", string>;
Looks: Record<"FILLED" | "INVERTED" | "OUTLINED" | "LINK" | "BLANK", string>;
Sizes: Record<"NONE" | "TINY" | "SMALL" | "MEDIUM" | "LARGE" | "XLARGE" | "MIN" | "MAX" | "ICON", string>;
Link: any;
};
export type Switch = ComponentType<PropsWithChildren<{
value: boolean;
onChange(value: boolean): void;
disabled?: boolean;
hideBorder?: boolean;
className?: string;
style?: CSSProperties;
note?: ReactNode;
tooltipNote?: ReactNode;
}>>;
export type CheckboxAligns = {
CENTER: "center";
TOP: "top";
@ -245,7 +170,8 @@ export type TextInput = ComponentType<PropsWithChildren<{
onChange?(value: string, name?: string): void;
placeholder?: string;
editable?: boolean;
maxLength?: number;
/** defaults to 999. Pass null to disable this default */
maxLength?: number | null;
error?: string;
inputClassName?: string;
@ -257,13 +183,15 @@ export type TextInput = ComponentType<PropsWithChildren<{
/** TextInput.Sizes.DEFAULT */
size?: string;
} & Omit<HTMLProps<HTMLInputElement>, "onChange">>> & {
} & Omit<HTMLProps<HTMLInputElement>, "onChange" | "maxLength">>> & {
Sizes: Record<"DEFAULT" | "MINI", string>;
};
export type TextArea = ComponentType<PropsWithRef<Omit<HTMLProps<HTMLTextAreaElement>, "onChange"> & {
// FIXME: this is wrong, it's not actually just HTMLTextAreaElement
export type TextArea = ComponentType<Omit<HTMLProps<HTMLTextAreaElement>, "onChange"> & {
onChange(v: string): void;
}>>;
inputRef?: Ref<HTMLTextAreaElement>;
}>;
interface SelectOption {
disabled?: boolean;
@ -315,7 +243,7 @@ export type Select = ComponentType<PropsWithChildren<{
export type SearchableSelect = ComponentType<PropsWithChildren<{
placeholder?: string;
options: ReadonlyArray<SelectOption>; // TODO
value?: SelectOption;
value?: any;
/**
* - 0 ~ Filled
@ -355,7 +283,7 @@ export type SearchableSelect = ComponentType<PropsWithChildren<{
"aria-labelledby"?: boolean;
}>>;
export type Slider = ComponentType<PropsWithChildren<{
export type Slider = ComponentClass<PropsWithChildren<{
initialValue: number;
defaultValue?: number;
keyboardStep?: number;
@ -393,14 +321,6 @@ export type Slider = ComponentType<PropsWithChildren<{
"aria-describedby"?: string;
}>>;
// TODO - type maybe idk probably not that useful other than the constants
export type Flex = ComponentType<PropsWithChildren<any>> & {
Align: Record<"START" | "END" | "CENTER" | "STRETCH" | "BASELINE", string>;
Direction: Record<"VERTICAL" | "HORIZONTAL" | "HORIZONTAL_REVERSE", string>;
Justify: Record<"START" | "END" | "CENTER" | "BETWEEN" | "AROUND", string>;
Wrap: Record<"NO_WRAP" | "WRAP" | "WRAP_REVERSE", string>;
};
declare enum PopoutAnimation {
NONE = "1",
TRANSLATE = "2",
@ -425,6 +345,7 @@ export type Popout = ComponentType<{
}
): ReactNode;
shouldShow?: boolean;
targetElementRef: RefObject<any>;
renderPopout(args: {
closePopout(): void;
isPositioned: boolean;
@ -488,19 +409,66 @@ export type MaskedLink = ComponentType<PropsWithChildren<{
channelId?: string;
}>>;
export type ScrollerThin = ComponentType<PropsWithChildren<{
export interface ScrollerBaseProps {
className?: string;
style?: CSSProperties;
dir?: "ltr";
orientation?: "horizontal" | "vertical" | "auto";
paddingFix?: boolean;
fade?: boolean;
onClose?(): void;
onScroll?(): void;
}
export type ScrollerThin = ComponentType<PropsWithChildren<ScrollerBaseProps & {
orientation?: "horizontal" | "vertical" | "auto";
fade?: boolean;
}>>;
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<ScrollerBaseProps & {
sections: number[];
renderSection?: (item: ListSection) => 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 = <T extends "a" | "div" | "span" | "li" = "div">(props: PropsWithChildren<ComponentPropsWithRef<T>> & {
tag?: T;
}) => ReactNode;
@ -534,3 +502,10 @@ export type Icon = ComponentType<JSX.IntrinsicElements["svg"] & {
colorClass?: string;
} & Record<string, any>>;
export type ColorPicker = ComponentType<{
color: number | null;
showEyeDropper?: boolean;
suggestedColors?: string[];
label?: ReactNode;
onChange(value: number | null): void;
}>;

30
packages/discord-types/src/flux.d.ts vendored Normal file
View file

@ -0,0 +1,30 @@
import { FluxStore } from "./stores/FluxStore";
export class FluxEmitter {
constructor();
changeSentinel: number;
changedStores: Set<FluxStore>;
isBatchEmitting: boolean;
isDispatching: boolean;
isPaused: boolean;
pauseTimer: NodeJS.Timeout | null;
reactChangedStores: Set<FluxStore>;
batched(batch: (...args: any[]) => void): void;
destroy(): void;
emit(): void;
emitNonReactOnce(): void;
emitReactOnce(): void;
getChangeSentinel(): number;
getIsPaused(): boolean;
injectBatchEmitChanges(batch: (...args: any[]) => void): void;
markChanged(store: FluxStore): void;
pause(): void;
resume(): void;
}
export interface Flux {
Store: typeof FluxStore;
Emitter: FluxEmitter;
}

File diff suppressed because one or more lines are too long

9
packages/discord-types/src/index.d.ts vendored Normal file
View file

@ -0,0 +1,9 @@
export * from "./common";
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";

View file

@ -1,22 +1,4 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2023 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import type { ComponentType, CSSProperties, MouseEvent, PropsWithChildren, ReactNode, UIEvent } from "react";
import type { ComponentType, CSSProperties, ForwardRefRenderFunction, MouseEvent, PropsWithChildren, ReactNode, UIEvent } from "react";
type RC<C> = ComponentType<PropsWithChildren<C & Record<string, any>>>;
@ -64,6 +46,8 @@ export interface Menu {
MenuControlItem: RC<{
id: string;
interactive?: boolean;
label?: string;
control: ForwardRefRenderFunction<any, any>;
}>;
MenuSliderControl: RC<{
minValue: number,
@ -73,7 +57,7 @@ export interface Menu {
renderValue?(value: number): string,
}>;
MenuSearchControl: RC<{
query: string
query: string;
onChange(query: string): void;
placeholder?: string;
}>;

View file

@ -0,0 +1,73 @@
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, 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;
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<void>;
cancel(): void;
delete(): Promise<void>;
getSize(): number;
maybeConvertToWebP(): Promise<void>;
removeFromMsgDraft(): void;
}

View file

@ -0,0 +1 @@
export * from "./CloudUpload";

View file

@ -0,0 +1,73 @@
import { FluxStore } from "..";
export type ReducedMotionPreference = "auto" | "reduce" | "no-preference";
export type ForcedColorsPreference = "none" | "active";
export type ContrastPreference = "no-preference" | "more" | "less" | "custom";
export type RoleStyle = "username" | "dot" | "hidden";
export interface AccessibilityState {
fontSize: number;
zoom: number;
keyboardModeEnabled: boolean;
contrastMode: string;
colorblindMode: boolean;
lowContrastMode: boolean;
saturation: number;
contrast: number;
desaturateUserColors: boolean;
forcedColorsModalSeen: boolean;
keyboardNavigationExplainerModalSeen: boolean;
messageGroupSpacing: number | null;
systemPrefersReducedMotion: ReducedMotionPreference;
systemPrefersCrossfades: boolean;
prefersReducedMotion: ReducedMotionPreference;
systemForcedColors: ForcedColorsPreference;
syncForcedColors: boolean;
systemPrefersContrast: ContrastPreference;
alwaysShowLinkDecorations: boolean;
roleStyle: RoleStyle;
displayNameStylesEnabled: boolean;
submitButtonEnabled: boolean;
syncProfileThemeWithUserTheme: boolean;
enableCustomCursor: boolean;
switchIconsEnabled: boolean;
}
export class AccessibilityStore extends FluxStore {
get fontScale(): number;
get fontSize(): number;
get isFontScaledUp(): boolean;
get isFontScaledDown(): boolean;
get fontScaleClass(): string;
get zoom(): number;
get isZoomedIn(): boolean;
get isZoomedOut(): boolean;
get keyboardModeEnabled(): boolean;
get colorblindMode(): boolean;
get lowContrastMode(): boolean;
get saturation(): number;
get contrast(): number;
get desaturateUserColors(): boolean;
get forcedColorsModalSeen(): boolean;
get keyboardNavigationExplainerModalSeen(): boolean;
get messageGroupSpacing(): number;
get isMessageGroupSpacingIncreased(): boolean;
get isMessageGroupSpacingDecreased(): boolean;
get isSubmitButtonEnabled(): boolean;
get syncProfileThemeWithUserTheme(): boolean;
get systemPrefersReducedMotion(): ReducedMotionPreference;
get rawPrefersReducedMotion(): ReducedMotionPreference;
get useReducedMotion(): boolean;
get systemForcedColors(): ForcedColorsPreference;
get syncForcedColors(): boolean;
get useForcedColors(): boolean;
get systemPrefersContrast(): ContrastPreference;
get systemPrefersCrossfades(): boolean;
get alwaysShowLinkDecorations(): boolean;
get enableCustomCursor(): boolean;
get roleStyle(): RoleStyle;
get displayNameStylesEnabled(): boolean;
get isHighContrastModeEnabled(): boolean;
get isSwitchIconsEnabled(): boolean;
getUserAgnosticState(): AccessibilityState;
}

View file

@ -0,0 +1,33 @@
import { Channel, FluxStore } from "..";
export interface ThreadJoined {
channel: Channel;
joinTimestamp: number;
}
export type ThreadsForParent = Record<string, ThreadJoined>;
export type ThreadsForGuild = Record<string, ThreadsForParent>;
export type AllActiveJoinedThreads = Record<string, ThreadsForGuild>;
export interface NewThreadCounts {
[parentChannelId: string]: number;
}
export class ActiveJoinedThreadsStore extends FluxStore {
computeAllActiveJoinedThreads(guildId?: string | null): Channel[];
getActiveJoinedRelevantThreadsForGuild(guildId: string): ThreadsForGuild;
getActiveJoinedRelevantThreadsForParent(guildId: string, parentChannelId: string): ThreadsForParent;
getActiveJoinedThreadsForGuild(guildId: string): ThreadsForGuild;
getActiveJoinedThreadsForParent(guildId: string, parentChannelId: string): ThreadsForParent;
getActiveJoinedUnreadThreadsForGuild(guildId: string): ThreadsForGuild;
getActiveJoinedUnreadThreadsForParent(guildId: string, parentChannelId: string): ThreadsForParent;
getActiveThreadCount(guildId: string, parentChannelId: string): number;
getActiveUnjoinedThreadsForGuild(guildId: string): ThreadsForGuild;
getActiveUnjoinedThreadsForParent(guildId: string, parentChannelId: string): ThreadsForParent;
getActiveUnjoinedUnreadThreadsForGuild(guildId: string): ThreadsForGuild;
getActiveUnjoinedUnreadThreadsForParent(guildId: string, parentChannelId: string): ThreadsForParent;
getAllActiveJoinedThreads(): AllActiveJoinedThreads;
getNewThreadCount(guildId: string, parentChannelId: string): number;
getNewThreadCountsForGuild(guildId: string): NewThreadCounts;
hasActiveJoinedUnreadThreads(guildId: string, parentChannelId: string): boolean;
}

View file

@ -0,0 +1,23 @@
import { Application, FluxStore } from "..";
export interface ApplicationStoreState {
botUserIdToAppUsage: Record<string, ApplicationUsage>;
}
export interface ApplicationUsage {
applicationId: string;
lastUsedMs: number;
}
export class ApplicationStore extends FluxStore {
getState(): ApplicationStoreState;
getApplication(applicationId: string): Application;
getApplicationByName(name: string): Application | undefined;
getApplicationLastUpdated(applicationId: string): number | undefined;
getGuildApplication(guildId: string, type: number): Application | undefined;
getGuildApplicationIds(guildId: string): string[];
getAppIdForBotUserId(botUserId: string): string | undefined;
getFetchingOrFailedFetchingIds(): string[];
isFetchingApplication(applicationId: string): boolean;
didFetchingApplicationFail(applicationId: string): boolean;
}

View file

@ -0,0 +1,11 @@
import { FluxStore } from "..";
export class AuthenticationStore extends FluxStore {
/**
* Gets the id of the current user
*/
getId(): string;
getSessionId(): string;
// This Store has a lot more methods related to everything Auth, but they really should
// not be needed, so they are not typed
}

View file

@ -0,0 +1,24 @@
import { FluxStore } from "..";
export interface Call {
channelId: string;
messageId: string | null;
region: string | null;
ringing: string[];
unavailable: boolean;
regionUpdated: boolean;
}
export interface CallStoreState {
calls: Record<string, Call>;
enqueuedRings: Record<string, string[]>;
}
export class CallStore extends FluxStore {
getCall(channelId: string): Call;
getCalls(): Call[];
getMessageId(channelId: string): string | null;
isCallActive(channelId: string, messageId?: string): boolean;
isCallUnavailable(channelId: string): boolean;
getInternalState(): CallStoreState;
}

View file

@ -0,0 +1,105 @@
import { FluxStore, User, VoiceState } from "..";
import { ParticipantType, RTCPlatform } from "../../enums";
export type RTCLayout = "normal" | "minimum" | "no-chat" | "full-screen" | "haven";
export type RTCMode = "video" | "voice";
export type RTCLayoutContext = "OVERLAY" | "APP" | "POPOUT" | "CALL_TILE_POPOUT";
export type ParticipantFilterType = "VIDEO" | "STREAM" | "FILTERED" | "SPEAKING" | "ACTIVITY" | "NOT_POPPED_OUT";
export interface StreamResolution {
height: number;
width: number;
}
export interface Stream {
channelId: string;
guildId: string | null;
ownerId: string;
streamType: string;
}
export interface BaseParticipant {
id: string;
type: ParticipantType;
isPoppedOut?: boolean;
}
export interface UserParticipant extends BaseParticipant {
type: ParticipantType.USER;
user: User;
voiceState: VoiceState | null;
voicePlatform: RTCPlatform | null;
speaking: boolean;
voiceDb: number;
latched: boolean;
lastSpoke: number;
soundsharing: boolean;
ringing: boolean;
userNick: string;
// TODO: type
userAvatarDecoration: any | null;
localVideoDisabled: boolean;
userVideo?: boolean;
streamId?: string;
}
export interface StreamParticipant extends BaseParticipant {
type: ParticipantType.STREAM | ParticipantType.HIDDEN_STREAM;
user: User;
userNick: string;
userVideo: boolean;
stream: Stream;
maxResolution?: StreamResolution;
maxFrameRate?: number;
streamId?: string;
}
export interface ActivityParticipant extends BaseParticipant {
type: ParticipantType.ACTIVITY;
applicationId: string;
activityType: number;
activityUrl: string;
participants: string[];
guildId: string | null;
sortKey: string;
}
export type Participant = UserParticipant | StreamParticipant | ActivityParticipant;
export interface SelectedParticipantStats {
view_mode_grid_duration_ms?: number;
view_mode_focus_duration_ms?: number;
view_mode_toggle_count?: number;
}
export interface ChannelRTCState {
voiceParticipantsHidden: Record<string, boolean>;
}
export class ChannelRTCStore extends FluxStore {
getActivityParticipants(channelId: string): ActivityParticipant[];
getAllChatOpen(): Record<string, boolean>;
getChatOpen(channelId: string): boolean;
getFilteredParticipants(channelId: string): Participant[];
getGuildRingingUsers(channelId: string): Set<string>;
getLayout(channelId: string, context?: RTCLayoutContext): RTCLayout;
getMode(channelId: string): RTCMode;
getParticipant(channelId: string, participantId: string): Participant | null;
getParticipants(channelId: string): Participant[];
getParticipantsListOpen(channelId: string): boolean;
getParticipantsOpen(channelId: string): boolean;
getParticipantsVersion(channelId: string): number;
getSelectedParticipant(channelId: string): Participant | null;
getSelectedParticipantId(channelId: string): string | null;
getSelectedParticipantStats(channelId: string): SelectedParticipantStats;
getSpeakingParticipants(channelId: string): UserParticipant[];
getStageStreamSize(channelId: string): StreamResolution | undefined;
getStageVideoLimitBoostUpsellDismissed(channelId: string): boolean | undefined;
getState(): ChannelRTCState;
getStreamParticipants(channelId: string): StreamParticipant[];
getUserParticipantCount(channelId: string): number;
getVideoParticipants(channelId: string): UserParticipant[];
getVoiceParticipantsHidden(channelId: string): boolean;
isFullscreenInContext(): boolean;
isParticipantPoppedOut(channelId: string, participantId: string): boolean;
}

View file

@ -0,0 +1,31 @@
import { Channel, FluxStore } from "..";
export class ChannelStore extends FluxStore {
getChannel(channelId: string): Channel;
getBasicChannel(channelId: string): Channel | undefined;
hasChannel(channelId: string): boolean;
getChannelIds(guildId?: string | null): string[];
getMutableBasicGuildChannelsForGuild(guildId: string): Record<string, Channel>;
getMutableGuildChannelsForGuild(guildId: string): Record<string, Channel>;
getAllThreadsForGuild(guildId: string): Channel[];
getAllThreadsForParent(channelId: string): Channel[];
getSortedLinkedChannelsForGuild(guildId: string): Channel[];
getDMFromUserId(userId: string): string;
getDMChannelFromUserId(userId: string): Channel | undefined;
getDMUserIds(): string[];
getMutableDMsByUserIds(): Record<string, string>;
getMutablePrivateChannels(): Record<string, Channel>;
getSortedPrivateChannels(): Channel[];
getGuildChannelsVersion(guildId: string): number;
getPrivateChannelsVersion(): number;
getInitialOverlayState(): Record<string, Channel>;
getDebugInfo(): {
loadedGuildIds: string[];
pendingGuildLoads: string[];
guildSizes: string[];
};
}

View file

@ -0,0 +1,34 @@
import { FluxStore } from "..";
import { DraftType } from "../../enums";
export interface Draft {
timestamp: number;
draft: string;
}
export interface ThreadSettingsDraft {
timestamp: number;
parentMessageId?: string;
name?: string;
isPrivate?: boolean;
parentChannelId?: string;
location?: string;
}
export type ChannelDrafts = {
[DraftType.ThreadSettings]: ThreadSettingsDraft;
} & {
[key in Exclude<DraftType, DraftType.ThreadSettings>]: Draft;
};
export type UserDrafts = Partial<Record<string, ChannelDrafts>>;
export type DraftState = Partial<Record<string, UserDrafts>>;
export class DraftStore extends FluxStore {
getState(): DraftState;
getRecentlyEditedDrafts(type: DraftType): Array<Draft & { channelId: string; }>;
getDraft(channelId: string, type: DraftType): string;
getThreadSettings(channelId: string): ThreadSettingsDraft | null | undefined;
getThreadDraftWithParentMessageId(parentMessageId: string): ThreadSettingsDraft | null | undefined;
}

View file

@ -0,0 +1,467 @@
import { Channel, CustomEmoji, Emoji, FluxStore } from "..";
import { EmojiIntention, LoadState } from "../../enums";
/** Emoji picker category names. */
export type EmojiCategory =
| "top guild emoji"
| "favorites"
| "recent"
| "custom"
| "people"
| "nature"
| "food"
| "activity"
| "travel"
| "objects"
| "symbols"
| "flags";
/**
* Tracks usage statistics for a single emoji to compute frecency scores.
*/
export interface EmojiUsageRecord {
/** Total number of times this emoji has been used. */
totalUses: number;
/** Array of recent usage timestamps in milliseconds. */
recentUses: number[];
/** Computed frecency score combining frequency and recency, -1 when dirty. */
frecency: number;
/** Raw score before frecency computation. */
score: number;
}
/**
* Options for tracking emoji usage.
*/
export interface TrackOptions {
/** Timestamp of the usage in milliseconds. */
timestamp?: number;
/** Number of uses since last track call. */
usesSinceLastTrack?: number;
}
/**
* Frecency tracker for emoji usage, combines frequency and recency to rank emojis.
* Used by both regular emoji picker and reaction emoji picker.
*/
export interface EmojiFrecency {
/** True when data has been modified and needs recomputation. */
dirty: boolean;
/** Cached array of frequently used emojis after computation. */
_frequently: Emoji[];
/** Maximum number of frequently used items to track (default 42). */
numFrequentlyItems: number;
/** Maximum number of recent usage samples to keep per emoji (default 10). */
maxSamples: number;
/** Computes bonus score for frecency calculation (returns 100). */
computeBonus: () => number;
/**
* Computes weight multiplier based on recency index.
* Returns 100 for index <= 3, 70 for <= 15, 50 for <= 30, 30 for <= 45, 10 for <= 80.
*/
computeWeight: (index: number) => number;
/**
* Computes frecency score for an emoji.
* @param totalUses Total number of times emoji was used.
* @param score Raw score value.
* @param config Configuration for frecency calculation.
*/
computeFrecency: (totalUses: number, score: number, config: {
/** Number of recent uses to consider. */
numOfRecentUses?: number;
/** Maximum total uses to cap at. */
maxTotalUse?: number;
}) => number;
/** Whether to calculate max total use dynamically. */
calculateMaxTotalUse: boolean;
/**
* Looks up an emoji by name or id.
* @param name Emoji name or id to look up.
* @returns The emoji if found.
*/
lookupKey: (name: string) => Emoji | undefined;
/** Usage history keyed by emoji name (for unicode) or id (for custom). */
usageHistory: Record<string, EmojiUsageRecord>;
/** Callback invoked after frecency computation completes. */
afterCompute: () => void;
/**
* Overwrites the usage history with new data.
* @param history New usage history to set.
* @param pendingUsages Pending usages to track after overwriting.
*/
overwriteHistory(history: Record<string, EmojiUsageRecord> | null, pendingUsages?: PendingUsage[]): void;
/** Marks the frecency data as dirty, requiring recomputation. */
markDirty(): void;
/** Returns whether the frecency data needs recomputation. */
isDirty(): boolean;
/**
* Tracks usage of an emoji.
* @param key Emoji name or id.
* @param options Track options including timestamp.
*/
track(key: string, options?: TrackOptions): void;
/**
* Gets the usage record for an emoji, computing if dirty.
* @param key Emoji name or id.
* @returns The usage record or null if not found.
*/
getEntry(key: string): EmojiUsageRecord | null;
/**
* Gets the score for an emoji.
* @param key Emoji name or id.
* @returns The score or null if not found.
*/
getScore(key: string): number | null;
/**
* Gets the frecency for an emoji.
* @param key Emoji name or id.
* @returns The frecency or null if not found.
*/
getFrecency(key: string): number | null;
/** Recomputes frecency scores for all emojis. */
compute(): void;
/** Gets the frequently used emojis, computing if necessary. */
get frequently(): Emoji[];
}
/**
* Container for a guild's emoji collection with usability checks.
*/
export interface GuildEmojis {
/** Guild id this emoji collection belongs to. */
id: string;
/** User id for permission checks. */
_userId: string;
/** Internal emoji array. */
_emojis: CustomEmoji[];
/** Fast lookup map of emoji id to emoji. */
_emojiMap: Record<string, CustomEmoji>;
/** Internal emoticons array. */
_emoticons: Emoticon[];
/** Internal usable emojis cache. */
_usableEmojis: CustomEmoji[];
/** Whether user can see server subscription IAP. */
_canSeeServerSubIAP: boolean;
/** All custom emojis in this guild. */
get emojis(): CustomEmoji[];
/** Custom emojis the current user can use in this guild. */
get usableEmojis(): CustomEmoji[];
/** Text emoticons configured for this guild. */
get emoticons(): Emoticon[];
/**
* Gets an emoji by id from this guild.
* @param id Emoji id to look up.
*/
getEmoji(id: string): CustomEmoji | undefined;
/**
* Gets a usable emoji by id from this guild.
* @param id Emoji id to look up.
*/
getUsableEmoji(id: string): CustomEmoji | undefined;
/**
* Checks if an emoji is usable by the current user.
* @param emoji Emoji to check.
*/
isUsable(emoji: CustomEmoji): boolean;
/** Returns array of all emoji ids in this guild. */
emojiIds(): string[];
}
/**
* Text emoticon that can be converted to emoji.
*/
export interface Emoticon {
/** Names/aliases for this emoticon. */
names: string[];
/** The text representation (e.g. ":)" or ":D"). */
surrogates: string;
/** Whether this emoticon should use sprite sheet rendering. */
useSpriteSheet: boolean;
}
/**
* Pending emoji usage waiting to be recorded.
*/
export interface PendingUsage {
/** Emoji key (name for unicode, id for custom). */
key: string;
/** Timestamp in milliseconds when usage occurred. */
timestamp: number;
}
/**
* Serializable state for EmojiStore persistence.
*/
export interface EmojiStoreState {
/** Pending emoji usages not yet committed. */
pendingUsages: PendingUsage[];
/** Pending reaction emoji usages not yet committed. */
emojiReactionPendingUsages: PendingUsage[];
/** Guild ids with expanded emoji sections in picker. */
expandedSectionsByGuildIds: Set<string>;
}
/**
* Context for emoji disambiguation, caching resolved emoji data for a guild context.
* Provides fast lookup of emojis without triggering data fetches.
*/
export interface DisambiguatedEmojiContext {
/** User's favorite emojis or null if not loaded. */
favorites: Emoji[] | null;
/** Set of favorite emoji names and ids for fast lookup, or null if not loaded. */
favoriteNamesAndIds: Set<string> | null;
/** Top emojis for the current guild or null if not loaded. */
topEmojis: Emoji[] | null;
/** Current guild id context or null for DMs. */
guildId: string | null;
/** Regex-escaped emoticon names for matching. */
escapedEmoticonNames: string;
/** All emojis with disambiguation applied (unique names). */
disambiguatedEmoji: Emoji[];
/** Compiled regex for matching emoticons or null if none. */
emoticonRegex: RegExp | null;
/** Frequently used emojis or null if not loaded. */
frequentlyUsed: Emoji[] | null;
/** Frequently used reaction emojis or null if not loaded. */
frequentlyUsedReactionEmojis: Emoji[] | null;
/** Set of frequently used reaction emoji names and ids, or null if not loaded. */
frequentlyUsedReactionNamesAndIds: Set<string> | null;
/** Unicode emoji aliases keyed by alias name, maps to primary name. */
unicodeAliases: Record<string, string>;
/** Custom emojis keyed by emoji id. */
customEmojis: Record<string, CustomEmoji>;
/** Custom emojis grouped by guild id. */
groupedCustomEmojis: Record<string, CustomEmoji[]>;
/** Emoticons keyed by name for fast lookup. */
emoticonsByName: Record<string, Emoticon>;
/** All emojis keyed by name for fast lookup. */
emojisByName: Record<string, Emoji>;
/** Custom emojis keyed by id for fast lookup. */
emojisById: Record<string, CustomEmoji>;
/** Newly added emojis grouped by guild id. */
newlyAddedEmoji: Record<string, CustomEmoji[]>;
/**
* Checks if an emoji is a favorite without triggering a fetch.
* @param emoji Emoji to check.
*/
isFavoriteEmojiWithoutFetchingLatest(emoji: Emoji): boolean;
/** Gets favorite emojis without triggering a fetch. */
get favoriteEmojisWithoutFetchingLatest(): Emoji[];
/** Gets all disambiguated emojis. */
getDisambiguatedEmoji(): Emoji[];
/** Gets all custom emojis keyed by name. */
getCustomEmoji(): Record<string, CustomEmoji>;
/** Gets custom emojis grouped by guild id. */
getGroupedCustomEmoji(): Record<string, CustomEmoji[]>;
/**
* Gets an emoji by name.
* @param name Emoji name to look up.
*/
getByName(name: string): Emoji | undefined;
/**
* Gets an emoticon by name.
* @param name Emoticon name to look up.
*/
getEmoticonByName(name: string): Emoticon | undefined;
/**
* Gets an emoji by id.
* @param id Emoji id to look up.
*/
getById(id: string): Emoji | undefined;
/**
* Gets the regex for matching custom emoticons.
* @returns RegExp or null if no emoticons.
*/
getCustomEmoticonRegex(): RegExp | null;
/** Gets frequently used emojis without triggering a fetch. */
getFrequentlyUsedEmojisWithoutFetchingLatest(): Emoji[];
/** Rebuilds the frequently used reaction emojis cache and returns it. */
rebuildFrequentlyUsedReactionsEmojisWithoutFetchingLatest(): {
frequentlyUsedReactionEmojis: Emoji[];
frequentlyUsedReactionNamesAndIds: Set<string>;
};
/** Gets frequently used reaction emojis without triggering a fetch. */
getFrequentlyUsedReactionEmojisWithoutFetchingLatest(): Emoji[];
/**
* Checks if an emoji is frequently used for reactions.
* @param emoji Emoji to check.
*/
isFrequentlyUsedReactionEmojiWithoutFetchingLatest(emoji: Emoji): boolean;
/** Rebuilds the favorite emojis cache and returns it. */
rebuildFavoriteEmojisWithoutFetchingLatest(): {
favorites: Emoji[];
favoriteNamesAndIds: Set<string>;
};
/**
* Gets emojis in priority order (favorites, frequent, top) without fetching.
* @returns Array of emojis in priority order.
*/
getEmojiInPriorityOrderWithoutFetchingLatest(): Emoji[];
/**
* Gets top emojis for a guild without triggering a fetch.
* @param guildId Guild id to get top emojis for.
*/
getTopEmojiWithoutFetchingLatest(guildId: string): Emoji[];
/**
* Gets newly added emojis for a specific guild.
* @param guildId Guild id.
*/
getNewlyAddedEmojiForGuild(guildId: string): CustomEmoji[];
/** Gets escaped custom emoticon names for regex matching. */
getEscapedCustomEmoticonNames(): string;
/**
* Checks if a name matches an emoji name chain.
* @param name Name to match.
*/
nameMatchesChain(name: string): boolean;
}
/**
* Search options for emoji search.
*/
export interface EmojiSearchOptions {
/** Channel context for permission checks. */
channel: Channel;
/** Search query string. */
query: string;
/** Maximum number of results to return. */
count?: number;
/** Intention for using the emoji, affects availability filtering. */
intention: EmojiIntention;
/** Whether to include emojis from guilds the user is not in. */
includeExternalGuilds?: boolean;
/** Whether to only show unicode emojis in results. */
showOnlyUnicode?: boolean;
/**
* Custom comparator for matching emoji names.
* @param name Emoji name to compare.
* @returns True if the name matches.
*/
matchComparator?(name: string): boolean;
}
/**
* Search results split by availability.
*/
export interface EmojiSearchResults {
/** Emojis that are locked (require Nitro or permissions). */
locked: Emoji[];
/** Emojis that are available for use. */
unlocked: Emoji[];
}
/**
* Metadata about top emojis for a guild.
*/
export interface TopEmojisMetadata {
/** Array of top emoji ids. */
emojiIds: string[];
/** Time-to-live for this data in milliseconds. */
topEmojisTTL: number;
}
/**
* Flux store managing all emoji data including custom guild emojis,
* unicode emojis, favorites, frecency, and search functionality.
*/
export class EmojiStore extends FluxStore {
/** Array of emoji category names for the picker. */
get categories(): EmojiCategory[];
/**
* Current skin tone modifier surrogate for emoji diversity.
* Empty string for default yellow, or skin tone modifier (🏻🏼🏽🏾🏿).
*/
get diversitySurrogate(): string;
/** Frecency tracker for emoji picker usage. */
get emojiFrecencyWithoutFetchingLatest(): EmojiFrecency;
/** Frecency tracker for reaction emoji usage. */
get emojiReactionFrecencyWithoutFetchingLatest(): EmojiFrecency;
/** Guild ids with expanded emoji sections in picker. */
get expandedSectionsByGuildIds(): Set<string>;
/** Current load state of the emoji store. */
get loadState(): LoadState;
/**
* Gets a custom emoji by its id.
* @param id Emoji id to look up.
* @returns The custom emoji if found.
*/
getCustomEmojiById(id?: string | null): CustomEmoji | undefined;
/**
* Gets a usable custom emoji by its id.
* @param id Emoji id to look up.
* @returns The custom emoji if found and usable by current user.
*/
getUsableCustomEmojiById(id?: string | null): CustomEmoji | undefined;
/**
* Gets all guild emoji collections keyed by guild id.
* @returns Record of guild id to GuildEmojis.
*/
getGuilds(): Record<string, GuildEmojis>;
/**
* Gets all custom emojis for a guild.
* @param guildId Guild id to get emojis for, or null for all guilds.
* @returns Array of custom emojis.
*/
getGuildEmoji(guildId?: string | null): CustomEmoji[];
/**
* Gets usable custom emojis for a guild.
* @param guildId Guild id to get emojis for.
* @returns Array of usable custom emojis.
*/
getUsableGuildEmoji(guildId?: string | null): CustomEmoji[];
/**
* Gets newly added emojis for a guild.
* @param guildId Guild id to get emojis for.
* @returns Array of newly added custom emojis.
*/
getNewlyAddedEmoji(guildId?: string | null): CustomEmoji[];
/**
* Gets top emojis for a guild based on usage.
* @param guildId Guild id to get emojis for.
* @returns Array of top custom emojis.
*/
getTopEmoji(guildId?: string | null): CustomEmoji[];
/**
* Gets metadata about top emojis for a guild.
* @param guildId Guild id to get metadata for.
* @returns Metadata including emoji ids and TTL, or undefined if not cached.
*/
getTopEmojisMetadata(guildId?: string | null): TopEmojisMetadata | undefined;
/**
* Checks if user has any favorite emojis in a guild context.
* @param guildId Guild id to check.
* @returns True if user has favorites.
*/
hasFavoriteEmojis(guildId?: string | null): boolean;
/**
* Checks if there are pending emoji usages to be recorded.
* @returns True if there are pending usages.
*/
hasPendingUsage(): boolean;
/**
* Checks if user has any usable custom emojis in any guild.
* @returns True if user has usable emojis.
*/
hasUsableEmojiInAnyGuild(): boolean;
/** Internal method for ordering search results. */
getSearchResultsOrder(...args: any[]): any;
/**
* Gets the serializable state for persistence.
* @returns Current store state.
*/
getState(): EmojiStoreState;
/**
* Searches for emojis without triggering data fetches.
* @param options Search options including query and filters.
* @returns Search results split by locked/unlocked.
*/
searchWithoutFetchingLatest(options: EmojiSearchOptions): EmojiSearchResults;
/**
* Gets the disambiguated emoji context for a guild.
* @param guildId Guild id to get context for, or null/undefined for global context.
*/
getDisambiguatedEmojiContext(guildId?: string | null): DisambiguatedEmojiContext;
}

View file

@ -0,0 +1,89 @@
import { FluxDispatcher, FluxEvents } from "..";
type Callback = () => void;
type SyncCallback = () => boolean | 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;
/** keyed by FluxEvents action type */
export type ActionHandlers = Partial<Record<FluxEvents, ActionHandler>>;
/**
* Base class for all Discord Flux stores.
* Provides change notification, action handling, and store synchronization.
*/
export class FluxStore {
/**
* @param dispatcher the FluxDispatcher instance to register with
* @param actionHandlers handlers for Flux actions, keyed by action type
* @param band priority band for action handling (default 2), lower runs first
*/
constructor(dispatcher: FluxDispatcher, actionHandlers?: ActionHandlers, band?: number);
/** returns displayName if set, otherwise constructor.name */
getName(): string;
/** adds listener to _changeCallbacks, invoked before react listeners and triggers syncWith processing */
addChangeListener(callback: Callback): void;
/**
* adds a listener that auto-removes when callback returns false.
* @param callback returning false removes the listener
* @param preemptive if true (default), calls callback immediately and skips adding if it returns false
*/
addConditionalChangeListener(callback: () => boolean, preemptive?: boolean): void;
/** adds listener to _reactChangeCallbacks, invoked after all regular change listeners complete */
addReactChangeListener(callback: Callback): void;
removeChangeListener(callback: Callback): void;
removeReactChangeListener(callback: Callback): void;
/** called by dispatcher after action handlers run, marks changed if listeners exist and may resume paused dispatch */
doEmitChanges(event: FluxEvent): void;
/** marks store as changed for batched listener notification */
emitChange(): void;
/** unique token identifying this store in the dispatcher */
getDispatchToken(): string;
/** override to set up initial state, called once by initializeIfNeeded */
initialize(): void;
/** calls initialize() if not already initialized, adds performance mark if init takes >5ms */
initializeIfNeeded(): void;
/**
* sets callback to determine if changes must emit during paused dispatch.
* @param callback if omitted, defaults to () => true (always emit)
*/
mustEmitChanges(callback?: ActionHandler): void;
/**
* registers additional action handlers after construction.
* @param actionHandlers handlers keyed by action type
* @param band priority band, lower runs first
*/
registerActionHandlers(actionHandlers: ActionHandlers, band?: number): void;
/**
* syncs this store with other stores, re-emitting when they change.
* without timeout: synchronous, callback runs during emitNonReactOnce.
* with timeout: debounced, adds regular change listener to each source store.
* @param stores stores to sync with
* @param callback returning false skips emitChange on this store
* @param timeout if provided, debounces the sync callback
*/
syncWith(stores: FluxStore[], callback: SyncCallback, timeout?: number): void;
/** adds dispatcher dependencies so this store's handlers run after the specified stores */
waitFor(...stores: FluxStore[]): void;
/** initializes all registered stores, called once at app startup */
static initialize(): void;
/** clears all registered stores and destroys the change listener system */
static destroy(): void;
/** returns all registered FluxStore instances */
static getAll(): FluxStore[];
}

View file

@ -0,0 +1,67 @@
import { Activity, FluxStore, Guild, User } from "..";
import { GiftIntentType, RelationshipType } from "../../enums";
export type FriendsSection = "ADD_FRIEND" | "ALL" | "ONLINE" | "PENDING" | "PENDING_IGNORED" | "SPAM" | "SUGGESTIONS";
export type StatusType = "online" | "offline" | "idle" | "dnd" | "invisible" | "streaming" | "unknown";
export interface ApplicationStream {
channelId: string;
guildId: string | null;
ownerId: string;
streamType: string;
}
export interface FriendsRow {
key: string;
userId: string;
/**
* 99 means contact based friend suggestions from FriendSuggestionStore,
* shown in SUGGESTIONS tab. different from RelationshipType.SUGGESTION
* which is for implicit suggestions in RelationshipStore
*/
type: RelationshipType | 99;
status: StatusType;
isMobile: boolean;
activities: Activity[];
applicationStream: ApplicationStream | null;
user: User | null;
usernameLower: string | null;
mutualGuildsLength: number;
mutualGuilds: Guild[];
nickname: string | null;
spam: boolean;
giftIntentType: GiftIntentType | undefined;
ignoredUser: boolean;
applicationId: string | undefined;
isGameRelationship: boolean;
comparator: [RelationshipType | 99, string | null];
}
export interface RelationshipCounts {
[RelationshipType.FRIEND]: number;
[RelationshipType.INCOMING_REQUEST]: number;
[RelationshipType.OUTGOING_REQUEST]: number;
[RelationshipType.BLOCKED]: number;
/** contact based friend suggestions from FriendSuggestionStore */
99: number;
}
export interface FriendsRows {
_rows: FriendsRow[];
reset(): FriendsRows;
clone(): FriendsRows;
update(updater: (userId: string) => Partial<FriendsRow>): boolean;
filter(section: FriendsSection, searchQuery?: string | null): FriendsRow[];
getRelationshipCounts(): RelationshipCounts;
}
export interface FriendsState {
fetching: boolean;
section: FriendsSection;
rows: FriendsRows;
}
export class FriendsStore extends FluxStore {
getState(): FriendsState;
}

View file

@ -0,0 +1,46 @@
import { Channel, FluxStore, ThreadJoined } from "..";
import { ChannelType } from "../../enums";
export interface ChannelWithComparator {
channel: Channel;
comparator: number;
}
export interface GuildChannels {
[ChannelType.GUILD_CATEGORY]: ChannelWithComparator[];
id: string;
SELECTABLE: ChannelWithComparator[] | ThreadJoined[];
VOCAL: ChannelWithComparator[];
count: number;
}
export interface ChannelNameDisambiguation {
id: string;
name: string;
}
export class GuildChannelStore extends FluxStore {
getAllGuilds(): Record<string, GuildChannels>;
getChannels(guildId: string): GuildChannels;
getDefaultChannel(guildId: string): Channel | null;
getDirectoryChannelIds(guildId: string): string[];
getFirstChannel(
guildId: string,
predicate: (item: ChannelWithComparator) => boolean,
includeVocal?: boolean
): Channel | null;
getFirstChannelOfType(
guildId: string,
predicate: (item: ChannelWithComparator) => boolean,
type: "SELECTABLE" | "VOCAL" | ChannelType.GUILD_CATEGORY
): Channel | null;
getSFWDefaultChannel(guildId: string): Channel | null;
getSelectableChannelIds(guildId: string): string[];
getSelectableChannels(guildId: string): ChannelWithComparator[];
getTextChannelNameDisambiguations(guildId: string): Record<string, ChannelNameDisambiguation>;
getVocalChannelIds(guildId: string): string[];
hasCategories(guildId: string): boolean;
hasChannels(guildId: string): boolean;
hasElevatedPermissions(guildId: string): boolean;
hasSelectableChannel(guildId: string, channelId: string): boolean;
}

View file

@ -0,0 +1,7 @@
import { FluxStore } from "..";
export class GuildMemberCountStore extends FluxStore {
getMemberCounts(): Record<string, number>;
getMemberCount(guildId: string): number;
getOnlineCount(guildId: string): number;
}

View file

@ -0,0 +1,35 @@
import { FluxStore, GuildMember } from "..";
export interface PendingRoleUpdates {
added: string[];
removed: string[];
}
export class GuildMemberStore extends FluxStore {
/** @returns Format: [guildId-userId: Timestamp (string)] */
getCommunicationDisabledUserMap(): Record<string, string>;
getCommunicationDisabledVersion(): number;
getMutableAllGuildsAndMembers(): Record<string, Record<string, GuildMember>>;
getMember(guildId: string, userId: string): GuildMember | null;
getTrueMember(guildId: string, userId: string): GuildMember | null;
getMemberIds(guildId: string): string[];
getMembers(guildId: string): GuildMember[];
getMemberVersion(): number;
getMemberRoleWithPendingUpdates(guildId: string, userId: string): string[];
getPendingRoleUpdates(guildId: string): PendingRoleUpdates;
memberOf(userId: string): string[];
getCachedSelfMember(guildId: string): GuildMember | null;
getSelfMember(guildId: string): GuildMember | null;
getSelfMemberJoinedAt(guildId: string): Date | null;
getNick(guildId: string, userId: string): string | null;
getNicknameGuildsMapping(userId: string): Record<string, string[]>;
getNicknames(userId: string): string[];
isMember(guildId: string, userId: string): boolean;
isGuestOrLurker(guildId: string, userId: string): boolean;
isCurrentUserGuest(guildId: string): boolean;
}

View file

@ -0,0 +1,13 @@
import { FluxStore, Guild, Role } from "..";
export class GuildRoleStore extends FluxStore {
getRolesSnapshot(guildId: string): Record<string, Role>;
getSortedRoles(guildId: string): Role[];
getEveryoneRole(guild: Guild): Role;
getManyRoles(guildId: string, roleIds: string[]): Role[];
getNumRoles(guildId: string): number;
getRole(guildId: string, roleId: string): Role;
getUnsafeMutableRoles(guildId: string): Record<string, Role>;
serializeAllGuildRoles(): Array<{ partitionKey: string; values: Record<string, Role>; }>;
}

View file

@ -0,0 +1,67 @@
import { FluxStore } from "..";
import { GuildScheduledEventEntityType, GuildScheduledEventPrivacyLevel, GuildScheduledEventStatus } from "../../enums";
export interface GuildScheduledEventEntityMetadata {
location?: string;
}
export interface GuildScheduledEventRecurrenceRule {
start: string;
end: string | null;
frequency: number;
interval: number;
byWeekday: number[] | null;
byNWeekday: { n: number; day: number; }[] | null;
byMonth: number[] | null;
byMonthDay: number[] | null;
byYearDay: number[] | null;
count: number | null;
}
export interface GuildScheduledEvent {
id: string;
guild_id: string;
channel_id: string | null;
creator_id: string | null;
name: string;
description: string | null;
image: string | null;
scheduled_start_time: string;
scheduled_end_time: string | null;
privacy_level: GuildScheduledEventPrivacyLevel;
status: GuildScheduledEventStatus;
entity_type: GuildScheduledEventEntityType;
entity_id: string | null;
entity_metadata: GuildScheduledEventEntityMetadata | null;
sku_ids: string[];
recurrence_rule: GuildScheduledEventRecurrenceRule | null;
// TODO: type
guild_scheduled_event_exceptions: any[];
auto_start: boolean;
}
export interface GuildScheduledEventRsvp {
guildScheduledEventId: string;
userId: string;
interested: boolean;
}
export interface GuildScheduledEventUsers {
// TODO: finish typing
[userId: string]: any;
}
export class GuildScheduledEventStore extends FluxStore {
getGuildScheduledEvent(eventId: string): GuildScheduledEvent | null;
getGuildScheduledEventsForGuild(guildId: string): GuildScheduledEvent[];
getGuildScheduledEventsByIndex(status: GuildScheduledEventStatus): GuildScheduledEvent[];
getGuildEventCountByIndex(status: GuildScheduledEventStatus): number;
getRsvpVersion(): number;
getRsvp(eventId: string, recurrenceId: string | null, userId: string | null): GuildScheduledEventRsvp | null;
isInterestedInEventRecurrence(eventId: string, recurrenceId: string | null): boolean;
getUserCount(eventId: string, recurrenceId: string | null): number;
hasUserCount(eventId: string, recurrenceId: string | null): boolean;
isActive(eventId: string): boolean;
getActiveEventByChannel(channelId: string): GuildScheduledEvent | null;
getUsersForGuildEvent(eventId: string, recurrenceId: string | null): GuildScheduledEventUsers;
}

View file

@ -0,0 +1,9 @@
import { Guild, FluxStore } from "..";
export class GuildStore extends FluxStore {
getGuild(guildId: string): Guild;
getGuildCount(): number;
getGuilds(): Record<string, Guild>;
getGuildsArray(): Guild[];
getGuildIds(): string[];
}

View file

@ -0,0 +1,17 @@
import { FluxStore } from "..";
import { Invite } from "./InviteStore";
export interface FriendInvite extends Invite {
max_age: number;
max_uses: number;
uses: number;
created_at: string;
revoked?: boolean;
}
export class InstantInviteStore extends FluxStore {
getInvite(channelId: string): Invite;
getFriendInvite(): FriendInvite | null;
getFriendInvitesFetching(): boolean;
canRevokeFriendInvite(): boolean;
}

View file

@ -0,0 +1,27 @@
import { Channel, FluxStore, Guild, User } from "..";
export interface Invite {
code: string;
guild: Guild | null;
channel: Channel | null;
inviter: User | null;
approximate_member_count?: number;
approximate_presence_count?: number;
expires_at?: string | null;
flags?: number;
target_type?: number;
target_user?: User;
// TODO: type these
target_application?: any;
stage_instance?: any;
guild_scheduled_event?: any;
}
export class InviteStore extends FluxStore {
getInvite(code: string): Invite;
// TODO: finish typing
getInviteError(code: string): any | undefined;
getInvites(): Record<string, Invite>;
getInviteKeyForGuildId(guildId: string): string | undefined;
getFriendMemberIds(code: string): string[] | undefined;
}

View file

@ -0,0 +1,6 @@
import { FluxStore } from "..";
export class LocaleStore extends FluxStore {
get locale(): string;
get systemLocale(): string;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,55 @@
import { FluxStore, Message } from "..";
export type JumpType = "ANIMATED" | "INSTANT";
export interface MessageCache {
_messages: Message[];
_map: Record<string, Message>;
_wasAtEdge: boolean;
_isCacheBefore: boolean;
}
export interface ChannelMessages {
channelId: string;
ready: boolean;
cached: boolean;
jumpType: JumpType;
jumpTargetId: string | null;
jumpTargetOffset: number;
jumpSequenceId: number;
jumped: boolean;
jumpedToPresent: boolean;
jumpFlash: boolean;
jumpReturnTargetId: string | null;
focusTargetId: string | null;
focusSequenceId: number;
initialScrollSequenceId: number;
hasMoreBefore: boolean;
hasMoreAfter: boolean;
loadingMore: boolean;
revealedMessageId: string | null;
hasFetched: boolean;
error: boolean;
_array: Message[];
_before: MessageCache;
_after: MessageCache;
_map: Record<string, Message>;
}
export class MessageStore extends FluxStore {
focusedMessageId(channelId: string): string | undefined;
getLastChatCommandMessage(channelId: string): Message | undefined;
getLastEditableMessage(channelId: string): Message | undefined;
getLastMessage(channelId: string): Message | undefined;
getLastNonCurrentUserMessage(channelId: string): Message | undefined;
getMessage(channelId: string, messageId: string): Message;
/** @see {@link ChannelMessages} */
getMessages(channelId: string): ChannelMessages;
hasCurrentUserSentMessage(channelId: string): boolean;
hasCurrentUserSentMessageSinceAppStart(channelId: string): boolean;
hasPresent(channelId: string): boolean;
isLoadingMessages(channelId: string): boolean;
isReady(channelId: string): boolean;
jumpedMessageId(channelId: string): string | undefined;
whenReady(channelId: string, callback: () => void): void;
}

View file

@ -0,0 +1,26 @@
import { FluxStore } from "..";
export type DesktopNotificationType = "ALL" | "ONLY_MENTIONS" | "NEVER";
export type TTSNotificationType = "ALL" | "ONLY_MENTIONS" | "NEVER";
export interface NotificationSettingsState {
desktopType: DesktopNotificationType;
disableAllSounds: boolean;
disabledSounds: string[];
ttsType: TTSNotificationType;
disableUnreadBadge: boolean;
taskbarFlash: boolean;
notifyMessagesInSelectedChannel: boolean;
}
export class NotificationSettingsStore extends FluxStore {
get taskbarFlash(): boolean;
getUserAgnosticState(): NotificationSettingsState;
getDesktopType(): DesktopNotificationType;
getTTSType(): TTSNotificationType;
getDisabledSounds(): string[];
getDisableAllSounds(): boolean;
getDisableUnreadBadge(): boolean;
getNotifyMessagesInSelectedChannel(): boolean;
isSoundDisabled(sound: string): boolean;
}

View file

@ -0,0 +1,15 @@
import { FluxStore } from "..";
export interface OverridePremiumTypeState {
createdAtOverride: Date | undefined;
premiumTypeActual: number | null;
premiumTypeOverride: number | undefined;
}
export class OverridePremiumTypeStore extends FluxStore {
getState(): OverridePremiumTypeState;
getCreatedAtOverride(): Date | undefined;
getPremiumTypeActual(): number | null;
getPremiumTypeOverride(): number | undefined;
get premiumType(): number | undefined;
}

View file

@ -0,0 +1,15 @@
import { Channel, Message } from "../common";
import { FluxStore } from "./FluxStore";
export interface PendingReply {
channel: Channel;
message: Message;
shouldMention: boolean;
showMentionToggle: boolean;
}
export class PendingReplyStore extends FluxStore {
getPendingReply(channelId: string): PendingReply | undefined;
/** Discord doesn't use this method. Also seems to always return undefined */
getPendingReplyActionSource(channelId: string): unknown;
}

View file

@ -0,0 +1,57 @@
import { Channel, Guild, Role, FluxStore } from "..";
export interface GuildPermissionProps {
canManageGuild: boolean;
canManageChannels: boolean;
canManageRoles: boolean;
canManageBans: boolean;
canManageNicknames: boolean;
canManageGuildExpressions: boolean;
canViewAuditLog: boolean;
canViewAuditLogV2: boolean;
canManageWebhooks: boolean;
canViewGuildAnalytics: boolean;
canAccessMembersPage: boolean;
isGuildAdmin: boolean;
isOwner: boolean;
isOwnerWithRequiredMfaLevel: boolean;
guild: Guild;
}
export interface PartialChannelContext {
channelId: string;
}
export interface PartialGuildContext {
guildId: string;
}
export type PartialContext = PartialChannelContext | PartialGuildContext;
type PartialChannel = Channel | { id: string; };
type PartialGuild = Guild | { id: string; };
export class PermissionStore extends FluxStore {
// TODO: finish typing these
can(permission: bigint, channelOrGuild: PartialChannel | PartialGuild, guildId?: string, overwrites?: Record<string, any>, userId?: string): boolean;
canBasicChannel(permission: bigint, channel: PartialChannel, guildId?: string, overwrites?: Record<string, any>, userId?: string): boolean;
canWithPartialContext(permission: bigint, context: PartialContext): boolean;
canManageUser(permission: bigint, userOrUserId: string, guild: PartialGuild): boolean;
canAccessGuildSettings(guild: PartialGuild): boolean;
canAccessMemberSafetyPage(guild: PartialGuild): boolean;
canImpersonateRole(guild: PartialGuild, role: Role): boolean;
// TODO: finish typing
computePermissions(channel: PartialChannel, guildId?: string, overwrites?: Record<string, any>, userId?: string): bigint;
computeBasicPermissions(channel: PartialChannel): number;
getChannelPermissions(channel: PartialChannel): bigint;
getGuildPermissions(guild: PartialGuild): bigint;
getGuildPermissionProps(guild: PartialGuild): GuildPermissionProps;
getHighestRole(guild: PartialGuild): Role | null;
isRoleHigher(guild: PartialGuild, firstRole: Role | null, secondRole: Role | null): boolean;
getGuildVersion(guildId: string): number;
getChannelsVersion(): number;
}

View file

@ -0,0 +1,246 @@
import { FluxStore } from "..";
/**
* Known popout window key constants.
* Used as the key parameter for PopoutWindowStore and PopoutActions methods.
*/
export type PopoutWindowKey =
| "DISCORD_CHANNEL_CALL_POPOUT"
| "DISCORD_CALL_TILE_POPOUT"
| "DISCORD_SOUNDBOARD"
| "DISCORD_RTC_DEBUG_POPOUT"
| "DISCORD_CHANNEL_POPOUT"
| "DISCORD_ACTIVITY_POPOUT"
| "DISCORD_OVERLAY_POPOUT"
| "DISCORD_DEVTOOLS_POPOUT";
/**
* Popout window lifecycle event types.
* Sent via postMessage from popout to parent window.
*/
export type PopoutWindowEventType = "loaded" | "unloaded";
/**
* Persisted window position and size state.
* Saved to localStorage and restored when reopening popouts.
*/
export interface PopoutWindowState {
/** window x position on screen in pixels. */
x: number;
/** window y position on screen in pixels. */
y: number;
/** window inner width in pixels. */
width: number;
/** window inner height in pixels. */
height: number;
/** whether window stays above other windows, only on desktop app. */
alwaysOnTop?: boolean;
}
/**
* Features passed to window.open() for popout configuration.
* Merged with default features (menubar, toolbar, location, directories = false).
*/
export interface BrowserWindowFeatures {
/** whether to show browser toolbar. */
toolbar?: boolean;
/** whether to show menu bar. */
menubar?: boolean;
/** whether to show location/address bar. */
location?: boolean;
/** whether to show directory buttons. */
directories?: boolean;
/** window width in pixels. */
width?: number;
/** window height in pixels. */
height?: number;
/** default width if no persisted state exists. */
defaultWidth?: number;
/** default height if no persisted state exists. */
defaultHeight?: number;
/** window left position in pixels. */
left?: number;
/** window top position in pixels. */
top?: number;
/** default always-on-top state, defaults to false. */
defaultAlwaysOnTop?: boolean;
/** whether window can be moved by user. */
movable?: boolean;
/** whether window can be resized by user. */
resizable?: boolean;
/** whether window has a frame/border. */
frame?: boolean;
/** whether window stays above other windows. */
alwaysOnTop?: boolean;
/** whether window has a shadow (macOS). */
hasShadow?: boolean;
/** whether window background is transparent. */
transparent?: boolean;
/** whether to hide window from taskbar. */
skipTaskbar?: boolean;
/** title bar style, null for default. */
titleBarStyle?: string | null;
/** window background color as hex string. */
backgroundColor?: string;
/** whether this is an out-of-process overlay window. */
outOfProcessOverlay?: boolean;
}
/**
* Manages Discord's popout windows (voice calls, activities, etc.).
* Extends PersistedStore to save window positions across sessions.
*
* Handles Flux actions:
* - POPOUT_WINDOW_OPEN: opens a new popout window
* - POPOUT_WINDOW_CLOSE: closes a popout window
* - POPOUT_WINDOW_SET_ALWAYS_ON_TOP: toggles always-on-top (desktop only)
* - POPOUT_WINDOW_ADD_STYLESHEET: injects stylesheet into all open popouts
* - LOGOUT: closes all popout windows
*/
export class PopoutWindowStore extends FluxStore {
/**
* Gets the Window object for a popout.
* @param key unique identifier for the popout window
* @returns Window reference or undefined if not open
*/
getWindow(key: string): Window | undefined;
/**
* Gets persisted position/size state for a window.
* State is saved when window closes and restored when reopened.
* @param key unique identifier for the popout window
* @returns saved state or undefined if never opened
*/
getWindowState(key: string): PopoutWindowState | undefined;
/**
* Gets all currently open popout window keys.
* @returns array of window key identifiers
*/
getWindowKeys(): string[];
/**
* Checks if a popout window is currently open.
* @param key unique identifier for the popout window
* @returns true if window exists and is not closed
*/
getWindowOpen(key: string): boolean;
/**
* Checks if a popout window has always-on-top enabled.
* Only functional on desktop app (isPlatformEmbedded).
* @param key unique identifier for the popout window
* @returns true if always-on-top is enabled
*/
getIsAlwaysOnTop(key: string): boolean;
/**
* Checks if a popout window's document has focus.
* @param key unique identifier for the popout window
* @returns true if window document has focus
*/
getWindowFocused(key: string): boolean;
/**
* Checks if a popout window is visible (not minimized/hidden).
* Uses document.visibilityState === "visible".
* @param key unique identifier for the popout window
* @returns true if window is visible
*/
getWindowVisible(key: string): boolean;
/**
* Gets all persisted window states.
* Keyed by window identifier, contains position/size data.
* @returns record of window key to persisted state
*/
getState(): Record<string, PopoutWindowState>;
/**
* Checks if a window is fully initialized and ready for rendering.
* A window is fully initialized when it has:
* - Window object created
* - React root mounted
* - Render function stored
* @param key unique identifier for the popout window
* @returns true if window is fully initialized
*/
isWindowFullyInitialized(key: string): boolean;
/**
* Checks if a popout window is in fullscreen mode.
* Checks if document.fullscreenElement.id === "app-mount".
* @param key unique identifier for the popout window
* @returns true if window is fullscreen
*/
isWindowFullScreen(key: string): boolean;
/**
* Unmounts and closes a popout window.
* Saves current position/size before closing.
* Logs warning if window was not fully initialized.
* @param key unique identifier for the popout window
*/
unmountWindow(key: string): void;
}
/**
* Actions for managing popout windows.
* Dispatches Flux actions to PopoutWindowStore.
*/
export interface PopoutActions {
/**
* Opens a new popout window.
* If window with key already exists and is not out-of-process:
* - On desktop: focuses the existing window via native module
* - On web: calls window.focus()
* @param key unique identifier for the popout window
* @param render function that returns React element to render, receives key as arg
* @param features window features (size, position, etc.)
*/
open(key: string, render: (key: string) => React.ReactNode, features?: BrowserWindowFeatures): void;
/**
* Closes a popout window.
* Saves position/size state before closing unless preventPopoutClose setting is true.
* @param key unique identifier for the popout window
*/
close(key: string): void;
/**
* Sets always-on-top state for a popout window.
* Only functional on desktop app (isPlatformEmbedded).
* @param key unique identifier for the popout window
* @param alwaysOnTop whether window should stay above others
*/
setAlwaysOnTop(key: string, alwaysOnTop: boolean): void;
/**
* Note: Not actually in the Webpack Common. You have to add it yourself if you want to use it
*
* Injects a stylesheet into all open popout windows.
* Validates origin matches current host or webpack public path.
* @param url stylesheet URL to inject
* @param integrity optional SRI integrity hash
*/
addStylesheet?(url: string, integrity?: string): void;
/**
* Note: Not actually in the Webpack Common. You have to add it yourself if you want to use it
*
* Opens a channel call popout for voice/video calls.
* Dispatches CHANNEL_CALL_POPOUT_WINDOW_OPEN action.
* @param channel channel object to open call popout for
*/
openChannelCallPopout?(channel: { id: string; }): void;
/**
* Note: Not actually in the Webpack Common. You have to add it yourself if you want to use it
*
* Opens a call tile popout for a specific participant.
* Dispatches CALL_TILE_POPOUT_WINDOW_OPEN action.
* @param channelId channel ID of the call
* @param participantId user ID of the participant
*/
openCallTilePopout?(channelId: string, participantId: string): void;
}

View file

@ -0,0 +1,38 @@
import { Activity, OnlineStatus } from "../common";
import { FluxStore } from "./FluxStore";
export interface UserAndActivity {
userId: string;
activity: Activity;
}
export type DiscordPlatform = "desktop" | "mobile" | "web" | "embedded" | "vr";
export interface PresenceStoreState {
presencesForGuilds: Record<string, Record<string, { status: OnlineStatus; activities: Activity[]; clientStatus: Partial<Record<DiscordPlatform, OnlineStatus>>; }>>;
statuses: Record<string, OnlineStatus>;
activities: Record<string, Activity[]>;
filteredActivities: Record<string, Activity[]>;
hiddenActivities: Record<string, Activity[]>;
// TODO: finish typing
activityMetadata: Record<string, any>;
clientStatuses: Record<string, Partial<Record<DiscordPlatform, OnlineStatus>>>;
}
export class PresenceStore extends FluxStore {
findActivity(userId: string, predicate: (activity: Activity) => boolean, guildId?: string): Activity | undefined;
getActivities(userId: string, guildId?: string): Activity[];
// TODO: finish typing
getActivityMetadata(userId: string): any;
getAllApplicationActivities(applicationId: string): UserAndActivity[];
getApplicationActivity(userId: string, applicationId: string, guildId?: string): Activity | null;
getClientStatus(userId: string): Record<DiscordPlatform, OnlineStatus>;
getHiddenActivities(): Activity[];
/** literally just getActivities(...)[0] */
getPrimaryActivity(userId: string, guildId?: string): Activity | null;
getState(): PresenceStoreState;
getStatus(userId: string, guildId?: string | null, defaultStatus?: OnlineStatus): OnlineStatus;
getUnfilteredActivities(userId: string, guildId?: string): Activity[];
getUserIds(): string[];
isMobileOnline(userId: string): boolean;
}

View file

@ -0,0 +1,82 @@
import { FluxStore } from "..";
export type RTCConnectionState =
| "DISCONNECTED"
| "AWAITING_ENDPOINT"
| "AUTHENTICATING"
| "CONNECTING"
| "RTC_DISCONNECTED"
| "RTC_CONNECTING"
| "RTC_CONNECTED"
| "NO_ROUTE"
| "ICE_CHECKING"
| "DTLS_CONNECTING";
export type RTCConnectionQuality = "unknown" | "bad" | "average" | "fine";
export interface LastRTCConnectionState {
duration: number | null;
mediaSessionId: string | null;
rtcConnectionId: string | null;
wasEverMultiParticipant: boolean;
wasEverRtcConnected: boolean;
// TODO: type
voiceStateAnalytics: any;
channelId: string;
}
export interface RTCConnectionPacketStats {
inbound: number;
outbound: number;
lost: number;
}
export interface VoiceStateStats {
max_voice_state_count: number;
}
export interface SecureFramesState {
state: string;
}
export interface SecureFramesRosterMapEntry {
pendingVerifyState: number;
verifiedState: number;
}
export class RTCConnectionStore extends FluxStore {
// TODO: type
getRTCConnection(): any | null;
getState(): RTCConnectionState;
isConnected(): boolean;
isDisconnected(): boolean;
getRemoteDisconnectVoiceChannelId(): string | null;
getLastSessionVoiceChannelId(): string | null;
setLastSessionVoiceChannelId(channelId: string | null): void;
getGuildId(): string | undefined;
getChannelId(): string | undefined;
getHostname(): string;
getQuality(): RTCConnectionQuality;
getPings(): number[];
getAveragePing(): number;
getLastPing(): number | undefined;
getOutboundLossRate(): number | undefined;
getMediaSessionId(): string | undefined;
getRTCConnectionId(): string | undefined;
getDuration(): number | undefined;
getLastRTCConnectionState(): LastRTCConnectionState | null;
getVoiceFilterSpeakingDurationMs(): number | undefined;
getPacketStats(): RTCConnectionPacketStats | undefined;
getVoiceStateStats(): VoiceStateStats | undefined;
// TODO: finish typing
getUserVoiceSettingsStats(userId: string): any | undefined;
getWasEverMultiParticipant(): boolean;
getWasEverRtcConnected(): boolean;
getUserIds(): string[] | undefined;
getJoinVoiceId(): string | null;
isUserConnected(userId: string): boolean | undefined;
getSecureFramesState(): SecureFramesState | undefined;
getSecureFramesRosterMapEntry(oderId: string): SecureFramesRosterMapEntry | undefined;
getLastNonZeroRemoteVideoSinkWantsTime(): number | null;
getWasMoved(): boolean;
}

View file

@ -0,0 +1,70 @@
import { Channel, FluxStore } from "..";
import { ReadStateType } from "../../enums";
export interface GuildChannelUnreadState {
mentionCount: number;
unread: boolean;
isMentionLowImportance: boolean;
}
export interface ReadStateSnapshot {
unread: boolean;
mentionCount: number;
guildUnread: boolean | null;
guildMentionCount: number | null;
takenAt: number;
}
export interface SerializedReadState {
channelId: string;
type: ReadStateType;
_guildId: string;
_persisted: boolean;
_lastMessageId: string;
_lastMessageTimestamp: number;
_ackMessageId: string;
_ackMessageTimestamp: number;
ackPinTimestamp: number;
lastPinTimestamp: number;
_mentionCount: number;
flags: number;
lastViewed: number;
}
export class ReadStateStore extends FluxStore {
ackMessageId(channelId: string, type?: ReadStateType): string | null;
getAllReadStates(includePrivate?: boolean): SerializedReadState[];
getChannelIdsForWindowId(windowId: string): string[];
getForDebugging(channelId: string): object | undefined;
getGuildChannelUnreadState(
channel: Channel,
isOptInEnabled: boolean,
guildHasActiveThreads: boolean,
isChannelMuted: boolean,
isGuildHome: boolean
): GuildChannelUnreadState;
getGuildUnreadsSentinel(guildId: string): number;
getIsMentionLowImportance(channelId: string, type?: ReadStateType): boolean;
getMentionChannelIds(): string[];
getMentionCount(channelId: string, type?: ReadStateType): number;
getNonChannelAckId(type: ReadStateType): string | null;
getNotifCenterReadState(channelId: string): object | undefined;
getOldestUnreadMessageId(channelId: string, type?: ReadStateType): string | null;
getOldestUnreadTimestamp(channelId: string, type?: ReadStateType): number;
getReadStatesByChannel(): Record<string, object>;
getSnapshot(channelId: string, maxAge: number): ReadStateSnapshot;
getTrackedAckMessageId(channelId: string, type?: ReadStateType): string | null;
getUnreadCount(channelId: string, type?: ReadStateType): number;
hasOpenedThread(channelId: string): boolean;
hasRecentlyVisitedAndRead(channelId: string): boolean;
hasTrackedUnread(channelId: string): boolean;
hasUnread(channelId: string, type?: ReadStateType): boolean;
hasUnreadOrMentions(channelId: string, type?: ReadStateType): boolean;
hasUnreadPins(channelId: string): boolean;
isEstimated(channelId: string, type?: ReadStateType): boolean;
isForumPostUnread(channelId: string): boolean;
isNewForumThread(threadId: string, parentChannelId: string, guildId: string): boolean;
lastMessageId(channelId: string, type?: ReadStateType): string | null;
lastMessageTimestamp(channelId: string, type?: ReadStateType): number;
lastPinTimestamp(channelId: string): number;
}

View file

@ -0,0 +1,42 @@
import { FluxStore } from "..";
import { RelationshipType } from "../../enums";
export class RelationshipStore extends FluxStore {
getBlockedIDs(): string[];
getBlockedOrIgnoredIDs(): string[];
getFriendCount(): number;
getFriendIDs(): string[];
getIgnoredIDs(): string[];
getMutableRelationships(): Map<string, RelationshipType>;
getNickname(userId: string): string;
getOriginApplicationId(userId: string): string | undefined;
getOutgoingCount(): number;
getPendingCount(): number;
getPendingIgnoredCount(): number;
getRelationshipCount(): number;
/** @returns Enum value from constants.RelationshipTypes */
getRelationshipType(userId: string): RelationshipType;
getSince(userId: string): string;
getSinces(): Record<string, string>;
getSpamCount(): number;
getVersion(): number;
isBlocked(userId: string): boolean;
isBlockedForMessage(userId: string): boolean;
/**
* @see {@link isBlocked}
* @see {@link isIgnored}
*/
isBlockedOrIgnored(userId: string): boolean;
isBlockedOrIgnoredForMessage(userId: string): boolean;
isFriend(userId: string): boolean;
isIgnored(userId: string): boolean;
isIgnoredForMessage(userId: string): boolean;
isSpam(userId: string): boolean;
isStranger(userId: string): boolean;
isUnfilteredPendingIncoming(userId: string): boolean;
}

View file

@ -0,0 +1,60 @@
import { FluxStore } from "..";
export interface RunningGame {
id?: string;
name: string;
exePath: string;
cmdLine: string;
distributor: string;
lastFocused: number;
lastLaunched: number;
nativeProcessObserverId: number;
pid?: number;
hidden?: boolean;
isLauncher?: boolean;
elevated?: boolean;
sandboxed?: boolean;
}
export interface GameOverlayStatus {
enabledLegacy: boolean;
enabledOOP: boolean;
}
export interface SystemServiceStatus {
state: string;
}
export class RunningGameStore extends FluxStore {
canShowAdminWarning: boolean;
addExecutableTrackedByAnalytics(exe: string): void;
getCandidateGames(): RunningGame[];
getCurrentGameForAnalytics(): RunningGame | null;
getCurrentNonGameForAnalytics(): RunningGame | null;
getGameForName(name: string): RunningGame | null;
getGameForPID(pid: number): RunningGame | null;
getGameOrTransformedSubgameForPID(pid: number): RunningGame | null;
getGameOverlayStatus(game: RunningGame): GameOverlayStatus | null;
getGamesSeen(includeHidden?: boolean): RunningGame[];
getLauncherForPID(pid: number): RunningGame | null;
getObservedAppNameForWindow(windowHandle: number): string | null;
getOverlayEnabledForGame(game: RunningGame): boolean;
getOverlayOptionsForPID(pid: number): object | null;
getOverrideForGame(game: RunningGame): object | null;
getOverrides(): object[];
getRunningDiscordApplicationIds(): string[];
getRunningGames(): RunningGame[];
getRunningNonGames(): RunningGame[];
getRunningVerifiedApplicationIds(): string[];
getSeenGameByName(name: string): RunningGame | null;
getSystemServiceStatus(service: string): SystemServiceStatus;
getVisibleGame(): RunningGame | null;
getVisibleRunningGames(): RunningGame[];
isDetectionEnabled(type?: string): boolean;
isGamesSeenLoaded(): boolean;
isObservedAppRunning(app: string): boolean;
isSystemServiceInitialized(service: string): boolean;
shouldContinueWithoutElevatedProcessForPID(pid: number): boolean;
shouldElevateProcessForPID(pid: number): boolean;
}

View file

@ -0,0 +1,16 @@
import { FluxStore } from "..";
export interface ChannelFollowingDestination {
guildId?: string;
channelId?: string;
}
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;
getLastSelectedChannels(guildId?: string): string;
getLastChannelFollowingDestination(): ChannelFollowingDestination | undefined;
}

View file

@ -0,0 +1,14 @@
import { FluxStore } from "..";
export interface SelectedGuildState {
selectedGuildTimestampMillis: Record<string | number, number>;
selectedGuildId: string | null;
lastSelectedGuildId: string | null;
}
export class SelectedGuildStore extends FluxStore {
getGuildId(): string | null;
getLastSelectedGuildId(): string | null;
getLastSelectedTimestamp(guildId: string): number | null;
getState(): SelectedGuildState | undefined;
}

View file

@ -0,0 +1,47 @@
import { FluxStore } from "..";
export interface SoundboardSound {
soundId: string;
name: string;
volume: number;
emojiId: string | null;
emojiName: string | null;
available: boolean;
guildId: string;
userId?: string;
}
export interface TopSoundForGuild {
soundId: string;
rank: number;
}
export interface SoundboardOverlayState {
soundboardSounds: Record<string, SoundboardSound[]>;
favoritedSoundIds: string[];
localSoundboardMutes: string[];
}
export class SoundboardStore extends FluxStore {
getOverlaySerializedState(): SoundboardOverlayState;
getSounds(): Map<string, SoundboardSound[]>;
getSoundsForGuild(guildId: string): SoundboardSound[] | null;
getSound(guildId: string, soundId: string): SoundboardSound;
getSoundById(soundId: string): SoundboardSound;
isFetchingSounds(): boolean;
isFetchingDefaultSounds(): boolean;
isFetching(): boolean;
shouldFetchDefaultSounds(): boolean;
hasFetchedDefaultSounds(): boolean;
isUserPlayingSounds(userId: string): boolean;
isPlayingSound(soundId: string): boolean;
isFavoriteSound(soundId: string): boolean;
getFavorites(): Set<string>;
getAllTopSoundsForGuilds(): Map<string, TopSoundForGuild[]>;
isLocalSoundboardMuted(userId: string): boolean;
hasHadOtherUserPlaySoundInSession(): boolean;
shouldFetchTopSoundsForGuilds(): boolean;
hasFetchedTopSoundsForGuilds(): boolean;
hasFetchedAllSounds(): boolean;
isFetchingAnySounds(): boolean;
}

View file

@ -0,0 +1,6 @@
import { FluxStore } from "..";
export class SpellCheckStore extends FluxStore {
hasLearnedWord(word: string): boolean;
isEnabled(): boolean;
}

View file

@ -0,0 +1,106 @@
import { FluxStore } from "..";
export interface SpotifyDevice {
id: string;
is_active: boolean;
is_private_session: boolean;
is_restricted: boolean;
name: string;
supports_volume: boolean;
type: string;
volume_percent: number;
}
export interface SpotifySocket {
accessToken: string;
accountId: string;
connectionId: string;
isPremium: boolean;
socket: WebSocket;
}
export interface SpotifySocketAndDevice {
socket: SpotifySocket;
device: SpotifyDevice;
}
export interface SpotifyArtist {
id: string;
name: string;
}
export interface SpotifyImage {
url: string;
height: number;
width: number;
}
export interface SpotifyAlbum {
id: string;
name: string;
type: string;
image: SpotifyImage | null;
}
export interface SpotifyTrack {
id: string;
name: string;
duration: number;
isLocal: boolean;
type: string;
album: SpotifyAlbum;
artists: SpotifyArtist[];
}
export interface SpotifyPlayerState {
track: SpotifyTrack;
startTime: number;
context: { uri: string } | null;
}
export interface SpotifyActivity {
name: string;
assets: {
large_image?: string;
large_text?: string;
};
details: string;
state: string | undefined;
timestamps: {
start: number;
end: number;
};
party: {
id: string;
};
sync_id?: string;
flags?: number;
metadata?: {
context_uri: string | undefined;
album_id: string;
artist_ids: string[];
type: string;
button_urls: string[];
};
}
export interface SpotifySyncingWith {
oderId: string;
partyId: string;
sessionId: string;
userId: string;
}
export class SpotifyStore extends FluxStore {
hasConnectedAccount(): boolean;
getActiveSocketAndDevice(): SpotifySocketAndDevice | null;
getPlayableComputerDevices(): SpotifySocketAndDevice[];
canPlay(deviceId: string): boolean;
getSyncingWith(): SpotifySyncingWith | undefined;
wasAutoPaused(): boolean;
getLastPlayedTrackId(): string | undefined;
getTrack(): SpotifyTrack | null;
getPlayerState(accountId: string): SpotifyPlayerState | null;
shouldShowActivity(): boolean;
getActivity(): SpotifyActivity | null;
}

View file

@ -0,0 +1,22 @@
import { FluxStore, GuildSticker, PremiumStickerPack, Sticker } from "..";
export type StickerGuildMap = Map<string, GuildSticker[]>;
export type StickerPackMap = Map<string, Sticker[]>;
export class StickersStore extends FluxStore {
hasLoadedStickerPacks: boolean;
isFetchingStickerPacks: boolean;
isLoaded: boolean;
loadState: number;
getAllGuildStickers(): StickerGuildMap;
getAllPackStickers(): StickerPackMap;
getPremiumPacks(): PremiumStickerPack[];
getRawStickersByGuild(): StickerGuildMap;
getStickerById(id: string): Sticker | undefined;
// TODO: type
getStickerMetadataArrays(): any[];
getStickerPack(id: string): PremiumStickerPack | undefined;
getStickersByGuildId(guildId: string): Sticker[] | undefined;
isPremiumPack(id: string): boolean;
}

View file

@ -0,0 +1,24 @@
import { FluxStore } from "..";
export interface StreamerModeSettings {
enabled: boolean;
autoToggle: boolean;
hideInstantInvites: boolean;
hidePersonalInformation: boolean;
disableSounds: boolean;
disableNotifications: boolean;
enableContentProtection: boolean;
}
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;
getSettings(): StreamerModeSettings;
getState(): Record<string, StreamerModeSettings>;
}

View file

@ -0,0 +1,19 @@
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;
/** 0 = not loaded, 1 = loaded */
status: 0 | 1;
preferences: Record<ThemePreference, Theme>;
}
export class ThemeStore extends FluxStore {
get systemTheme(): SystemTheme;
get theme(): Theme;
getState(): ThemeState;
themePreferenceForSystemTheme(preference: ThemePreference): Theme;
}

View file

@ -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<string, number>;
isTyping(channelId: string, userId: string): boolean;
}

View file

@ -0,0 +1,11 @@
import { CloudUpload, FluxStore } from "..";
import { DraftType } from "../../enums";
export class UploadAttachmentStore extends FluxStore {
getFirstUpload(channelId: string, draftType: DraftType): CloudUpload | null;
hasAdditionalUploads(channelId: string, draftType: DraftType): boolean;
getUploads(channelId: string, draftType: DraftType): CloudUpload[];
getUploadCount(channelId: string, draftType: DraftType): number;
getUpload(channelId: string, uploadId: string, draftType: DraftType): CloudUpload;
findUpload(channelId: string, draftType: DraftType, predicate: (upload: CloudUpload) => boolean): CloudUpload | undefined;
}

View file

@ -0,0 +1,91 @@
import { Channel, FluxStore } from "..";
export interface MuteConfig {
selected_time_window: number;
end_time: string | null;
}
export interface ChannelOverride {
muted: boolean;
mute_config: MuteConfig | null;
message_notifications: number;
flags: number;
collapsed: boolean;
channel_id: string;
}
export interface GuildSettings {
suppress_everyone: boolean;
suppress_roles: boolean;
mute_scheduled_events: boolean;
mobile_push: boolean;
muted: boolean;
message_notifications: number;
flags: number;
channel_overrides: Record<string, ChannelOverride>;
notify_highlights: number;
hide_muted_channels: boolean;
version: number;
mute_config: MuteConfig | null;
guild_id: string;
}
export interface AccountNotificationSettings {
flags: number;
}
export interface UserGuildSettingsState {
useNewNotifications: boolean;
}
export class UserGuildSettingsStore extends FluxStore {
get accountNotificationSettings(): AccountNotificationSettings;
get mentionOnAllMessages(): boolean;
get useNewNotifications(): boolean;
allowAllMessages(guildId: string): boolean;
allowNoMessages(guildId: string): boolean;
getAddedToMessages(): string[];
// TODO: finish typing
getAllSettings(): { userGuildSettings: Record<string, GuildSettings>; };
getChannelFlags(channel: Channel): number;
getChannelIdFlags(guildId: string, channelId: string): number;
getChannelMessageNotifications(guildId: string, channelId: string): number | null;
getChannelMuteConfig(guildId: string, channelId: string): MuteConfig | null;
getChannelOverrides(guildId: string): Record<string, ChannelOverride>;
getChannelRecordUnreadSetting(channel: Channel): number;
getChannelUnreadSetting(guildId: string, channelId: string): number;
getGuildFavorites(guildId: string): string[];
getGuildFlags(guildId: string): number;
getGuildUnreadSetting(guildId: string): number;
getMessageNotifications(guildId: string): number;
getMuteConfig(guildId: string): MuteConfig | null;
getMutedChannels(guildId: string): string[];
getNewForumThreadsCreated(guildId: string): boolean;
getNotifyHighlights(guildId: string): number;
getOptedInChannels(guildId: string): string[];
// TODO: finish typing these
getOptedInChannelsWithPendingUpdates(guildId: string): Record<string, any>;
getPendingChannelUpdates(guildId: string): Record<string, any>;
getState(): UserGuildSettingsState;
isAddedToMessages(channelId: string): boolean;
isCategoryMuted(guildId: string, channelId: string): boolean;
isChannelMuted(guildId: string, channelId: string): boolean;
isChannelOptedIn(guildId: string, channelId: string, usePending?: boolean): boolean;
isChannelOrParentOptedIn(guildId: string, channelId: string, usePending?: boolean): boolean;
isChannelRecordOrParentOptedIn(channel: Channel, usePending?: boolean): boolean;
isFavorite(guildId: string, channelId: string): boolean;
isGuildCollapsed(guildId: string): boolean;
isGuildOrCategoryOrChannelMuted(guildId: string, channelId: string): boolean;
isMessagesFavorite(guildId: string): boolean;
isMobilePushEnabled(guildId: string): boolean;
isMuteScheduledEventsEnabled(guildId: string): boolean;
isMuted(guildId: string): boolean;
isOptInEnabled(guildId: string): boolean;
isSuppressEveryoneEnabled(guildId: string): boolean;
isSuppressRolesEnabled(guildId: string): boolean;
isTemporarilyMuted(guildId: string): boolean;
resolveGuildUnreadSetting(guildId: string): number;
resolveUnreadSetting(channel: Channel): number;
resolvedMessageNotifications(guildId: string): number;
}

View file

@ -0,0 +1,166 @@
import { FluxStore, Guild, User, Application, ApplicationInstallParams } from "..";
import { ApplicationIntegrationType } from "../../enums";
export interface MutualFriend {
/**
* the userid of the mutual friend
*/
key: string;
/**
* the status of the mutual friend
*/
status: "online" | "offline" | "idle" | "dnd";
/**
* the user object of the mutual friend
*/
user: User;
}
export interface MutualGuild {
/**
* the guild object of the mutual guild
*/
guild: Guild;
/**
* the user's nickname in the guild, if any
*/
nick: string | null;
}
export interface ProfileBadge {
id: string;
description: string;
icon: string;
link?: string;
}
export interface ConnectedAccount {
type: "twitch" | "youtube" | "skype" | "steam" | "leagueoflegends" | "battlenet" | "bluesky" | "bungie" | "reddit" | "twitter" | "twitter_legacy" | "spotify" | "facebook" | "xbox" | "samsung" | "contacts" | "instagram" | "mastodon" | "soundcloud" | "github" | "playstation" | "playstation-stg" | "epicgames" | "riotgames" | "roblox" | "paypal" | "ebay" | "tiktok" | "crunchyroll" | "domain" | "amazon-music";
/**
* underlying id of connected account
* eg. account uuid
*/
id: string;
/**
* display name of connected account
*/
name: string;
verified: boolean;
metadata?: Record<string, string>;
}
export interface ProfileApplication {
id: string;
customInstallUrl: string | undefined;
installParams: ApplicationInstallParams | undefined;
flags: number;
popularApplicationCommandIds?: string[];
integrationTypesConfig: Record<ApplicationIntegrationType, Partial<{
oauth2_install_params: ApplicationInstallParams;
}>>;
primarySkuId: string | undefined;
storefront_available: boolean;
}
export interface UserProfileBase extends Pick<User, "banner"> {
accentColor: number | null;
/**
* often empty for guild profiles, get the user profile for badges
*/
badges: ProfileBadge[];
bio: string | undefined;
popoutAnimationParticleType: string | null;
profileEffectExpiresAt: number | Date | undefined;
profileEffectId: undefined | string;
/**
* often an empty string when not set
*/
pronouns: string | "" | undefined;
themeColors: [number, number] | undefined;
userId: string;
}
export interface ApplicationRoleConnection {
application: Application;
application_metadata: Record<string, any>;
metadata: Record<string, any>;
platform_name: string;
platform_username: string;
}
export interface UserProfile extends UserProfileBase, Pick<User, "premiumType"> {
/** If this is a bot user profile, this will be its application */
application: ProfileApplication | null;
applicationRoleConnections: ApplicationRoleConnection[] | undefined;
connectedAccounts: ConnectedAccount[] | undefined;
fetchStartedAt: number;
fetchEndedAt: number;
legacyUsername: string | undefined;
premiumGuildSince: Date | null;
premiumSince: Date | null;
}
export interface ApplicationWidgetConfig {
applicationId: string;
widgetType: number;
}
export interface WishlistSettings {
privacy: number;
}
export class UserProfileStore extends FluxStore {
get applicationWidgetApplicationConfigs(): Record<string, ApplicationWidgetConfig>;
get isSubmitting(): boolean;
getApplicationWidgetApplicationConfig(applicationId: string): ApplicationWidgetConfig | undefined;
getFirstWishlistId(userId: string): string | null;
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;
getUserProfile(userId: string): UserProfile | undefined;
// TODO: finish typing
getWidgets(userId: string): any[] | undefined;
getWishlistIds(userId: string): string[];
getWishlistSettings(userId: string): WishlistSettings | null;
/**
* 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;
/**
* @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;
takeSnapshot(): Record<string, UserProfile>;
}

View file

@ -0,0 +1,223 @@
import { FluxStore } from "..";
export interface GuildFolder {
guildIds: string[];
folderId?: number;
folderName?: string;
folderColor?: number;
}
export interface GuildProto {
// TODO: finish typing
channels: Record<string, any>;
hubProgress: number;
guildOnboardingProgress: number;
dismissedGuildContent: Record<string, number>;
disableRaidAlertPush: boolean;
disableRaidAlertNag: boolean;
leaderboardsDisabled: boolean;
// TODO: finish typing
guildDismissibleContentStates: Record<string, any>;
}
export interface UserSettingsVersions {
clientVersion: number;
serverVersion: number;
dataVersion: number;
}
export interface InboxSettings {
currentTab: number;
viewedTutorial: boolean;
}
export interface GuildsSettings {
guilds: Record<string, GuildProto>;
}
export interface UserContentSettings {
dismissedContents: string;
lastReceivedChangelogId: string;
// TODO: finish typing
recurringDismissibleContentStates: Record<string, any>;
// TODO: type
lastDismissedOutboundPromotionStartDate: any;
premiumTier0ModalDismissedAt: any;
}
export interface VoiceAndVideoSettings {
// TODO: type
videoBackgroundFilterDesktop: any;
alwaysPreviewVideo: boolean;
afkTimeout: number;
streamNotificationsEnabled: boolean;
nativePhoneIntegrationEnabled: boolean;
disableStreamPreviews: boolean;
soundmojiVolume: number;
}
export interface TextAndImagesSettings {
emojiPickerCollapsedSections: string[];
stickerPickerCollapsedSections: string[];
soundboardPickerCollapsedSections: string[];
dmSpamFilterV2: number;
viewImageDescriptions: boolean;
inlineAttachmentMedia: boolean;
inlineEmbedMedia: boolean;
gifAutoPlay: boolean;
renderEmbeds: boolean;
renderReactions: boolean;
animateEmoji: boolean;
animateStickers: number;
enableTtsCommand: boolean;
messageDisplayCompact: boolean;
explicitContentFilter: number;
viewNsfwGuilds: boolean;
convertEmoticons: boolean;
viewNsfwCommands: boolean;
includeStickersInAutocomplete: boolean;
// TODO: type these
explicitContentSettings: any;
goreContentSettings: any;
showMentionSuggestions: boolean;
}
export interface NotificationsSettings {
notificationCenterAckedBeforeId: string;
focusModeExpiresAtMs: string;
reactionNotifications: number;
gameActivityNotifications: boolean;
customStatusPushNotifications: boolean;
showInAppNotifications: boolean;
notifyFriendsOnGoLive: boolean;
enableVoiceActivityNotifications: boolean;
enableUserResurrectionNotifications: boolean;
}
export interface PrivacySettings {
restrictedGuildIds: string[];
defaultGuildsRestricted: boolean;
allowAccessibilityDetection: boolean;
activityRestrictedGuildIds: string[];
defaultGuildsActivityRestricted: boolean;
activityJoiningRestrictedGuildIds: string[];
messageRequestRestrictedGuildIds: string[];
guildsLeaderboardOptOutDefault: boolean;
slayerSdkReceiveDmsInGame: boolean;
defaultGuildsActivityRestrictedV2: boolean;
detectPlatformAccounts: boolean;
passwordless: boolean;
contactSyncEnabled: boolean;
friendSourceFlags: number;
friendDiscoveryFlags: number;
dropsOptedOut: boolean;
hideLegacyUsername: boolean;
defaultGuildsRestrictedV2: boolean;
quests3PDataOptedOut: boolean;
}
export interface GameLibrarySettings {
disableGamesTab: boolean;
}
export interface StatusSettings {
statusExpiresAtMs: string;
status: { status: string; } | null;
showCurrentGame: boolean;
statusCreatedAtMs: string;
}
export interface LocalizationSettings {
locale: { localeCode: string; } | null;
timezoneOffset: { offset: number; } | null;
}
export interface AppearanceSettings {
theme: number;
developerMode: boolean;
mobileRedesignDisabled: boolean;
timestampHourCycle: number;
launchPadMode: number;
uiDensity: number;
swipeRightToLeftMode: number;
// TODO: type
clientThemeSettings: any;
}
export interface GuildFoldersSettings {
folders: GuildFolder[];
guildPositions: string[];
}
export interface AudioContextSettings {
// TODO: finish these
user: Record<string, any>;
stream: Record<string, any>;
}
export interface ClipsSettings {
allowVoiceRecording: boolean;
}
export interface InAppFeedbackSettings {
// TODO: finish typing
inAppFeedbackStates: Record<string, any>;
}
export interface UserSettings {
versions: UserSettingsVersions;
inbox: InboxSettings;
guilds: GuildsSettings;
userContent: UserContentSettings;
voiceAndVideo: VoiceAndVideoSettings;
textAndImages: TextAndImagesSettings;
notifications: NotificationsSettings;
privacy: PrivacySettings;
// TODO: finish typing
debug: Record<string, any>;
gameLibrary: GameLibrarySettings;
status: StatusSettings;
localization: LocalizationSettings;
appearance: AppearanceSettings;
guildFolders: GuildFoldersSettings;
audioContextSettings: AudioContextSettings;
clips: ClipsSettings;
inAppFeedbackSettings: InAppFeedbackSettings;
}
export interface FrecencySettings {
// TODO: type all of these
versions: any;
favoriteGifs: any;
favoriteStickers: any;
stickerFrecency: any;
favoriteEmojis: any;
emojiFrecency: any;
applicationCommandFrecency: any;
favoriteSoundboardSounds: any;
applicationFrecency: any;
playedSoundFrecency: any;
guildAndChannelFrecency: any;
emojiReactionFrecency: any;
}
export interface ProtoState {
// TODO: type
proto: any;
}
export class UserSettingsProtoStore extends FluxStore {
settings: UserSettings;
frecencyWithoutFetchingLatest: FrecencySettings;
wasMostRecentUpdateFromServer: boolean;
getState(): Record<string, ProtoState>;
computeState(): Record<string, ProtoState>;
getFullState(): Record<string, ProtoState>;
hasLoaded(settingsType: number): boolean;
getGuildFolders(): GuildFolder[];
getGuildRecentsDismissedAt(guildId: string): number;
getDismissedGuildContent(guildId: string): Record<string, number> | null;
// TODO: finish typing
getGuildDismissedContentState(guildId: string): any;
getGuildsProto(): Record<string, GuildProto>;
}

View file

@ -0,0 +1,34 @@
import { FluxStore, User } from "..";
/** returned by takeSnapshot for persistence */
export interface UserStoreSnapshot {
/** snapshot format version, currently 1 */
version: number;
data: {
/** contains only the current user */
users: User[];
};
}
export class UserStore extends FluxStore {
/**
* filters users and optionally sorts results.
* @param sort if true (default false), sorts alphabetically by username
*/
filter(filter: (user: User) => boolean, sort?: boolean): User[];
/**
* finds user by username and discriminator.
* for new username system (unique usernames), pass null/undefined as discriminator.
*/
findByTag(username: string, discriminator?: string | null): User | undefined;
/** @param action return false to break iteration early */
forEach(action: (user: User) => boolean | void): void;
getCurrentUser(): User;
getUser(userId: string): User;
/** keyed by user ID */
getUsers(): Record<string, User>;
/** increments when users are added/updated/removed */
getUserStoreVersion(): number;
/** only includes current user, used for persistence */
takeSnapshot(): UserStoreSnapshot;
}

View file

@ -0,0 +1,51 @@
import { DiscordRecord } from "../common";
import { FluxStore } from "./FluxStore";
export type UserVoiceStateRecords = Record<string, VoiceState>;
export type VoiceStates = Record<string, UserVoiceStateRecords>;
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;
getVoiceStateVersion(): number;
getVoiceStates(guildId?: string | null): UserVoiceStateRecords;
getVoiceStatesForChannel(channelId: string): UserVoiceStateRecords;
getVideoVoiceStatesForChannel(channelId: string): UserVoiceStateRecords;
getVoiceState(guildId: string | null, userId: string): VoiceState | undefined;
getDiscoverableVoiceState(guildId: string | null, userId: string): VoiceState | null;
getVoiceStateForChannel(channelId: string, userId?: string): VoiceState | undefined;
getVoiceStateForUser(userId: string): VoiceState | undefined;
getDiscoverableVoiceStateForUser(userId: string): VoiceState | undefined;
getVoiceStateForSession(userId: string, sessionId?: string | null): VoiceState | null | undefined;
getUserVoiceChannelId(guildId: string | null, userId: string): string | undefined;
getCurrentClientVoiceChannelId(guildId: string | null): string | undefined;
getUsersWithVideo(channelId: string): Set<string>;
getVoicePlatformForChannel(channelId: string, guildId: string): string | undefined;
isCurrentClientInVoiceChannel(): boolean;
isInChannel(channelId: string, userId?: string): boolean;
hasVideo(channelId: string): boolean;
get userHasBeenMovedVersion(): number;
}

View file

@ -0,0 +1,22 @@
import { FluxStore } from "..";
export interface WindowSize {
width: number;
height: number;
}
export class WindowStore extends FluxStore {
/** returns focused window ID, or null if no window is focused */
getFocusedWindowId(): string | null;
getLastFocusedWindowId(): string;
/** true if any window is focused (getFocusedWindowId() !== null) */
isAppFocused(): boolean;
/** @param windowId defaults to current window */
isElementFullScreen(windowId?: string): boolean;
/** @param windowId defaults to current window */
isFocused(windowId?: string): boolean;
/** @param windowId defaults to current window */
isVisible(windowId?: string): boolean;
/** @param windowId defaults to current window, returns {width: 0, height: 0} for invalid ID */
windowSize(windowId?: string): WindowSize;
}

View file

@ -0,0 +1,66 @@
// please keep in alphabetical order
export * from "./AccessibilityStore";
export * from "./ActiveJoinedThreadsStore";
export * from "./ApplicationStore";
export * from "./AuthenticationStore";
export * from "./CallStore";
export * from "./ChannelRTCStore";
export * from "./ChannelStore";
export * from "./DraftStore";
export * from "./EmojiStore";
export * from "./FluxStore";
export * from "./FriendsStore";
export * from "./GuildChannelStore";
export * from "./GuildMemberCountStore";
export * from "./GuildMemberStore";
export * from "./GuildRoleStore";
export * from "./GuildScheduledEventStore";
export * from "./GuildStore";
export * from "./InstantInviteStore";
export * from "./InviteStore";
export * from "./LocaleStore";
export * from "./MediaEngineStore";
export * from "./MessageStore";
export * from "./NotificationSettingsStore";
export * from "./OverridePremiumTypeStore";
export * from "./PendingReplyStore";
export * from "./PermissionStore";
export * from "./PopoutWindowStore";
export * from "./PresenceStore";
export * from "./ReadStateStore";
export * from "./RelationshipStore";
export * from "./RTCConnectionStore";
export * from "./RunningGameStore";
export * from "./SelectedChannelStore";
export * from "./SelectedGuildStore";
export * from "./SoundboardStore";
export * from "./SpellCheckStore";
export * from "./SpotifyStore";
export * from "./StickersStore";
export * from "./StreamerModeStore";
export * from "./ThemeStore";
export * from "./TypingStore";
export * from "./UploadAttachmentStore";
export * from "./UserGuildSettingsStore";
export * from "./UserProfileStore";
export * from "./UserSettingsProtoStore";
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 = <T>(
stores: any[],
mapper: () => T,
dependencies?: any,
isEqual?: (old: T, newer: T) => boolean
) => T;

View file

@ -1,22 +1,4 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2023 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Channel, Guild, GuildMember, Message, User } from "discord-types/general";
import { Channel, Guild, GuildMember, Message, User } from ".";
import type { ReactNode } from "react";
import { LiteralUnion } from "type-fest";
@ -24,13 +6,15 @@ import type { FluxEvents } from "./fluxEvents";
export { FluxEvents };
type FluxEventsAutoComplete = LiteralUnion<FluxEvents, string>;
export interface FluxDispatcher {
_actionHandlers: any;
_subscriptions: any;
dispatch(event: { [key: string]: unknown; type: FluxEvents; }): Promise<void>;
dispatch(event: { [key: string]: unknown; type: FluxEventsAutoComplete; }): Promise<void>;
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;
}
@ -240,34 +224,7 @@ export interface ExpressionPickerStore {
useExpressionPickerStore<T>(selector: (state: ExpressionPickerStoreState) => T): T;
}
export interface BrowserWindowFeatures {
toolbar?: boolean;
menubar?: boolean;
location?: boolean;
directories?: boolean;
width?: number;
height?: number;
defaultWidth?: number;
defaultHeight?: number;
left?: number;
top?: number;
defaultAlwaysOnTop?: boolean;
movable?: boolean;
resizable?: boolean;
frame?: boolean;
alwaysOnTop?: boolean;
hasShadow?: boolean;
transparent?: boolean;
skipTaskbar?: boolean;
titleBarStyle?: string | null;
backgroundColor?: string;
}
export interface PopoutActions {
open(key: string, render: (windowKey: string) => ReactNode, features?: BrowserWindowFeatures);
close(key: string): void;
setAlwaysOnTop(key: string, alwaysOnTop: boolean): void;
}
export { BrowserWindowFeatures, PopoutActions } from "./stores/PopoutWindowStore";
export type UserNameUtilsTagInclude = LiteralUnion<"auto" | "always" | "never", string>;
export interface UserNameUtilsTagOptions {
@ -290,6 +247,7 @@ export interface UsernameUtils {
humanizeStatus: any;
}
// TODO: fix type
export class DisplayProfile {
userId: string;
banner?: string;
@ -335,3 +293,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;
}

View file

@ -1,11 +1,9 @@
/*
* Vencord, a Discord client mod
* @vencord/discord-types
* Copyright (c) 2024 Vendicated, Nuckyz and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
import { SYM_ORIGINAL_FACTORY, SYM_PATCHED_BY, SYM_PATCHED_SOURCE } from "./patchWebpack";
export type ModuleExports = any;
export type Module = {
@ -215,24 +213,3 @@ export type WebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & {
/** rspack unique id */
ruid: string;
};
// Utility section for Vencord
export type AnyWebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & Partial<Omit<WebpackRequire, "m">> & {
/** The module factories, where all modules that have been loaded are stored (pre-loaded or loaded by lazy chunks) */
m: Record<PropertyKey, AnyModuleFactory>;
};
/** exports can be anything, however initially it is always an empty object */
export type AnyModuleFactory = ((this: ModuleExports, module: Module, exports: ModuleExports, require: AnyWebpackRequire) => void) & {
[SYM_PATCHED_SOURCE]?: string;
[SYM_PATCHED_BY]?: Set<string>;
};
export type PatchedModuleFactory = AnyModuleFactory & {
[SYM_ORIGINAL_FACTORY]: AnyModuleFactory;
[SYM_PATCHED_SOURCE]?: string;
[SYM_PATCHED_BY]?: Set<string>;
};
export type MaybePatchedModuleFactory = PatchedModuleFactory | AnyModuleFactory;

View file

@ -1,7 +1,7 @@
{
"name": "@vencord/types",
"private": false,
"version": "1.11.5",
"version": "1.14.1",
"description": "",
"types": "index.d.ts",
"scripts": {
@ -19,10 +19,14 @@
"dependencies": {
"@types/lodash": "4.17.15",
"@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",
"@vencord/discord-types": "^1.0.0",
"highlight.js": "11.11.1",
"moment": "^2.22.2",
"ts-pattern": "^5.6.0",
"type-fest": "^4.35.0"
},
"peerDependencies": {
"@types/react": "18.3.1",
"@types/react-dom": "18.3.1"
}
}

View file

@ -1,49 +0,0 @@
diff --git a/lib/rules/no-useless-escape.js b/lib/rules/no-useless-escape.js
index 0e0f6f09f2c35f3276173c08f832cde9f2cf56a0..7dc22851715f3574d935f513c1b5e35552985711 100644
--- a/lib/rules/no-useless-escape.js
+++ b/lib/rules/no-useless-escape.js
@@ -65,13 +65,31 @@ module.exports = {
escapeBackslash: "Replace the `\\` with `\\\\` to include the actual backslash character."
},
- schema: []
+ schema: [{
+ type: "object",
+ properties: {
+ extra: {
+ type: "string",
+ default: ""
+ },
+ extraCharClass: {
+ type: "string",
+ default: ""
+ },
+ },
+ additionalProperties: false
+ }]
},
create(context) {
+ const options = context.options[0] || {};
+ const { extra, extraCharClass } = options;
const sourceCode = context.sourceCode;
const parser = new RegExpParser();
+ const NON_CHARCLASS_ESCAPES = union(REGEX_NON_CHARCLASS_ESCAPES, new Set(extra));
+ const CHARCLASS_ESCAPES = union(REGEX_GENERAL_ESCAPES, new Set(extraCharClass));
+
/**
* Reports a node
* @param {ASTNode} node The node to report
@@ -200,9 +218,9 @@ module.exports = {
let allowedEscapes;
if (characterClassStack.length) {
- allowedEscapes = unicodeSets ? REGEX_CLASSSET_CHARACTER_ESCAPES : REGEX_GENERAL_ESCAPES;
+ allowedEscapes = unicodeSets ? REGEX_CLASSSET_CHARACTER_ESCAPES : CHARCLASS_ESCAPES;
} else {
- allowedEscapes = REGEX_NON_CHARCLASS_ESCAPES;
+ allowedEscapes = NON_CHARCLASS_ESCAPES;
}
if (allowedEscapes.has(escapedChar)) {
return;

2233
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more