diff options
Diffstat (limited to 'node_modules/discord.js')
329 files changed, 49392 insertions, 0 deletions
diff --git a/node_modules/discord.js/CHANGELOG.md b/node_modules/discord.js/CHANGELOG.md new file mode 100644 index 0000000..3ab0dfe --- /dev/null +++ b/node_modules/discord.js/CHANGELOG.md @@ -0,0 +1,4899 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +# [14.13.0](https://github.com/discordjs/discord.js/compare/14.12.1...14.13.0) - (2023-08-17) + +## Bug Fixes + +- **Action:** Do not add the client user as a recipient (#9774) ([24fbb11](https://github.com/discordjs/discord.js/commit/24fbb11ba2f7e8f8f604752159d2053f2cee16ec)) +- **DMChannel:** Correct partial typo (#9773) ([c1ff545](https://github.com/discordjs/discord.js/commit/c1ff545bf1c018875f5a9ceb828c9f84ed391920)) +- **CachedManager:** Allow overriding constructor for makeCache (#9763) ([346fa57](https://github.com/discordjs/discord.js/commit/346fa57f95a99d5b4e1169bb85706c4c25bf71d0)) +- **types:** Fixed CachedManager constructor arguments in type (#9761) ([b3c85d3](https://github.com/discordjs/discord.js/commit/b3c85d34a6ced8a8e2cd15a6e3879fb2dd5121d0)) +- **Action:** Do not set `undefined` values (#9755) ([d8e3755](https://github.com/discordjs/discord.js/commit/d8e37551ceefe9f82566e3f45edc69bb7f9d1463)) + +## Documentation + +- **EmbedBuilder:** `@readonly` length (#9778) ([8f572a6](https://github.com/discordjs/discord.js/commit/8f572a6badd45b916d3a46dd489653d2d6efb2a8)) +- **WebhookEditOptions:** Add all of the types (#9776) ([d5be424](https://github.com/discordjs/discord.js/commit/d5be4242c6a6f90b90af54e27071ecc0f5422944)) +- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6)) + +## Features + +- **Client:** Add deleteWebhook method (#9777) ([d90ba8d](https://github.com/discordjs/discord.js/commit/d90ba8dce8de630db14b77764ec35201998c7ce7)) +- **ClientPresence:** Allow setting activity state (#9743) ([9ed1b59](https://github.com/discordjs/discord.js/commit/9ed1b59df6acb6356d5950b43d04885d5e692887)) +- **ClientApplication:** Approximate guild count and new `GET` route (#9713) ([632a9b4](https://github.com/discordjs/discord.js/commit/632a9b4965cd24ffffdf0f88f1a9eedeb6b284f7)) +- **Role:** Add `flags` (#9694) ([3b18e5b](https://github.com/discordjs/discord.js/commit/3b18e5b08dc3ec2aba37d3e6a55e42ce8af7dbab)) +- **Attachment:** Add `flags` (#9686) ([692f0fc](https://github.com/discordjs/discord.js/commit/692f0fc96d9f92161b64fb83f02b71d43d2d7c9c)) +- Add `Client#webhooksUpdate` (#9732) ([0de071d](https://github.com/discordjs/discord.js/commit/0de071d0a5524ba1fbb8cab5d7e74567103f7129)) + +## Typings + +- **GuildInvitableChannelResolvable:** Allow forum channels (#9775) ([727dc09](https://github.com/discordjs/discord.js/commit/727dc094d52a5b169e46917b64308ab87a7144b1)) +- Make activity name required (#9765) ([0a9a3ed](https://github.com/discordjs/discord.js/commit/0a9a3ede292b92235a103b6776477a707da4d84b)) +- **BaseButtonComponentData:** Narrow component type (#9735) ([a30d46c](https://github.com/discordjs/discord.js/commit/a30d46c5f5909eee86704bbb9e34fb7bb09b2c27)) + +# [14.12.1](https://github.com/discordjs/discord.js/compare/14.12.0...14.12.1) - (2023-08-01) + +## Bug Fixes + +- **BaseClient:** Fix destroy method (#9742) ([1af7e5a](https://github.com/discordjs/discord.js/commit/1af7e5a0bb4eca35221cb342c1c53dc18263c789)) + +# [14.12.0](https://github.com/discordjs/discord.js/compare/14.11.0...14.12.0) - (2023-07-31) + +## Bug Fixes + +- **ChannelUpdate:** Check against unknown channels (#9697) ([7fb91c5](https://github.com/discordjs/discord.js/commit/7fb91c57f72b74395d67f2207246033c703f1f19)) +- **Action:** Use existing recipients if available (#9653) ([719e54a](https://github.com/discordjs/discord.js/commit/719e54a921f74890519f066a9f56e52fdcfacf07)) +- Everyone role members (#9685) ([0803eb5](https://github.com/discordjs/discord.js/commit/0803eb562bdc7644fa611a0a87dea3e8b0d4c7af)) +- `awaitMessageComponent` with `MessageComponentInteraction`s (#8598) ([b61e4fb](https://github.com/discordjs/discord.js/commit/b61e4fb0dcb9e5d43a7626c5a4760f5801e06fae)) +- **ThreadManager:** Fix internal crash upon conditionally resolving thread members (#9648) ([a6dbe16](https://github.com/discordjs/discord.js/commit/a6dbe163dd3df12ad98465b1dfc040b8eff8805e)) +- **User:** Check global name in equals (#9631) ([8f3bd38](https://github.com/discordjs/discord.js/commit/8f3bd3807233fca2a057948406bdc8aef008b6cb)) +- **WebSocketManager:** Await WebSocket destroy (#9519) ([75308f2](https://github.com/discordjs/discord.js/commit/75308f266933454301b10ee8e1d940d782fdb637)) +- **Client:** Safe call for possibly null WebSocket (#9600) ([24a6149](https://github.com/discordjs/discord.js/commit/24a61495b9bf07887dd535a05ffbec2895faa888)) +- **ThreadManager:** Ensure `fetchActive()` only returns active threads in a channel (#9568) ([53aa24d](https://github.com/discordjs/discord.js/commit/53aa24d41809382c1af57bd1871107c8359e4a15)) +- **LimitedCollection:** Allow items to be stored if keepOverLimit is true when maxSize is 0 (#9534) ([9345d1b](https://github.com/discordjs/discord.js/commit/9345d1b1ac4f7b1f66b919602dff995782151407)) +- **AutocompleteInteraction:** Prevent snake casing of locales (#9565) ([7196fe3](https://github.com/discordjs/discord.js/commit/7196fe36e8089dde7bcaf0db4dd09cf524125e0c)) + +## Documentation + +- Change `Channel` to `BaseChannel` (#9718) ([e5effb6](https://github.com/discordjs/discord.js/commit/e5effb6f6a3e547006eb9bc054cc168844a157f2)) +- **BaseChannel:** Remove `APIChannel` (#9717) ([125405f](https://github.com/discordjs/discord.js/commit/125405f1cf11433c69ff1ae9d6b8f7e713fc37c0)) +- **BuildersSelectMenuOption:** Update link (#9690) ([ede9f4e](https://github.com/discordjs/discord.js/commit/ede9f4e5e203bcfb8820ae7ec3418482735ff9c1)) +- **ClientOptions:** Change default value of sweepers in docs (#9591) ([911e6ef](https://github.com/discordjs/discord.js/commit/911e6eff75f5d05e837d5dfaacf557d6594df16a)) +- **Client:** Correct invite gateway permission checks (#9597) ([e1b6eee](https://github.com/discordjs/discord.js/commit/e1b6eeed0e2e18f9900bc945c9f82d2d05f28a78)) +- Fix broken links to new documentation (#9563) ([d01e8aa](https://github.com/discordjs/discord.js/commit/d01e8aa8af00f5caacffe98caef3ead02e80a9bf)) + +## Features + +- Add ws option support for "buildIdentifyThrottler" (#9728) ([6307f81](https://github.com/discordjs/discord.js/commit/6307f813854ed9dc76d2c4351bd69dd0490d0928)) +- **Client:** Add `guildAvailable` event (#9692) ([3c85fb2](https://github.com/discordjs/discord.js/commit/3c85fb21e62b30e75a7200b704e242c3a0adeda1)) +- User avatar decorations (#8914) ([8d97017](https://github.com/discordjs/discord.js/commit/8d9701745840e23854e8f0b057d21cb10e7d1d54)) +- Add silent option to ShardingManager (#9506) ([df40dcd](https://github.com/discordjs/discord.js/commit/df40dcdb850c398642ebc5cd6e4c48034280f464)) +- **EmbedBuilder:** Add `.length` (#8682) ([53c17e0](https://github.com/discordjs/discord.js/commit/53c17e00c0668c3d1497142dde7384c058c46c64)) +- Guild onboarding (#9120) ([dc73c93](https://github.com/discordjs/discord.js/commit/dc73c938ff9d04a0d7d57630faeb8e81ea343006)) +- Add resume event in shard (#9650) ([a73d54e](https://github.com/discordjs/discord.js/commit/a73d54e43a01719f683e8fd21714e85ffe737add)) +- **presence:** Re-introduce image resolving for other platforms (#9637) ([73c2f8a](https://github.com/discordjs/discord.js/commit/73c2f8aa17aac51b05382444148cb1f60081ee03)) +- Add message to send resume event to shard (#9626) ([a873ec1](https://github.com/discordjs/discord.js/commit/a873ec1e8511829ba95e85bbc9a4074e40c76086)) +- Support new username system (#9512) ([1ab60f9](https://github.com/discordjs/discord.js/commit/1ab60f9da4d6b7ea144fa05b97b029a4bfaeede2)) +- **GuildAuditLogsEntry#extra:** Add missing `channel` property (#9518) ([2272321](https://github.com/discordjs/discord.js/commit/227232112d1cd9f211e177996b7cdee2940f471e)) + +## Performance + +- **Channel:** Linear speed position getter (#9497) ([09b0382](https://github.com/discordjs/discord.js/commit/09b0382c458ed0f3df5b8fa778c504b3e658ac49)) +- **Role:** Improve `members` getter (#9529) ([37181ab](https://github.com/discordjs/discord.js/commit/37181ab2322e48e17ff0d1040bcc510dc7c34e93)) + +## Refactor + +- **User:** Remove deprecation warning from tag (#9660) ([cf8012c](https://github.com/discordjs/discord.js/commit/cf8012c20022aff184d7bce0ad436c136e428d9c)) +- **GuildMember:** Make `_roles` property non-enumerable (#9387) ([46167a7](https://github.com/discordjs/discord.js/commit/46167a79d7d0cac5599459a31c33b2bbcf6e06da)) +- **rest:** Switch api to fetch-like and provide strategies (#9416) ([cdaa0a3](https://github.com/discordjs/discord.js/commit/cdaa0a36f586459f1e5ede868c4250c7da90455c)) + - **BREAKING CHANGE:** NodeJS v18+ is required when using node due to the use of global `fetch` + - **BREAKING CHANGE:** The raw method of REST now returns a web compatible `Respone` object. + - **BREAKING CHANGE:** The `parseResponse` utility method has been updated to operate on a web compatible `Response` object. + - **BREAKING CHANGE:** Many underlying internals have changed, some of which were exported. + - **BREAKING CHANGE:** `DefaultRestOptions` used to contain a default `agent`, which is now set to `null` instead. + +## Typings + +- **MessageManager:** Allow comparison of messages again (#9612) ([a48d0ef](https://github.com/discordjs/discord.js/commit/a48d0efb09613eac6bf3c1bd996f58f5fff7667c)) +- **AutoModerationActionExecution:** Add forum channels as a possible type in `channel()` (#9623) ([d64330a](https://github.com/discordjs/discord.js/commit/d64330a1570b3a2047ef959a6bce268372c70e99)) +- **ModalSubmitFields:** Components is an array (#9406) ([1cab79f](https://github.com/discordjs/discord.js/commit/1cab79f6fde6f367141c9f7ed91bcb70ed2e5c17)) +- Use `readonly` arrays and `const` type parameters in places (#9641) ([cd69868](https://github.com/discordjs/discord.js/commit/cd6986854f4c2d143d2cd9b81d096738480dfa63)) +- **BaseInteraction:** `appPermissions` not `null` in guilds (#9601) ([6c2242f](https://github.com/discordjs/discord.js/commit/6c2242f4f970b1c75c243f74ae64f30ecbf8ba0d)) + +# [14.11.0](https://github.com/discordjs/discord.js/compare/14.10.2...14.11.0) - (2023-05-06) + +## Bug Fixes + +- **WebSocketManager:** Properly emit shard error events (#9521) ([e627468](https://github.com/discordjs/discord.js/commit/e6274681fd10b0d75e1d3b448c94b50ec6810367)) +- **WebSocketManager:** Emit raw ws events again (#9502) ([c429763](https://github.com/discordjs/discord.js/commit/c429763be8e94f0f0cbc630e8bb1d415d46f1465)) + +## Documentation + +- **Client:** Update Sapphire's snowflake utility links (#9501) ([1b7981e](https://github.com/discordjs/discord.js/commit/1b7981e4696b8ae74ceffa876fc0a9be7d0b9f93)) + +## Features + +- **Guild:** Safety alerts channel and mention raid protection (#8959) ([6b2c3fb](https://github.com/discordjs/discord.js/commit/6b2c3fb9d0571de808e990cf064f73240ab93451)) + +## Performance + +- **Role:** Linear speed position getter (#9493) ([8e9a2b4](https://github.com/discordjs/discord.js/commit/8e9a2b4630f78bb9e45345ec2a16812bfac70a20)) + +## Refactor + +- **GuildChannel:** Simplify constructor (#9499) ([f2ad076](https://github.com/discordjs/discord.js/commit/f2ad0762c521422ab64e5b10344a6fd67961031b)) + +## Typings + +- **StringSelectMenuComponentData:** `options` is required (#9515) ([d7b18f0](https://github.com/discordjs/discord.js/commit/d7b18f0681d4147ff192c98108c035d6d0f96cce)) + +# [14.10.2](https://github.com/discordjs/discord.js/compare/14.10.1...14.10.2) - (2023-05-01) + +## Bug Fixes + +- Correct `isJSONEncodable()` import (#9495) ([201b002](https://github.com/discordjs/discord.js/commit/201b002ad405b845ace5f708077c1f157bb4126d)) +- **Client:** `generateInvite()` scope validation (#9492) ([b327f49](https://github.com/discordjs/discord.js/commit/b327f4925ff557e0aa8273d7f017aa616226ca06)) + +# [14.10.1](https://github.com/discordjs/discord.js/compare/14.10.0...14.10.1) - (2023-05-01) + +## Bug Fixes + +- **Client:** Spelling of InvalidScopesWithPermissions ([ac9bf3a](https://github.com/discordjs/discord.js/commit/ac9bf3ac06ec78dbaca2ce4a82cceb0d82484211)) + +## Refactor + +- **ShardClientUtil:** Logic de-duplication (#9491) ([a9f2bff](https://github.com/discordjs/discord.js/commit/a9f2bff82a18c6a3afdee99e5830e1d7b4da65dc)) + +# [14.10.0](https://github.com/discordjs/discord.js/compare/14.9.0...14.10.0) - (2023-05-01) + +## Bug Fixes + +- **ShardClientUtil:** Fix client event names (#9474) ([ad217cc](https://github.com/discordjs/discord.js/commit/ad217cc7604dda6a33df73db82799fd5bb4e85a9)) +- **BaseClient:** Prevent user agent mutation (#9425) ([217e5d8](https://github.com/discordjs/discord.js/commit/217e5d81005a2506c96335f7fb96fa21d7dbb04c)) +- **BitField:** Use only enum names in iterating (#9357) ([40d07fb](https://github.com/discordjs/discord.js/commit/40d07fbbbd51d62793d9ea541f41f157b5dad224)) +- Use new permission name (#9274) ([d2d27ce](https://github.com/discordjs/discord.js/commit/d2d27ce7346bc37b34938c84bd3b106a4fa51f53)) +- **Message#editable:** Fix permissions check in locked threads (#9319) ([d4c1fec](https://github.com/discordjs/discord.js/commit/d4c1fecbe264bc52a70aaf0ec303d35e2f15bbcd)) +- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2)) + +## Documentation + +- **AutoModerationRule:** Update docs (#9464) ([1b15d31](https://github.com/discordjs/discord.js/commit/1b15d31b5ae1b1739716fab00b18083c1d7d389a)) +- **APITypes:** Document role & user select menu components (#9435) ([c6ca5a8](https://github.com/discordjs/discord.js/commit/c6ca5a83e7b72613f95c2145606a1330f64ae894)) +- **BaseMessageOptions:** Fix embeds and components (#9437) ([5c52bb9](https://github.com/discordjs/discord.js/commit/5c52bb95906250518a8813820d543f43dd7abdf9)) +- **InteractionResponses:** ShowModal docs change (#9434) ([7d34100](https://github.com/discordjs/discord.js/commit/7d341000d44b762a2fe0434a6b518f7d63539d34)) +- Use ESM code in examples (#9427) ([ce287f2](https://github.com/discordjs/discord.js/commit/ce287f21d1540da7f17cac8a57dc33a67f391ef3)) +- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9)) +- **Options:** Fix links and invalid syntax (#9322) ([86e5f5a](https://github.com/discordjs/discord.js/commit/86e5f5a119c6d2588b988a33236d358ded357847)) +- Cleanup MessageCreateOptions and MessageReplyOptions (#9283) ([300059c](https://github.com/discordjs/discord.js/commit/300059cb266e6cca42c30ee7f997c48ab2cc565e)) +- **Events:** Document auto moderation events (#9342) ([79bcdfa](https://github.com/discordjs/discord.js/commit/79bcdfa767e7e842164e1174b6f4834ed731d329)) +- Add `SnowflakeUtil` (#9371) ([8ffcf77](https://github.com/discordjs/discord.js/commit/8ffcf77840b62590fcb4731380d28b22d0b98741)) +- Use stable tag (#9343) ([c0f2dd7](https://github.com/discordjs/discord.js/commit/c0f2dd713151a29c98e1eebad66721a208be1fc0)) +- Remove `JSONEncondable` (#9344) ([b2eec5f](https://github.com/discordjs/discord.js/commit/b2eec5f9fcf37ebb3b7f87a67a6ee3160c182183)) + +## Features + +- **Attachment:** Voice messages (#9392) ([3e01f91](https://github.com/discordjs/discord.js/commit/3e01f91bbba2cbacacc6c921ed664752f679960b)) +- **BaseInteraction:** Support new channel payload (#9337) ([29389e3](https://github.com/discordjs/discord.js/commit/29389e39f479b832e54c7cb3ddd363aebe99674f)) +- **RoleTagData:** Add guildConnections (#9366) ([2dddbe1](https://github.com/discordjs/discord.js/commit/2dddbe1f321f2e2722dba4a28f7d18384cf50353)) + +## Performance + +- **RoleManager:** Dont call Role#position getter twice per role (#9352) ([bfee6c8](https://github.com/discordjs/discord.js/commit/bfee6c8d889502ea39ad919dd9b1e6253a2af571)) + +## Refactor + +- **WebSocketManager:** Use /ws package internally (#9099) ([a9e0de4](https://github.com/discordjs/discord.js/commit/a9e0de4288ea39a6a089b8379dcd44ac0053dac7)) +- Remove `fromInteraction` in internal channel creation (#9335) ([794abe8](https://github.com/discordjs/discord.js/commit/794abe8450bae000cd0544922cdf53e7b3e4c59c)) + +## Typings + +- **AutoModerationActionMetadataOptions:** Make channel property optional (#9460) ([d26df5f](https://github.com/discordjs/discord.js/commit/d26df5fabaf227fb9d10ba5cc1ab326de55aadbc)) +- **CategoryChannel:** Ensure `parent` and `parentId` are `null` (#9327) ([8218ffc](https://github.com/discordjs/discord.js/commit/8218ffc78d23234b32c05a97fde2f4bea64d7aa6)) +- **GuildTextBasedChannel:** Remove unnecessary exclusion of forum channels (#9326) ([7ff3d52](https://github.com/discordjs/discord.js/commit/7ff3d528d942a0daa990194915ff8328dec99149)) + +# [14.9.0](https://github.com/discordjs/discord.js/compare/14.8.0...14.9.0) - (2023-04-01) + +## Bug Fixes + +- Add support for new guild feature `GUILD_WEB_PAGE_VANITY_URL` (#9219) ([de1aac6](https://github.com/discordjs/discord.js/commit/de1aac674acb3830124646fcd52cdd98cdb71ba5)) +- Resolving string bitfield (#9262) ([7987565](https://github.com/discordjs/discord.js/commit/79875658cf4a8daa25210c2c620c73a710ca22de)) +- **AutocompleteInteraction:** Send `name_localizations` correctly (#9238) ([1864d37](https://github.com/discordjs/discord.js/commit/1864d37d36e53d127e74b6969a5f542193bfc3c7)) +- Keep symbols in actions manager (#9293) ([984bd55](https://github.com/discordjs/discord.js/commit/984bd55b437507e7ebfdf09ac944c8eba0340d27)) +- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b)) +- **ClientUser:** No mutation on edit (#9259) ([abd6ae9](https://github.com/discordjs/discord.js/commit/abd6ae9fc8ea03722e8b36e29c3fdc1c2cfc93e8)) +- **Message#editable:** Update editable check in threads locked (#9216) ([22e880a](https://github.com/discordjs/discord.js/commit/22e880aaa0d8c644fc8d16a524d17f4f53a056f6)) +- **ThreadManager:** Add `members` and conditionally include `hasMore` (#9164) ([e9a8eb3](https://github.com/discordjs/discord.js/commit/e9a8eb323f3a554dc8f9dab361cd1bac7b88e1cc)) +- **ThreadManager:** Respect `cache` and `force` in fetching (#9239) ([cc57563](https://github.com/discordjs/discord.js/commit/cc57563e73d78a0d71d1444d1ee8215a26a81fa8)) +- **TextBasedChannelTypes:** Add `GuildStageVoice` (#9232) ([51edba7](https://github.com/discordjs/discord.js/commit/51edba78bc4d4cb44b4dd2b79e4bbc515dc46f5b)) + +## Documentation + +- Describe private properties (#8879) ([2792e48](https://github.com/discordjs/discord.js/commit/2792e48119f1cf5fa7d5e6b63369457b0719d4e4)) +- Differ `User#send` (#9251) ([384b4d1](https://github.com/discordjs/discord.js/commit/384b4d10e8642f0f280ea1651f33cd378c341333)) +- Fix compare position example (#9272) ([d16114c](https://github.com/discordjs/discord.js/commit/d16114c52646ca92c53f9b44a0dd10af98dbddcd)) +- **Role:** Fix example for `comparePositionTo()` (#9270) ([bc641fa](https://github.com/discordjs/discord.js/commit/bc641fa9360b851642bc51839cef6bd5600d71f7)) +- Add more examples (#9252) ([bf507ab](https://github.com/discordjs/discord.js/commit/bf507ab2659d95e2991e83293b3834f21283ff33)) +- **FetchArchivedThreadOptions:** `before` respects `archive_timestamp`, not creation timestamp (#9240) ([178c8dc](https://github.com/discordjs/discord.js/commit/178c8dcfeea1c4a6a32835baea389f25feefbac7)) +- Update `APISelectMenuComponent` (#9235) ([56cf138](https://github.com/discordjs/discord.js/commit/56cf138e029e7884a4e7efb606055687ca67b4ac)) + +## Features + +- **Guild:** Add `max_stage_video_channel_users` (#8422) ([34bc36a](https://github.com/discordjs/discord.js/commit/34bc36ac4b04ad033d0dcc3d2701fcf2e682743c)) +- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b)) +- Add GuildBasedTextChannelTypes (#9234) ([5f93dcc](https://github.com/discordjs/discord.js/commit/5f93dcce466286f0fdead8faf4131e98d1c9db55)) + +## Refactor + +- Call `GuildBanManager#create()` directly (#9263) ([f340f3b](https://github.com/discordjs/discord.js/commit/f340f3b1fd719e8f7cf6fa28a41835bc16039fc7)) +- **FetchThreadsOptions:** Remove `active` (#9241) ([519e163](https://github.com/discordjs/discord.js/commit/519e163f8aa3b55420f86d2d60c2584b3a2eb327)) + +# [14.8.0](https://github.com/discordjs/discord.js/compare/14.7.1...14.8.0) - (2023-03-12) + +## Bug Fixes + +- **snowflake:** Snowflakes length (#9144) ([955e8fe](https://github.com/discordjs/discord.js/commit/955e8fe312c42ad4937cc1994d1d81e517c413c8)) +- **Actions:** Inject built data by using a symbol (#9203) ([a63ac88](https://github.com/discordjs/discord.js/commit/a63ac88fcca5b61209892a6e560e35d58f5adc3b)) +- **Message#deletable:** Add check for deletable message types (#9168) ([e78b8ad](https://github.com/discordjs/discord.js/commit/e78b8ad3fb6692cba2c565b508254c723f185f0c)) +- **Message:** `bulkDeletable` permissions should be retrieved later for DMs (#9146) ([a9495bd](https://github.com/discordjs/discord.js/commit/a9495bd8f014c8021a214b83ffc531a2af5defef)) +- **AutoModerationActionExecution:** Transform `action` (#9111) ([9156a28](https://github.com/discordjs/discord.js/commit/9156a2889cd0946dfd0b30a5f8365abfbc377b3d)) +- **MessageReaction:** `toJSON()` infinite recursion (#9070) ([f268e1d](https://github.com/discordjs/discord.js/commit/f268e1d9798744e169ae87089ea2e1f214364d95)) +- **ThreadChannel:** Insert starter message from threads created in forum channels (#9100) ([0b76ab4](https://github.com/discordjs/discord.js/commit/0b76ab4c403dd646c71482856ab993b263b7c474)) +- **ApplicationRoleConnectionMetadata:** Export the class correctly (#9076) ([071516c](https://github.com/discordjs/discord.js/commit/071516c35239bd4e1cae572c855d86b335c8536d)) +- Don't auth for interaction `showModal()` (#9046) ([b803a9a](https://github.com/discordjs/discord.js/commit/b803a9a899aaa75a3ea2bc6623c6afb28f495e8c)) +- **WebSocketShard:** Zombie connection fix (#8989) ([876b181](https://github.com/discordjs/discord.js/commit/876b1813128ec702d3ef1e7b0074a4613e88c332)) +- Keep other properties in triggerMetadata (#8977) ([d8dd197](https://github.com/discordjs/discord.js/commit/d8dd197a936dfffc05f9e5bc3184ec9022c56b51)) +- **escapeX:** Emojis with underlines (#8945) ([07b597d](https://github.com/discordjs/discord.js/commit/07b597df16b9412c23ec2387d54564e4d1bcf7ed)) +- **WebSocketShard:** Either start close timeout or emit destroyed but never both (#8956) ([43ce2a5](https://github.com/discordjs/discord.js/commit/43ce2a572eb8977b6994680171ac0c5f9bda1703)) +- **DMChannel:** `recipientId` edge case (#8950) ([7ce9909](https://github.com/discordjs/discord.js/commit/7ce990954e2f73d7a996df0afa42ab287cb12514)) +- Return only boolean for `disabled` (#8965) ([6614603](https://github.com/discordjs/discord.js/commit/66146033268a4db1279b2eaee4bd418f326c0d4b)) +- Export missing `escapeX()` functions (#8944) ([25c27ea](https://github.com/discordjs/discord.js/commit/25c27eac1417e75c9b601b17cf177b1f47b699a9)) +- **WebSocketShard:** Only cleanup the connection if a connection still exists (#8946) ([5eab5fc](https://github.com/discordjs/discord.js/commit/5eab5fc06ca6be36ecf1557f2ad29a670d4d5ae7)) +- Add `@discordjs/formatters` to dependency list (#8939) ([18b3a19](https://github.com/discordjs/discord.js/commit/18b3a19810a6436fa8bb4b490ec5137eaecbd465)) +- **resolveColor:** Invalid colors (#8933) ([c76e170](https://github.com/discordjs/discord.js/commit/c76e17078602914c3e1d227a3acc98eaa99c18d4)) +- **WebSocketShard:** Clear listeners on reconnect (#8927) ([aa8c57d](https://github.com/discordjs/discord.js/commit/aa8c57dab60104549e28451abf35c0387595d67e)) +- Re-export formatters (#8909) ([b14604a](https://github.com/discordjs/discord.js/commit/b14604abdecca575b1fca693c1593e3585bcca8c)) + +## Documentation + +- **MessageManager:** Add clarification to fetch messages (#9222) ([f5ec1ca](https://github.com/discordjs/discord.js/commit/f5ec1cada5ebf0ca4093bdfc81aaf56900c794ef)) +- Make interactionResponse as optional (#9179) ([664cccb](https://github.com/discordjs/discord.js/commit/664cccb2706db33635aa2556954de57f93b3d3db)) +- Fix typos (#9127) ([1ba1f23](https://github.com/discordjs/discord.js/commit/1ba1f238f04221ec890fc921678909b5b7d92c26)) +- **chatInputApplicationCommandMention:** Parameters are not nullable (#9091) ([6f78e82](https://github.com/discordjs/discord.js/commit/6f78e8285b3ce762de010e68d49b377a47dc5a63)) +- No `@type` description and reveal info block (#9097) ([405f940](https://github.com/discordjs/discord.js/commit/405f9400e8e3ffea9f3847ab5abb431a34538a96)) +- **ThreadEditOptions:** Move info tag back to `invitable` (#9020) ([f3fe3ce](https://github.com/discordjs/discord.js/commit/f3fe3ced622676b406a62b43f085aedde7a621aa)) +- Fix a typo in the MentionableSelectMenuInteraction link (#9000) ([6d7a143](https://github.com/discordjs/discord.js/commit/6d7a143667f33ef2ea45d8016ac4738237707881)) +- **ApplicationRoleConnectionMetadata:** Add documentation (#8976) ([2e22b31](https://github.com/discordjs/discord.js/commit/2e22b31892d9b858fcb24fa580b486b4154e823f)) +- Fix malformed overridden documentation (#8954) ([0b8b114](https://github.com/discordjs/discord.js/commit/0b8b114761f961a2bf8e5aae342ed711b154a89e)) +- **GuildForumThreadManager:** Fix `sticker` type (#8940) ([dd62be0](https://github.com/discordjs/discord.js/commit/dd62be077d3e4fbd73a0c10ca344d93d3d19fa38)) +- Fix deprecated links (#8907) ([976b234](https://github.com/discordjs/discord.js/commit/976b234e9dc9999e5dee47b58c85afbc1cd494c2)) +- **UserFlagsBitField:** Make `.Flags` static (#8902) ([c48ff5e](https://github.com/discordjs/discord.js/commit/c48ff5e4205899e3b6cd35812ca857236bef6864)) + +## Features + +- **Collector:** Add lastCollectedTimestamp (#9044) ([4458a13](https://github.com/discordjs/discord.js/commit/4458a13925164762b519ded1037ae8775d879f71)) +- **StageChannel:** Add messages (#9134) ([ffdb197](https://github.com/discordjs/discord.js/commit/ffdb197f988657100e2a9ff0ca17b759339a1dda)) +- **AutoModerationActionExecution:** Add `channel`, `user` and `member` getters (#9142) ([095bd77](https://github.com/discordjs/discord.js/commit/095bd77515aa31bb0e95a350b4355980fea9268d)) +- **AutoModeration:** Support `custom_message` (#9171) ([c1000b8](https://github.com/discordjs/discord.js/commit/c1000b86ed6d5413afcd6ee7e80505e5a845430b)) +- **ThreadMemberManager:** Support pagination fetching (#9035) ([765d5a3](https://github.com/discordjs/discord.js/commit/765d5a3b2d5529c3a2a4b29512f6932264443ed1)) +- **InteractionResponse:** Add new methods (#9132) ([dc9924f](https://github.com/discordjs/discord.js/commit/dc9924fb5f24c8dac963d6b86ba279a89545e73b)) +- **GuildMember:** Add `flags` (#9087) ([76b2116](https://github.com/discordjs/discord.js/commit/76b21162aca7cd4897826437da3063524e1e7553)) +- **Client:** `guildAuditLogEntryCreate` event (#9058) ([9439107](https://github.com/discordjs/discord.js/commit/9439107a1d6a9b77b5f991973d96bc6100da4753)) +- Add role subscription data (#9025) ([1ba22f4](https://github.com/discordjs/discord.js/commit/1ba22f4c9e4173f8866339d3eadb2939d4b32034)) +- **Sticker:** Add support for gif stickers (#9038) ([6a9875d](https://github.com/discordjs/discord.js/commit/6a9875da054a875a4711394547d47439bbe66fb6)) +- **GuildAuditLogs:** Support `after` (#9011) ([0076589](https://github.com/discordjs/discord.js/commit/0076589ccc93e09d77a448874d1ceff5d0e91aa2)) +- Add role subscriptions (#8915) ([3407e1e](https://github.com/discordjs/discord.js/commit/3407e1eea3c8d5629465553f342ac30ceae27a47)) +- Add `not_found` to guild member chunk data (#8975) ([be294ea](https://github.com/discordjs/discord.js/commit/be294eaf9901ea139ce485deeec9178959ffa91f)) +- **ClientApplication:** Add role connections (#8855) ([22e2bbb](https://github.com/discordjs/discord.js/commit/22e2bbb0d24e3f30516f262308d5786f2f666713)) +- **CommandInteractionOptionResolver:** Add `channelTypes` option to `getChannel` (#8934) ([429dbcc](https://github.com/discordjs/discord.js/commit/429dbccc85cabd9986b2e8bf443bf384e4ddc61a)) +- **ForumChannel:** Add `defaultForumLayout` (#8895) ([cbafd47](https://github.com/discordjs/discord.js/commit/cbafd479b331633ed97f7b1a22ef03c6a2f4cf31)) +- Add support for nsfw commands (#7976) ([7a51344](https://github.com/discordjs/discord.js/commit/7a5134459c5f06864bf74631d83b96d9c21b72d8)) +- **InteractionResponse:** CreatedTimestamp (#8917) ([627511d](https://github.com/discordjs/discord.js/commit/627511d6522f772b84c25e6a3f6da06b06bb912e)) +- **Guild:** Add disableInvites method (#8801) ([45faa19](https://github.com/discordjs/discord.js/commit/45faa199820e7c4ccdb2997c7e3b353f566d2312)) + +## Refactor + +- Compare with `undefined` directly (#9191) ([869153c](https://github.com/discordjs/discord.js/commit/869153c3fdf155783e7c0ecebd3627b087c3a026)) +- **GuildMemberManager:** Tidy up fetching guild members (#8972) ([4e0e125](https://github.com/discordjs/discord.js/commit/4e0e1250399aa12c340ac92a86ec2c05704fe2bb)) +- **BitField:** Reverse iterator/toArray responsibilities (#9118) ([f70df91](https://github.com/discordjs/discord.js/commit/f70df910ed12e397066d0bdb27343af21ead4d92)) +- Moved the escapeX functions from discord.js to @discord.js/formatters (#8957) ([13ce78a](https://github.com/discordjs/discord.js/commit/13ce78af6e3aedc793f53a099a6a615df44311f7)) +- Use `deprecate()` directly (#9026) ([1c871b5](https://github.com/discordjs/discord.js/commit/1c871b5b576dddef12c5afacecf416dbd6243dea)) +- **Guild:** Destructure object in guild editing (#8971) ([d3e9f2a](https://github.com/discordjs/discord.js/commit/d3e9f2a355a1f5272d62a507eb6ecd8808904fff)) +- **GuildManager:** Better handling of creation code (#8974) ([d7a09f6](https://github.com/discordjs/discord.js/commit/d7a09f6fcee30c31b4418166bf7bf9e894841f87)) +- **sharding:** Use switch statement (#8928) ([6540914](https://github.com/discordjs/discord.js/commit/6540914b4a7f244f5e40fe2a3b7e73986763d81b)) +- Use consistent naming for options (#8901) ([a7b55c1](https://github.com/discordjs/discord.js/commit/a7b55c1460cf63fb482f7d05657120eec96bee82)) +- **CommandInteractionOptionResolver:** Loosen mentionable checks (#8910) ([1b151db](https://github.com/discordjs/discord.js/commit/1b151db59c4340417f8a28a88064f45336ac8c78)) + +## Styling + +- Run prettier (#9041) ([2798ba1](https://github.com/discordjs/discord.js/commit/2798ba1eb3d734f0cf2eeccd2e16cfba6804873b)) + +## Typings + +- Allow sending messages with `SuppressNotifications` flag (#9177) ([71a427f](https://github.com/discordjs/discord.js/commit/71a427f6322be76fe2d1cb265de09f171b1b354a)) +- Remove `EscapeMarkdownOptions` (#9153) ([fd0246c](https://github.com/discordjs/discord.js/commit/fd0246ca4c75e60d8e117d9ac5af7067c7a63277)) +- **Attachment:** Make `attachment` private (#8982) ([da23cd5](https://github.com/discordjs/discord.js/commit/da23cd5d69de4856d075f00738f75c68c555ae5b)) +- Fix type of Attachment#name (#9101) ([4e0a89f](https://github.com/discordjs/discord.js/commit/4e0a89f58f43f362bfde80d8319dce767c62850f)) +- Allow builders to set channel types in discord.js (#8990) ([7dec892](https://github.com/discordjs/discord.js/commit/7dec892218f7b470a5f8e78732a524a53da24d26)) +- Swap message reaction and emoji identifier types (#8969) ([ad49845](https://github.com/discordjs/discord.js/commit/ad4984526020f2baeefaeeebbded66c6848c4b85)) +- **widget:** Add missing `name` (#8978) ([898b5ac](https://github.com/discordjs/discord.js/commit/898b5ac416cbbb415b125bb27221d0901fdd180e)) +- Use StringSelectMenuOptionBuilder (#8949) ([bec51de](https://github.com/discordjs/discord.js/commit/bec51de1038c35c6edaaa13934781758fe1951de)) +- Fix actions type in automod (#8962) ([5915f39](https://github.com/discordjs/discord.js/commit/5915f39810b712c05a46fa21ab4e12b4cfa3c25a)) +- Subcommand group `options` is required (#8966) ([5dc5e90](https://github.com/discordjs/discord.js/commit/5dc5e902688fc563087cd5061dcb59dd68fd4eda)) +- Add generic to `ActionRowBuilder.from()` (#8414) ([153352a](https://github.com/discordjs/discord.js/commit/153352ad7a1ccb4a9461523cf2597d81df93b69c)) + +# [14.7.1](https://github.com/discordjs/discord.js/compare/14.7.0...14.7.1) - (2022-12-01) + +## Bug Fixes + +- Prevent crash on no select menu option (#8881) ([11d195d](https://github.com/discordjs/discord.js/commit/11d195d04ff57d51adb0f0d3a0a7342f9e34aba0)) + +# [14.7.0](https://github.com/discordjs/discord.js/compare/14.6.0...14.7.0) - (2022-11-28) + +## Bug Fixes + +- **MessageMentions:** Add `InGuild` generic (#8828) ([f982803](https://github.com/discordjs/discord.js/commit/f9828034cd21e6f702762a46923e0f42115596f6)) +- **Activity:** Fix equals() not checking for differing emoji (#8841) ([7e06f68](https://github.com/discordjs/discord.js/commit/7e06f68185423ba7cb310220b213f445b6571e29)) +- Fixed react/astro/guide/discord.js build, updated dependencies, fix crawlvatar (#8861) ([d0c8256](https://github.com/discordjs/discord.js/commit/d0c82561b8a1765a1daa362ca903f3ffb3fa33ee)) +- **escapeMarkdown:** Fix double escaping (#8798) ([d6873b7](https://github.com/discordjs/discord.js/commit/d6873b7159352479475b3a0daa215bddbdd3a79b)) +- **Transfomers:** Call `.toJSON` in `toSnakeCase` (#8790) ([017f9b1](https://github.com/discordjs/discord.js/commit/017f9b1ed4014dc1db0b78c1a77e463b4403de5d)) +- Censor token in debug output (#8764) ([53d8e87](https://github.com/discordjs/discord.js/commit/53d8e87d7f3a329608250656950bd0a200adb1c7)) +- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4)) + +## Documentation + +- Describe InteractionEditReplyOptions (#8840) ([cb77fd0](https://github.com/discordjs/discord.js/commit/cb77fd02d083438de2aff6f0769baf7d1797bc65)) +- **AutoModerationRuleManager:** Describe cache (#8848) ([d275480](https://github.com/discordjs/discord.js/commit/d2754802cc3479e6288cdbfcd48c76bf57e09a07)) +- Fix message action row components (#8819) ([65bc0ad](https://github.com/discordjs/discord.js/commit/65bc0adbf4d7870d33b92585ca18f964f24bc84e)) +- Specify `ActionRowBuilder` for `components` (#8834) ([8ed5c1b](https://github.com/discordjs/discord.js/commit/8ed5c1beb622f71ce0bd89e4cbeff50e464da8fe)) +- Add `@extends` for select menu classes (#8824) ([09f65b7](https://github.com/discordjs/discord.js/commit/09f65b724b0d2f36bbe89b83570c0d18093b5126)) +- Make WebSocketShard.lastPingTimestamp public (#8768) ([68c9cb3](https://github.com/discordjs/discord.js/commit/68c9cb37bc3df6326b720291827ea477e421faf2)) +- **MessageReplyOptions:** Remove duplicate stickers field (#8766) ([6e348ff](https://github.com/discordjs/discord.js/commit/6e348ffd1d8db8d8ad2da7823460814695e01a43)) + +## Features + +- **Webhook:** Add `channel` property (#8812) ([decbce4](https://github.com/discordjs/discord.js/commit/decbce401062af75f633e6acacc88207b115a719)) +- Auto Moderation (#7938) ([fd4ba5e](https://github.com/discordjs/discord.js/commit/fd4ba5eaba66898699127fc0d5f0ab52c18e3db0)) +- **SelectMenuInteractions:** Add `values` property (#8805) ([b2fabd1](https://github.com/discordjs/discord.js/commit/b2fabd130a76ea54cfbfa1b871ef8659513c2c7a)) +- **ThreadChannel:** Add a helper for pin and unpin (#8786) ([e74aa7f](https://github.com/discordjs/discord.js/commit/e74aa7f6b0fe04e3473fc4a62a73a7db87307685)) +- Add `Message#bulkDeletable` (#8760) ([ff85481](https://github.com/discordjs/discord.js/commit/ff85481d3e7cd6f7c5e38edbe43b27b104e82fba)) +- New select menus (#8793) ([5152abf](https://github.com/discordjs/discord.js/commit/5152abf7285581abf7689e9050fdc56c4abb1e2b)) +- **InteractionResponses:** Add message parameter (#8773) ([8b400ca](https://github.com/discordjs/discord.js/commit/8b400ca975c6bad00060b9c67068f42bd53524ba)) +- Support resume urls (#8784) ([88cd9d9](https://github.com/discordjs/discord.js/commit/88cd9d906074eb79e85df0ef49287f11133d2e0d)) +- Allow deletion of ephemeral messages (#8774) ([fc10774](https://github.com/discordjs/discord.js/commit/fc107744618857bf28c2167f204253baf690ede8)) +- **GuildChannelManager:** Add `.addFollower()` method (#8567) ([caeb1cb](https://github.com/discordjs/discord.js/commit/caeb1cbfdb2f2f007252c4d7e9f47a575c24bcb5)) + +## Refactor + +- **Embed:** Use `embedLength` function from builders (#8735) ([cb3826c](https://github.com/discordjs/discord.js/commit/cb3826ce6dbcd3cf7ab639af6cdfcea80336aa1d)) + +# [14.6.0](https://github.com/discordjs/discord.js/compare/14.5.0...14.6.0) - (2022-10-10) + +## Bug Fixes + +- **ClientOptions:** Make `ClientOptions#intents` returns an IntentsBitField (#8617) ([4c2955a](https://github.com/discordjs/discord.js/commit/4c2955a5de6779c29c09e63ba9ad2b235904f842)) +- Correctly construct a builder (#8727) ([e548e6a](https://github.com/discordjs/discord.js/commit/e548e6a10b7e1720f5e8f3c859b0b64d5134a012)) +- **Components:** Error with unknown components (#8724) ([6fd331d](https://github.com/discordjs/discord.js/commit/6fd331dd528e78fd023c908bd58af3faa9ed6c65)) +- **Client:** Don't auth for webhook fetches with token (#8709) ([01d75c8](https://github.com/discordjs/discord.js/commit/01d75c8b8b14f33c95a4da83a8494db848beeb8c)) +- Re-export util (#8699) ([a306219](https://github.com/discordjs/discord.js/commit/a306219673335584accd2ff77ab34d2812ef6c5d)) +- Throw discord.js errors correctly (#8697) ([ace974f](https://github.com/discordjs/discord.js/commit/ace974fc1fdbc5bcaa0d7f6f6d17de185c9f9cbf)) + +## Documentation + +- **Utils:** Remove `private` from `parseEmoji` (#8718) ([a31e605](https://github.com/discordjs/discord.js/commit/a31e605e09064a300e31a3c91466b613654ba98e)) +- Update UserContextMenuCommandInteraction documentation (#8717) ([7556db2](https://github.com/discordjs/discord.js/commit/7556db243d9480949835668fcb5724fdd5d70e08)) +- Fix `AwaitMessageComponentOptions` typedef (#8696) ([9effd82](https://github.com/discordjs/discord.js/commit/9effd82abe82ba71ae627673da21ba07e1ede23e)) + +## Features + +- **Util:** Escape more markdown characters (#8701) ([7b8966b](https://github.com/discordjs/discord.js/commit/7b8966bca156db79933403289741893a6e10ccd5)) +- **GuildChannelManager:** Allow creating channels with a default auto archive duration (#8693) ([628759b](https://github.com/discordjs/discord.js/commit/628759bcff8b0d4c77926cee2b8c18d8fdb4c260)) +- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3)) +- **ForumChannel:** Add `defaultSortOrder` (#8633) ([883f6e9](https://github.com/discordjs/discord.js/commit/883f6e9202a559c986f4b15fccb422b5aea7bea8)) + +## Refactor + +- Rename Error to DiscordjsError internally (#8706) ([aec44a0](https://github.com/discordjs/discord.js/commit/aec44a0c93f620b22242f35e626d817e831fc8cb)) + +## Typings + +- Fix events augmentation (#8681) ([ac83ada](https://github.com/discordjs/discord.js/commit/ac83ada306ec153c13260d2bd53e4d704884b68a)) +- **Message:** Remove `& this` from `#inGuild` typeguard (#8704) ([c0f7a1a](https://github.com/discordjs/discord.js/commit/c0f7a1a89a4cf62edc7065bd200b2ce4018e0a27)) +- **ModalBuilder:** Fix constructor typings (#8690) ([2ea2a85](https://github.com/discordjs/discord.js/commit/2ea2a85e6335d57f44689f9b6e284129104de8fc)) + +# [14.5.0](https://github.com/discordjs/discord.js/compare/14.4.0...14.5.0) - (2022-09-25) + +## Bug Fixes + +- **ThreadChannel:** Add forum channel to parent (#8664) ([0126d9b](https://github.com/discordjs/discord.js/commit/0126d9b810a156c4bf1b8b93f2121f3319855bac)) +- **GuildChannelManager:** Allow creating webhooks on forums (#8661) ([16fcdc3](https://github.com/discordjs/discord.js/commit/16fcdc36877d1a65ce9995c9fe3502aa268c9388)) +- **ForumChannel:** Implement missing properties and methods (#8662) ([8622939](https://github.com/discordjs/discord.js/commit/862293922924f453f69b0b0f8efe87ddebbd387d)) +- RepliableInteraction respect cached generic (#8667) ([578bc95](https://github.com/discordjs/discord.js/commit/578bc951bdcdc21ec5aee86e7a47a17e8c867dfc)) +- **ThreadChannel:** Allow editing flags (#8671) ([1244854](https://github.com/discordjs/discord.js/commit/1244854e1365d7e4a8d01703a7ec13610ed100c7)) +- **GuildChannelManager:** Typo in `flags` property name when editing (#8669) ([fc8ed81](https://github.com/discordjs/discord.js/commit/fc8ed816e643754a938211a17b41a2cec95df265)) + +## Documentation + +- Fix duplicate typedefs (#8677) ([d79aa2d](https://github.com/discordjs/discord.js/commit/d79aa2d0d0b186bd28cbfc82f3d6ecf3deb41c50)) +- **ForumChannel:** Add `@implements` (#8678) ([8ca407e](https://github.com/discordjs/discord.js/commit/8ca407e089c3050b61a51a52b9100e4613ad1666)) + +## Features + +- **GuildChannelManager:** Allow editing `flags` (#8637) ([abb7226](https://github.com/discordjs/discord.js/commit/abb7226af3445f5b724815bb2f7a121a52a563b5)) + +## Refactor + +- **GuildBanManager:** Add deprecation warning for `deleteMessageDays` (#8659) ([e993122](https://github.com/discordjs/discord.js/commit/e9931229ae62a120ae0761ee2a2c10ea0cb1a6fb)) + +## Typings + +- **GuildChannelManager:** Handle forum channel overload (#8660) ([1486bc9](https://github.com/discordjs/discord.js/commit/1486bc9336369d229972df5e28b9428365b92bff)) +- **Caches:** Allow `GuildForumThreadManager` and `GuildTextThreadManager` (#8665) ([2487e3b](https://github.com/discordjs/discord.js/commit/2487e3bf76260a4a2fbf375e0b01a43f347922a3)) + +# [14.4.0](https://github.com/discordjs/discord.js/compare/14.3.0...14.4.0) - (2022-09-21) + +## Bug Fixes + +- Correct applied tags type (#8641) ([f6f15d8](https://github.com/discordjs/discord.js/commit/f6f15d8e877d4ffbe908a093e64809ef9015e0ff)) +- **ThreadChannel:** Make `fetchStarterMessage()` work in forum posts (#8638) ([a7f816e](https://github.com/discordjs/discord.js/commit/a7f816eeb7fa1e193cf0901efbdcaf629f72465f)) +- Update `messageCount`/`totalMessageSent` on message events (#8635) ([145eb2f](https://github.com/discordjs/discord.js/commit/145eb2fc5db5ca739aa9782d5ec5210f81a6aeeb)) +- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9)) + +## Documentation + +- Correctly overwrite `setRTCRegion` method (#8642) ([f049734](https://github.com/discordjs/discord.js/commit/f0497343f1193635b260b9e2085cac7b43991f74)) +- **GuildTextThreadManager:** Document correct `@extend` (#8639) ([802b239](https://github.com/discordjs/discord.js/commit/802b2394b08151faab6810695fd5c8f27ce84d58)) +- Fix regexps incorrectly being called global (#8624) ([fc9653f](https://github.com/discordjs/discord.js/commit/fc9653f5aea4013da15fb8de0a4452400eaa7739)) +- Update misleading `Client#guildMemberAvailable` event description (#8626) ([22ac6b4](https://github.com/discordjs/discord.js/commit/22ac6b4660db6b02f62b9851e9e3bcfe5fb506b5)) +- **Options:** Update DefaultMakeCacheSettings (#8585) ([3252332](https://github.com/discordjs/discord.js/commit/32523325c6610e95fe3ffcc31d005b3418c6bc68)) +- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0)) + +## Features + +- **Widget:** Allow forum channels (#8645) ([b106956](https://github.com/discordjs/discord.js/commit/b1069563086fc616fe21abb789f28f69e57c8851)) +- **WelcomeChannel:** Add forum channel as a type (#8643) ([6f1f465](https://github.com/discordjs/discord.js/commit/6f1f465a77e362e20ec50067be0e634d35946ba5)) +- Allow forum channels in webhook update event (#8646) ([5048a3d](https://github.com/discordjs/discord.js/commit/5048a3d17ace22336e74451d30b513b3db42a26f)) +- Add support for guild forums (#7791) ([8a8d519](https://github.com/discordjs/discord.js/commit/8a8d519c9c4c082370fc6935b56dafb525b873df)) +- **GuildBanManager#create:** Add `deleteMessageSeconds` (#8326) ([03fb5b0](https://github.com/discordjs/discord.js/commit/03fb5b0a2f45275dec7885175ad691a1d9c449c4)) +- Add typeguard to BaseInteraction#isRepliable (#8565) ([55c3ee2](https://github.com/discordjs/discord.js/commit/55c3ee20ae700e78d18a3c4c04b6a7426cffc060)) +- **Integration:** Add `scopes` (#8483) ([8b3d006](https://github.com/discordjs/discord.js/commit/8b3d0061180cfd5d9ba8beae3e8d623b5ce43ea4)) +- Add `chatInputApplicationCommandMention` formatter (#8546) ([d08a57c](https://github.com/discordjs/discord.js/commit/d08a57cadd9d69a734077cc1902d931ab10336db)) + +## Refactor + +- Replace usage of deprecated `ChannelType`s (#8625) ([669c3cd](https://github.com/discordjs/discord.js/commit/669c3cd2566eac68ef38ab522dd6378ba761e8b3)) +- Split message send/edit types/documentation (#8590) ([8e1afae](https://github.com/discordjs/discord.js/commit/8e1afaebdb686033555ca58e53f34bb97f7369c8)) +- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67)) + +## Typings + +- Narrow channel type in thread managers (#8640) ([14bbc91](https://github.com/discordjs/discord.js/commit/14bbc9150a748e7ac1660c2375c7f065fcc55a6c)) +- **interactions:** Pass `Cached` type to return type of methods (#8619) ([053da5b](https://github.com/discordjs/discord.js/commit/053da5bc91d5cfa8d842b13b0b05083d2f7f086d)) +- Ensure events possess `Client<true>` (#8612) ([a9f003a](https://github.com/discordjs/discord.js/commit/a9f003ac9b56d31166cbf353d02140dad0b2517e)) +- **GuildChannelManager:** Correct `fetch` return type (#8549) ([1d4cdee](https://github.com/discordjs/discord.js/commit/1d4cdee321ab25bb0f109d55a000582825dd79f9)) +- **ThreadChannel:** `fetchStarterMessage` must return a `Message<true>` (#8560) ([b9c62ac](https://github.com/discordjs/discord.js/commit/b9c62ac0f0f534c33f9913135095f8b3d98ec05e)) +- **webhook:** Avatar can be null (#8541) ([f77612a](https://github.com/discordjs/discord.js/commit/f77612a55e9c593a21bc27e58c9fbd03d85787e3)) + +# [14.3.0](https://github.com/discordjs/discord.js/compare/14.2.0...14.3.0) - (2022-08-22) + +## Bug Fixes + +- **GuildMemberManager:** `add()` method throws an error (#8539) ([3bef901](https://github.com/discordjs/discord.js/commit/3bef9018c0be3c5dc51d03b796d08b925dc4e1b9)) +- **Guild:** Widget channel types and fixes (#8530) ([23a0b6c](https://github.com/discordjs/discord.js/commit/23a0b6ccf27410963bd4f5c53d9ee2ce019e90a8)) +- **Embed:** Reference video in video (#8473) ([c97977a](https://github.com/discordjs/discord.js/commit/c97977a3e806bd5d8682bc7fb22ebec1a8ceecdc)) + +## Documentation + +- **GuildAuditLogsEntry:** Correct `action` wording (#8499) ([7d25072](https://github.com/discordjs/discord.js/commit/7d2507279cc9d1397c7d61e7c7b856ff4bc17c86)) + +## Features + +- **GuildMemberManager:** AddRole and removeRole (#8510) ([cda3f00](https://github.com/discordjs/discord.js/commit/cda3f005b1546fdb8410e9550526956f840857fc)) +- Deprecate `ActionRow.from()` (#8504) ([f9c25dd](https://github.com/discordjs/discord.js/commit/f9c25ddcfe68f089e13f1090c3df4bd7cd74d2b7)) +- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166)) + +## Refactor + +- **GuildAuditLogsEntry:** Remove `guild` from application command permission update extra (#8520) ([2b8074d](https://github.com/discordjs/discord.js/commit/2b8074dd12f2f1e957caffb57e5fd4d7be88dc25)) + +## Typings + +- Inference of guild in `MessageManager` (#8538) ([6bb1474](https://github.com/discordjs/discord.js/commit/6bb1474d2001b76773954c959b2c2687e1df0136)) +- Allow choice's value type to be strictly inferred (#8529) ([b3f7c32](https://github.com/discordjs/discord.js/commit/b3f7c32f7f91f12766178f5e17585856e81d9a87)) +- **GuildAuditLogs:** Allow fetching to return all possible values (#8522) ([0dba8ad](https://github.com/discordjs/discord.js/commit/0dba8adbd2e6efd634bd3eb31df09467ba8a8a0d)) +- Correct `EventEmitter.on (static)` return type (#8524) ([16bbc8a](https://github.com/discordjs/discord.js/commit/16bbc8aa208a8a16c22be24696f57d5f7a5faf2b)) +- **GuildAuditLogs:** Remove static `Entry` (#8521) ([7a3d18d](https://github.com/discordjs/discord.js/commit/7a3d18dd6d1fe27393d00019b9ecd35c98b95ee7)) +- Disallow some channel types from webhook creation (#8531) ([4882b17](https://github.com/discordjs/discord.js/commit/4882b17a77484f801faa19fb971f2e6abd88e59f)) +- Implement max/min values for autocomplete (#8498) ([812f7f1](https://github.com/discordjs/discord.js/commit/812f7f1ea86fc953aa796875cbc7ccc434203d77)) +- **ModalMessageModalSubmitInteraction:** ChannelId is not nullable (#8496) ([c31a5cf](https://github.com/discordjs/discord.js/commit/c31a5cfcc82706667768eac77b5f99ba69cf3c91)) +- Change type of ApplicationCommandSubCommand.options (#8476) ([ebaf158](https://github.com/discordjs/discord.js/commit/ebaf158006d3c7db3b8c695e7c027b8af11999ba)) + +# [14.2.0](https://github.com/discordjs/discord.js/compare/14.1.2...14.2.0) - (2022-08-10) + +## Bug Fixes + +- **ThreadChannel:** Handle possibly `null` parent (#8466) ([afa27b1](https://github.com/discordjs/discord.js/commit/afa27b15c5b92bc8d55b8285834d8e03f6692d06)) +- Remove DM channels from `Client#messageDeleteBulk`'s types (#8460) ([6c6fe74](https://github.com/discordjs/discord.js/commit/6c6fe74dd84859c5319efa999404e8168f189710)) +- **Transformers:** Do not transform `Date` objects (#8463) ([0e2a095](https://github.com/discordjs/discord.js/commit/0e2a09571c8e5ee61153b04e45334a226a1b4534)) +- **ModalSubmitInteraction:** Allow deferUpdate (#8455) ([0fab869](https://github.com/discordjs/discord.js/commit/0fab869e5179dca7ddec75b5519615278e51ad82)) +- **Guild:** Unable to fetch templates (#8420) ([aac8acc](https://github.com/discordjs/discord.js/commit/aac8acc22be7d7af99933ef099eca7deda43cb40)) +- **MessageMentions:** Infinite loop in `parsedUsers` getter (#8430) ([b8a3136](https://github.com/discordjs/discord.js/commit/b8a31360a220e3d796f5381bd215d30a379ecb7c)) +- **DataResolver:** Make `Buffer` from string (#8416) ([e72b986](https://github.com/discordjs/discord.js/commit/e72b986939e2958547c0e54d6d27472c8d111609)) + +## Documentation + +- Change registration example to use global commands (#8454) ([64a4041](https://github.com/discordjs/discord.js/commit/64a4041a05e9514334a9f9e1f38a1ea18bb676d5)) +- **Colors:** Provide enum descriptions (#8437) ([6ef4754](https://github.com/discordjs/discord.js/commit/6ef4754d40c5ec65715fc1e00e643c52fe0a6209)) +- **AttachmentBuilder:** Fix #8407 (#8421) ([5b053cf](https://github.com/discordjs/discord.js/commit/5b053cf82ec2f2b717a490485af052dc956fe3c9)) + +## Features + +- **Guild:** Add `max_video_channel_users` (#8423) ([3a96ce7](https://github.com/discordjs/discord.js/commit/3a96ce7970947f6268c21a1323d986aac8cb736d)) + +## Typings + +- **Message:** Correct `bulkDelete` return type (#8465) ([c5b96a1](https://github.com/discordjs/discord.js/commit/c5b96a185cb8ba836b7cd10526c14059866f218f)) +- Fix missing types for mentionable options (#8443) ([452e94f](https://github.com/discordjs/discord.js/commit/452e94fd3ecc12de9e3408982c5c7fd931bae634)) +- **ApplicationCommandOption:** Add `ApplicationCommandBooleanOption` (#8434) ([38275fc](https://github.com/discordjs/discord.js/commit/38275fc53d633ce77ed2b142aff788dcbd4fad8c)) + +# [14.1.2](https://github.com/discordjs/discord.js/compare/14.1.1...14.1.2) - (2022-07-30) + +## Bug Fixes + +- **errors:** Error codes (#8398) ([480c85c](https://github.com/discordjs/discord.js/commit/480c85c9c3d129204b3399ed726a4e570e0b2852)) + +## Documentation + +- **Embed:** Ensure height and width are numbers (#8396) ([fca3dad](https://github.com/discordjs/discord.js/commit/fca3dada2a565eecfc7e5275cc9317df1d261871)) + +# [14.1.0](https://github.com/discordjs/discord.js/compare/14.0.3...14.1.0) - (2022-07-29) + +## Bug Fixes + +- **MessageMentions:** `ignoreRepliedUser` option in `has()` (#8202) ([b4e2c0c](https://github.com/discordjs/discord.js/commit/b4e2c0c4d5538b945f9d597c6410a6f84b315084)) +- **GuildChannelManager:** Allow unsetting rtcRegion (#8359) ([a7d49e5](https://github.com/discordjs/discord.js/commit/a7d49e56fc7c34d2e4548d9e5bf0aec45273506e)) +- **ThreadChannel:** Omit webhook fetching (#8351) ([3839958](https://github.com/discordjs/discord.js/commit/3839958e3f682c715f1017da05436d2fe34900fd)) +- **GuildAuditLogsEntry:** Replace OverwriteType with AuditLogOptionsType (#8345) ([58c1b51](https://github.com/discordjs/discord.js/commit/58c1b51c5ceab137ad9851919b338419eeeab69e)) +- **ShardClientUtil#_respond:** Construct global error (#8348) ([8e520f9](https://github.com/discordjs/discord.js/commit/8e520f946a5b9f93a939290facf4ccca2c05ff21)) +- **Presence:** Do not return NaN for activity timestamp (#8340) ([df42fdf](https://github.com/discordjs/discord.js/commit/df42fdfc421f1190f0a2267a66efd3c921ec2348)) +- **Client:** Omit private properties from toJSON (#8337) ([830c670](https://github.com/discordjs/discord.js/commit/830c670c61dcb17d8ab2a894a3203c68917d27e0)) +- **ApplicationCommandManager:** Allow passing 0n to defaultMemberPermissions (#8311) ([1fb7b30](https://github.com/discordjs/discord.js/commit/1fb7b30963cfe7ea4c05b1f3b42171c879c46a1d)) + +## Documentation + +- **InteractionResponses:** Add `showModal()` return type (#8376) ([0b61dbf](https://github.com/discordjs/discord.js/commit/0b61dbf720e844322b066e30080c3537ab3d8174)) +- **WebhookClient:** Document working options (#8375) ([ba6797e](https://github.com/discordjs/discord.js/commit/ba6797e74209161b64c412de1b6f307cb28736b8)) +- **Message:** Document gateway intent for content (#8364) ([2130aae](https://github.com/discordjs/discord.js/commit/2130aae3210a8eaf91c5ccae5463940d49052c7d)) +- Use info blocks for requirements (#8361) ([80b9738](https://github.com/discordjs/discord.js/commit/80b9738957ebf5b6eb7c9858cec0fb1c897d0a1f)) +- **WebhookClient:** Make constructor a union (#8370) ([e9920a9](https://github.com/discordjs/discord.js/commit/e9920a9c98ffb78bd7d0ae00d486476367296646)) +- Update docs and examples to PascalCase links (#8305) ([34ba9d1](https://github.com/discordjs/discord.js/commit/34ba9d1c4c80eff7e6ac199a40232d07491432cc)) + +## Features + +- Add channel & message URL formatters (#8371) ([a7deb8f](https://github.com/discordjs/discord.js/commit/a7deb8f89830ead6185c5fb46a49688b6d209ed1)) +- Restore missing typeguards (#8328) ([77ed407](https://github.com/discordjs/discord.js/commit/77ed407f6aadb68e729470c5269e9b526cb1b3f0)) +- **GuildMember:** Add dmChannel getter (#8281) ([4fc2c60](https://github.com/discordjs/discord.js/commit/4fc2c60a3bb43671b4b0202ae75eab42aba163ff)) + +## Refactor + +- Deprecate `Formatter` class (#8373) ([7fd9ed8](https://github.com/discordjs/discord.js/commit/7fd9ed8f13d17ce7e98e34f7454d9047054d8467)) +- **PermissionOverwriteManager:** Use `OverwriteType` (#8374) ([6d24805](https://github.com/discordjs/discord.js/commit/6d248051cfd431e9cb1c65cb98f56aa0a6556407)) + +## Typings + +- **GuildAuditLogsEntryExtraField:** Use `AuditLogOptionsType` (#8349) ([200ab91](https://github.com/discordjs/discord.js/commit/200ab91f527d8a5706d277b89a975096f75d141a)) + +# [14.0.3](https://github.com/discordjs/discord.js/compare/14.0.2...14.0.3) - (2022-07-19) + +## Bug Fixes + +- **Components:** Support emoji id strings (#8310) ([660e212](https://github.com/discordjs/discord.js/commit/660e212e83df026c684ee2cda7fb4e98870f342e)) + +# [14.0.2](https://github.com/discordjs/discord.js/compare/14.0.1...14.0.2) - (2022-07-18) + +## Bug Fixes + +- **DataResolver#resolveImage:** Adjust to updated resolveFile (#8308) ([3a7e93d](https://github.com/discordjs/discord.js/commit/3a7e93df576172c797f1d8bd6483234bb6af2d00)) + +# [14.0.0](https://github.com/discordjs/discord.js/compare/9.3.1...14.0.0) - (2022-07-17) + +## Bug Fixes + +- **GuildMemberManager:** Allow setting own nickname (#8066) ([52a9e21](https://github.com/discordjs/discord.js/commit/52a9e213c2dc13ee52ee0234593fdce392f43890)) +- **PermissionOverwriteManager:** Mutates user (#8283) ([3bf30b1](https://github.com/discordjs/discord.js/commit/3bf30b1e6d2d6f583f7069a1e24e7842d59fab2f)) +- **GuildChannelManager:** Access `resolveId` correctly (#8296) ([3648f6d](https://github.com/discordjs/discord.js/commit/3648f6d567cd834c301de913ce19f786a265240d)) +- **GuildChannelManager:** Edit lockPermissions (#8269) ([7876548](https://github.com/discordjs/discord.js/commit/787654816d2b6a5168d199d32cdaeb4ef6d270b9)) +- **`SelectMenuBuilder`:** Properly accept `SelectMenuOptionBuilder`s (#8174) ([31d5930](https://github.com/discordjs/discord.js/commit/31d593046466438c55f5784b0f2098e233c5edc4)) +- Remove global flag on regular expressions (#8177) ([cdd9214](https://github.com/discordjs/discord.js/commit/cdd9214212892e30b3eaa161837c37516c5bcaa0)) +- **MessagePayload:** Guard against `repliedUser` property (#8211) ([fa010b5](https://github.com/discordjs/discord.js/commit/fa010b516254c4ab2762278817f31bf289f0ab6a)) +- **ApplicationCommandManager:** Explicitly allow passing builders to methods (#8209) ([50d55bd](https://github.com/discordjs/discord.js/commit/50d55bd6b819307c86701f4808c087f359c6ccff)) +- **GuildMemberRemove:** Remove member's presence (#8181) ([11b1739](https://github.com/discordjs/discord.js/commit/11b173931968c548f8504649ae7090865892e62d)) +- Edit() data can be partial and `defaultMemberPermissions` can be `null` (#8163) ([0ffbef5](https://github.com/discordjs/discord.js/commit/0ffbef506a97a0bf22cb134fc007c2aec29cbffc)) +- **WebSocketShard:** Keep an error handler on connections (#8150) ([c34c02a](https://github.com/discordjs/discord.js/commit/c34c02ab8d119bf16d8d14d125a9b650b4bb18f4)) +- **DJSError:** Error code validation (#8149) ([31f6582](https://github.com/discordjs/discord.js/commit/31f658247fe0e1047897edab629643d140e77e07)) +- **vcs:** Nsfw property (#8132) ([2eeaad6](https://github.com/discordjs/discord.js/commit/2eeaad6f27fdf8868364fa95ed20755ee09bda87)) +- **WebSocketManager:** Correct error name (#8138) ([db2b033](https://github.com/discordjs/discord.js/commit/db2b0333d912fe83381db2ffe16829d7d03d6c2e)) +- **WebSocketShard:** Disconnected casing (#8117) ([23e183a](https://github.com/discordjs/discord.js/commit/23e183a9ac7aaa3bca2bc4eb8634d1738ec34a26)) +- **webhooks:** Revert webhook caching (and returning Message) (#8038) ([d54bf5d](https://github.com/discordjs/discord.js/commit/d54bf5d286f4057db130901591b192fd4d1668c1)) +- **ApplicationCommand:** Remove `autocomplete` check at the top level and correctly check for `dmPermission` (#8100) ([0a44b05](https://github.com/discordjs/discord.js/commit/0a44b05db83948857afbe18471e7a867da47177a)) +- **ApplicationCommand:** Fix default member permissions assignment (#8067) ([96053ba](https://github.com/discordjs/discord.js/commit/96053babe1bd65ebe1fc6a261f5eb052906afdb9)) +- **scripts:** Read directory and rerun (#8065) ([f527dea](https://github.com/discordjs/discord.js/commit/f527dea36ead194aaae1bf5da1e953df59d692fd)) +- Select menu options to accept both rest and array (#8032) ([fbe67e1](https://github.com/discordjs/discord.js/commit/fbe67e102502b4b49690cbf8ff891ead2232ecf3)) +- **CommandInteractionOptionResolver:** Handle autocompletion interactions (#8058) ([d8077c6](https://github.com/discordjs/discord.js/commit/d8077c6839dc8ceb57d3c3a86bf9746be2a91ada)) +- **scripts:** Add quotes around blob arguments (#8054) ([598f61b](https://github.com/discordjs/discord.js/commit/598f61b992fab1b3fdcab8ff960366f7af0b37ea)) +- **Message:** Force fetching (#8047) ([f2b267c](https://github.com/discordjs/discord.js/commit/f2b267c079dd8aa7277910471f3db2f88af6efb2)) +- **Attachment:** Do not destructure `data` (#8041) ([1afae90](https://github.com/discordjs/discord.js/commit/1afae909d72e648cf48d63d7de2708737a78c126)) +- **DirectoryChannel:** Type `name` and handle `url` (#8023) ([86d8fbc](https://github.com/discordjs/discord.js/commit/86d8fbc023e3925e8f86799d6ebf2d423f7bf2ec)) +- Readd `isThread` type guard (#8019) ([f8ed71b](https://github.com/discordjs/discord.js/commit/f8ed71bfca6e47e3d44ad063e23804354bd23604)) +- Add static method `from` in builders (#7990) ([ad36c0b](https://github.com/discordjs/discord.js/commit/ad36c0be7744ea4214ccf345fe80a5a1a9e89101)) +- Typings (#7965) ([7a1095b](https://github.com/discordjs/discord.js/commit/7a1095b66be3c5d81185e026281e2908c10c1695)) +- **GuildAuditLogs:** Cache guild scheduled events (#7951) ([2f03f9a](https://github.com/discordjs/discord.js/commit/2f03f9ad3f63abee5b5c46d02f1afa8885e8977c)) +- Make sure action row builders create djs builders (#7945) ([adf461b](https://github.com/discordjs/discord.js/commit/adf461baf49be754c7a10c61faf1ef3df333413a)) +- **TextBasedChannel#bulkDelete:** Return deleted message (#7943) ([191510b](https://github.com/discordjs/discord.js/commit/191510b7f87903e4bd93b891649cb290fd50c47e)) +- Remove trailing invites on channel deletion (#7932) ([5e9b757](https://github.com/discordjs/discord.js/commit/5e9b757a3733e6526770eb60a15072612294eb21)) +- **DataResolver:** Fix check for readable streams (#7928) ([28172ca](https://github.com/discordjs/discord.js/commit/28172ca7b57357436d3252ec01ec17dad865d87f)) +- **AuditLog:** Default changes to empty array (#7880) ([19eaed6](https://github.com/discordjs/discord.js/commit/19eaed63905367ef4604366b8839023384524d1f)) +- **Util:** Flatten ignoring certain fields (#7773) ([df64d3e](https://github.com/discordjs/discord.js/commit/df64d3ea382c07e66bc7cc8877ee430206c31d63)) +- Possibly missing (#7829) ([6239d83](https://github.com/discordjs/discord.js/commit/6239d83c4d5f0a396678410d7fef35e39ed29009)) +- `endReason` not being properly set in base Collector (#7833) ([0c18dab](https://github.com/discordjs/discord.js/commit/0c18dab1280205b8855d17d075b7421860d59c14)) +- **SelectMenuBuilder:** Options array (#7826) ([3617093](https://github.com/discordjs/discord.js/commit/361709332bdc871822c2b9919f14fd090d68666a)) +- **Activity:** Platform type (#7805) ([4ac91c6](https://github.com/discordjs/discord.js/commit/4ac91c61d08111ae4d49d1e64caf94e6e49832c8)) +- **ApplicationCommand:** Equal nameLocalizations and descriptionLocalizations (#7802) ([4972bd8](https://github.com/discordjs/discord.js/commit/4972bd87c17cbc6a94c9608ba2ab39c475f9921f)) +- **InteractionResponses:** Use optional chaining on nullable property (#7812) ([c5fb548](https://github.com/discordjs/discord.js/commit/c5fb54852906898ffb19282dd60168dfc6fb2eba)) +- **MessageManager:** Allow caching option of an unspecified limit (#7763) ([1b2d8de](https://github.com/discordjs/discord.js/commit/1b2d8decb638faeae8184119c5cedfcdaf9485e3)) +- **builders:** Add constructor default param (#7788) ([c286650](https://github.com/discordjs/discord.js/commit/c2866504a3824005fe756556fec4b349898b7d22)) +- **MessagePayload:** ResolveBody check body instead of data (#7738) ([3db20ab](https://github.com/discordjs/discord.js/commit/3db20abdd2d502a1ed457842181b164dc6390ba1)) +- **ActionRow:** ToJSON should include components (#7739) ([ebb4dfa](https://github.com/discordjs/discord.js/commit/ebb4dfa262adb2086c83db487002bb2e1ed5ab88)) +- Prevent `NaN` for nullable timestamps (#7750) ([8625d81](https://github.com/discordjs/discord.js/commit/8625d817145eb642aeb0da05184352f438586986)) +- **InteractionCreateAction:** Ensure text-based channel for caching messages (#7755) ([25fdb38](https://github.com/discordjs/discord.js/commit/25fdb3894d33dc395a376a3d962a063eb5735253)) +- Pass `force` correctly (#7721) ([402514f](https://github.com/discordjs/discord.js/commit/402514ff323ccf1f8c95d295f044cf0bb5547c2e)) +- Support reason in setRTCRegion helpers (#7723) ([905a6a1](https://github.com/discordjs/discord.js/commit/905a6a11663f9469ada67f8310a969453ffc5b2a)) +- **GuildMemberManager:** Return type can be null (#7680) ([74bf7d5](https://github.com/discordjs/discord.js/commit/74bf7d57ab959eb820ab1c213ac86ab1ea660398)) +- **gateway:** Use version 10 (#7689) ([8880de0](https://github.com/discordjs/discord.js/commit/8880de0cecdf273fd6df23988e4cb77774a75390)) +- Audit log static reference (#7703) ([85e531f](https://github.com/discordjs/discord.js/commit/85e531f22d7a8f8ad043647ce445726ae0df26c0)) +- Handle possibly missing property (#7641) ([0c32332](https://github.com/discordjs/discord.js/commit/0c32332a5aacbbb6c415da75c166d09cfdb34bbd)) +- **util:** Allow `escapeInlineCode` to escape double backtics (#7638) ([d5369a5](https://github.com/discordjs/discord.js/commit/d5369a56e3fcf50513f3bc582552c2838b04d199)) +- **GuildEditData:** Some fields can be null (#7632) ([4d2b559](https://github.com/discordjs/discord.js/commit/4d2b55955d1a3ff05c3047599232becdc3f2c445)) +- TOKEN_INVALID error not thrown at login with invalid token (#7630) ([cd79bef](https://github.com/discordjs/discord.js/commit/cd79bef2547594f4d0c744faa8fa67fb9fd61526)) +- **GuildScheduledEvent:** Handle missing `image` (#7625) ([c684ac5](https://github.com/discordjs/discord.js/commit/c684ac55e1d225740e67ab7bd5643de1b35f4594)) +- **guild:** Throw if ownerId falsey (#7575) ([98177aa](https://github.com/discordjs/discord.js/commit/98177aa38d3d6516d4c5354d6c7edea925dc881d)) +- Remove Modal export (#7654) ([87a6b84](https://github.com/discordjs/discord.js/commit/87a6b8445bfbf3981cd39813fe961dfa1c7f2bce)) +- **Embed:** Fix incorrect destructuring import (#7615) ([cbdb408](https://github.com/discordjs/discord.js/commit/cbdb408dffd1c7f2193c15989528a3de5fd9f13a)) +- **ThreadMembersUpdate:** Only emit added & removed thread members (#7539) ([c12d61a](https://github.com/discordjs/discord.js/commit/c12d61a3421afcdc41f77c0fddde4efbb257fa69)) +- **Util:** EscapeInlineCode properly (#7587) ([851f380](https://github.com/discordjs/discord.js/commit/851f380eb10d23ffd08e8b845aed4039abbcd03b)) +- **GuildStickerManager:** Correctly access guild ID (#7605) ([4b08d9b](https://github.com/discordjs/discord.js/commit/4b08d9b376bda7a7f4bb3fb8c555d25cca648de4)) +- **MessageManager:** Pin route (#7610) ([cb566c8](https://github.com/discordjs/discord.js/commit/cb566c8b6abff489a944db7952e5c5a48e0c98b0)) +- Handle partial data for `Typing#user` (#7542) ([c6cb5e9](https://github.com/discordjs/discord.js/commit/c6cb5e9ebbf46d81404119a6aa11bb8ebb17d5a4)) +- **guild:** Fix typo accessing user instead of users (#7537) ([8203c5d](https://github.com/discordjs/discord.js/commit/8203c5d843f2431c0f49023282f1bf73d85881d1)) +- **test:** `MessageActionRow` to `ActionRow` (#7523) ([d1d1b07](https://github.com/discordjs/discord.js/commit/d1d1b076bebf7cb706b2436a40d87c6efaed1e1d)) +- **MessagePayload:** Don't set reply flags to target flags (#7514) ([4f30652](https://github.com/discordjs/discord.js/commit/4f306521d829fef21ebd70557b37f8199b82572b)) +- **invite:** Add back channelId property (#7501) ([78aa36f](https://github.com/discordjs/discord.js/commit/78aa36f9f5913b86c82376ecdf20653b15340bbe)) +- Properly serialize `undefined` values (#7497) ([8dbd345](https://github.com/discordjs/discord.js/commit/8dbd34544cbeb499282f01dda9d35ed9bca93591)) +- Allow unsafe embeds to be serialized (#7494) ([942ea1a](https://github.com/discordjs/discord.js/commit/942ea1acbfb49289ccb3a1882b5a2da0a7d0bccf)) +- Attachment types (#7478) ([395a68f](https://github.com/discordjs/discord.js/commit/395a68ff49c622d5136d6b775beaf8e88a2d8610)) +- Use case converter for json component serialization (#7464) ([2d45544](https://github.com/discordjs/discord.js/commit/2d4554440ed9329a5876a9c674c3eb2de0f2f917)) +- **GuildAuditLogs:** Typings and consistency (#7445) ([c1b27f8](https://github.com/discordjs/discord.js/commit/c1b27f8eed8ea04a48bc106453892bddcdc6b73e)) +- **dataresolver:** Ensure fetched file is convert to a buffer (#7457) ([9311fa7](https://github.com/discordjs/discord.js/commit/9311fa7b42b2b5a74e411aa263daa4fbfc270645)) +- **messagepayload:** ResolveFile property names (#7458) ([a8106f7](https://github.com/discordjs/discord.js/commit/a8106f7c586f0ecac76e7f72c53b0da215a6fbf1)) +- **ci:** Ci error (#7454) ([0af9bc8](https://github.com/discordjs/discord.js/commit/0af9bc841ffe1a297d308500d696bad4b85abda9)) +- **threads:** Require being sendable to be unarchivable (#7406) ([861f0e2](https://github.com/discordjs/discord.js/commit/861f0e2134662ab64a11d313130aff58b413d495)) +- **guildmember:** Check if member has administrator permission (#7384) ([81d8b54](https://github.com/discordjs/discord.js/commit/81d8b54ff6b98b0e7ee2c57eaee6bc0b707e135a)) +- **guild:** Remove `maximumPresences` default value (#7440) ([55b388a](https://github.com/discordjs/discord.js/commit/55b388a763dc7223e88b62ae928fe85fe8b8fe58)) +- **guildchannelmanager:** Edit always sets parent to null (#7446) ([b97aedd](https://github.com/discordjs/discord.js/commit/b97aedd8e15f9358960cb59403f3a8ea24b87141)) +- **guildmember:** Make `pending` nullable (#7401) ([fe11ff5](https://github.com/discordjs/discord.js/commit/fe11ff5f6e85571a981e90eba5b9f3bda7a2cd04)) +- **clientpresence:** Fix used opcodes (#7415) ([a921ec7](https://github.com/discordjs/discord.js/commit/a921ec7dc525c58d40b4678e66270f9238abed31)) +- Correctly export UnsafeSelectMenuComponent from builders (#7421) ([aadfbda](https://github.com/discordjs/discord.js/commit/aadfbda586d57a7b775ad26c201f0dc34618180b)) +- MessageReaction.me being false when it shouldn't (#7378) ([04502ce](https://github.com/discordjs/discord.js/commit/04502ce702da53c4b00bf391d0fd936746851381)) +- Fix some typos (#7393) ([92a04f4](https://github.com/discordjs/discord.js/commit/92a04f4d98f6c6760214034cc8f5a1eaa78893c7)) +- **messagementions:** Fix `has` method (#7292) ([3a5ab2c](https://github.com/discordjs/discord.js/commit/3a5ab2c4e54de4e67ab6e323d7eac86482da7382)) +- **guildmembermanager:** Use rest in edit (#7356) ([00ce1c5](https://github.com/discordjs/discord.js/commit/00ce1c56ac224691a8691a3525cb14ae002319c6)) +- **typings:** Mark `RESTOptions` as Partial in `ClientOptions` (#7349) ([e1ecc1a](https://github.com/discordjs/discord.js/commit/e1ecc1a80a9358cdbafbe8542c40b9de8cad467e)) +- **Webhook:** Use correct method name (#7348) ([11e5e5a](https://github.com/discordjs/discord.js/commit/11e5e5ac5b70138f56332eb3e61a42443670b0de)) +- **thread:** Don't assign directly to getters (#7346) ([2db0cdd](https://github.com/discordjs/discord.js/commit/2db0cdd357c3a02decb4fd4168db87888efba283)) +- Missed enums and typings from #7290 (#7331) ([47633f0](https://github.com/discordjs/discord.js/commit/47633f0fd2435d6d8c694d8d37b26039a7b3797a)) +- **guildchannelmanager:** Remove reverse enum lookup (#7304) ([857bba4](https://github.com/discordjs/discord.js/commit/857bba448029f3f070c67fb40b59a3a2a2e5c6f4)) +- Import `clear{Timeout,Interval}` from `node:timers` (#7269) ([8ddd44e](https://github.com/discordjs/discord.js/commit/8ddd44ed85b32c86243efe0ec35b283eaaa8212c)) +- **ApplicationCommand:** Use new ApplicationCommandOptionType enums (#7257) ([06f5210](https://github.com/discordjs/discord.js/commit/06f5210f58bbba6102173033a9f1e6fb004fdf5d)) +- Use enums from discord-api-types (#7258) ([f284a46](https://github.com/discordjs/discord.js/commit/f284a4641fd68de9190bda97ec1eab0981149630)) +- **exports:** Export ApplicationCommandType properly (#7256) ([f753882](https://github.com/discordjs/discord.js/commit/f75388259262bf6b4a64375b97800bd72378f3bc)) +- **Shard:** EventEmitter listener warning (#7240) ([ff3a8b8](https://github.com/discordjs/discord.js/commit/ff3a8b83234d3826fc49c5a8c3cb52ef9f281ffd)) +- **timestamps:** Account for timestamps of 0 when creating Dates (#7226) ([a8509c9](https://github.com/discordjs/discord.js/commit/a8509c91ca0147393b407221405b6b917677961a)) +- **MessageEmbed:** CreatedAt field can be zero (#7218) ([37cad54](https://github.com/discordjs/discord.js/commit/37cad54dbdade39607397b8ad697eca94f1b7197)) +- **BaseClient:** Do not append default options if provided is not an object (#6453) ([b92a7d7](https://github.com/discordjs/discord.js/commit/b92a7d72332c35b607db54aa6aca24b8e10e00ad)) +- Snowflakeutil import (#7219) ([962f4bf](https://github.com/discordjs/discord.js/commit/962f4bf88211dbfb5ad0295a9467dede1e2688ee)) +- **Role:** Remove unused process (#7215) ([63034b4](https://github.com/discordjs/discord.js/commit/63034b44c9849087e391684d9b6c0c6ae9a21113)) +- **WebhookClient:** Updated webhook url regex (#6804) ([1c615d1](https://github.com/discordjs/discord.js/commit/1c615d1bb2606d5f19e55076d4ecab95c619518e)) +- **Sweepers:** Add sweepStickers function (#7213) ([95f8375](https://github.com/discordjs/discord.js/commit/95f8375d425f58f501f32ead03f7927e6596f8e6)) +- **InteractionCreate:** Use ChatInputCommandInteraction instead (#7210) ([49dada3](https://github.com/discordjs/discord.js/commit/49dada35f92470d3e4426362510847b93dd42d1a)) +- **Structues:** Rename old module's name (#7207) ([fbef454](https://github.com/discordjs/discord.js/commit/fbef45489457a2198357dc4dd303740d79036784)) +- **WebSocket:** Remove application command handler (#7202) ([033151c](https://github.com/discordjs/discord.js/commit/033151cf92fe43536b8a4c0f4d7d9ed75a2095c5)) +- **User:** `bannerURL()` should not throw when not present (#6789) ([3872acf](https://github.com/discordjs/discord.js/commit/3872acfeb8390f6f7202d69cf1f7f8616a7b0b34)) +- **VoiceState:** Ensure `suppress` & `streaming` have proper fallback values (#6377) ([a0d5f13](https://github.com/discordjs/discord.js/commit/a0d5f13dd9b27c44f5183a2a9af4c4fdecb312c0)) +- **sweepers:** Provide default for object param (#7182) ([ae2f013](https://github.com/discordjs/discord.js/commit/ae2f013653c8a9f9ffb12ae8fcdb1bb604b39236)) + +## Deprecation + +- **Caching:** Clean up deprecated cache sweeping (#7118) ([12ffa06](https://github.com/discordjs/discord.js/commit/12ffa069aa8b247e945fef16a543f41c2c391bf1)) + +## Documentation + +- Align webhook method return types with implementation (#8253) ([5aeed99](https://github.com/discordjs/discord.js/commit/5aeed9935058241648507d7f651679226a89dbb3)) +- Remove `@private` constructor documentation (#8255) ([452dec5](https://github.com/discordjs/discord.js/commit/452dec57ca422f5e7424a0f0e78c3e152717f413)) +- **ApplicationCommand:** Add `min_length` and `max_length` to ApplicationCommandOptionData (#8239) ([43f62bb](https://github.com/discordjs/discord.js/commit/43f62bb6678ec332795c8cfbe0c01854b95aa61e)) +- **MessageInteraction#commandName:** Updated description (#8212) ([ab238a9](https://github.com/discordjs/discord.js/commit/ab238a9046e0201dbd4755fa41fa69c44b186912)) +- Add missing `@extends` (#8205) ([e0c8282](https://github.com/discordjs/discord.js/commit/e0c82824905dcebf62c2d1afcc5e5590a5594838)) +- **Constants:** Fix SweeperKeys type (#8157) ([af04992](https://github.com/discordjs/discord.js/commit/af04992ed3c2617fda686c2bc7338dcada283dc6)) +- **Channels:** Internally document channel creation (#8154) ([5e5853a](https://github.com/discordjs/discord.js/commit/5e5853a4e885c47e3dde519761dd59a5ec0e06fc)) +- Update threads to use `ThreadAutoArchiveDuration` (#8153) ([ee36d60](https://github.com/discordjs/discord.js/commit/ee36d60dc6714c83569a20716fa8ca8e1bd7de4f)) +- **APITypes:** Remove duplicate type definition (#8144) ([a061233](https://github.com/discordjs/discord.js/commit/a0612335101c7ce2a07d95da4b79f0d4a2b1a6a0)) +- Document missing type definitions (#8130) ([203bc4a](https://github.com/discordjs/discord.js/commit/203bc4a2cf0c2d90a003093318aa0741605610f5)) +- **InteractionResponse:** Fix return (#8141) ([f1ac17c](https://github.com/discordjs/discord.js/commit/f1ac17c961cf95d99e205133605d10d8be5bd737)) +- **PermissionsBitField:** Fix `@name` of bitfield (#8115) ([3a77ce0](https://github.com/discordjs/discord.js/commit/3a77ce0b18c60a0b21ba088590ff89f2ace94087)) +- `TextBasedChannel` -> `TextBasedChannels` typos (#8110) ([db663a5](https://github.com/discordjs/discord.js/commit/db663a55c2ed2faf61e217009158da50dfcf274f)) +- Remove `number`s from enums (#8098) ([0a138da](https://github.com/discordjs/discord.js/commit/0a138dab95a86512f08ac3be356f77f38f2ea880)) +- **GuildAuditLogs:** Fix and reimplement type definitions (#8108) ([4155136](https://github.com/discordjs/discord.js/commit/415513696c7b7e139d1b958e480bf0c7e4d14111)) +- **WebSocketOptions:** Add `version` to docs and typings (#8050) ([386c41f](https://github.com/discordjs/discord.js/commit/386c41f24fb3c9d06967d9c1881a57645c3a71f2)) +- **BaseGuildTextChannel:** Update `setType()`'s parameter type (#8088) ([9c0f190](https://github.com/discordjs/discord.js/commit/9c0f190de1f743d9bd597ffd656503c672db71c1)) +- Update outdated examples (#8081) ([51eadf3](https://github.com/discordjs/discord.js/commit/51eadf37371a6138847efdb4b5b81ee132001cf0)) +- **ThreadMemberManager:** Require `member` in `FetchThreadMemberOptions` (#8079) ([552ec72](https://github.com/discordjs/discord.js/commit/552ec72542ec3b2b3ebf35c9fd84ab502dd746cf)) +- **AutocompleteInteraction:** Change useless log in responds example (#8077) ([ac7bf69](https://github.com/discordjs/discord.js/commit/ac7bf692bfce8204e278205dde811515a51f154b)) +- Description and missing `@typedef` fixes (#8087) ([a2eebf6](https://github.com/discordjs/discord.js/commit/a2eebf6c66f3e4c96ece9d2ae2a1133c84257f42)) +- Ignore docs of unexported functions (#8051) ([94bdcac](https://github.com/discordjs/discord.js/commit/94bdcaca62414a77d4ee0b8b79752a2be937320b)) +- **ClientOptions:** Fix closeTimeout default (#8049) ([b2eea1c](https://github.com/discordjs/discord.js/commit/b2eea1c900ba73d4b98b72f5c196f51e27d3ab8f)) +- **DirectoryChannel:** Extend `Channel` (#8022) ([f3f34f0](https://github.com/discordjs/discord.js/commit/f3f34f07b3b396015b130b8e9d938a3eec688fc3)) +- **Attachment:** Remove constructor doc (#8009) ([0a7953e](https://github.com/discordjs/discord.js/commit/0a7953e46310c77483d277539b47f1a7ab051fd9)) +- **VoiceChannel:** Annotate that it is implementing TextBasedChannel (#8007) ([5987dbe](https://github.com/discordjs/discord.js/commit/5987dbe5cff6991ae6905b0387411fa042d3e9b7)) +- Add missing discord-api-types external types (#8001) ([546d486](https://github.com/discordjs/discord.js/commit/546d48655f36ed9a6c6c5ce3c2eabcca1a86a945)) +- **InteractionResponses:** Replace outdated Embed example for reply (#7875) ([d308c66](https://github.com/discordjs/discord.js/commit/d308c66eeca6bdc3471637ae3aaaaa0a2f5c9989)) +- Require parameter (#7838) ([f4ccc67](https://github.com/discordjs/discord.js/commit/f4ccc6772c15e32489ca22fb2c3e803b85d4dbf9)) +- **ApplicationCommand:** Fix and improve localization docs (#7804) ([61a44c5](https://github.com/discordjs/discord.js/commit/61a44c509c40abaf7ffb95b10942889cbbf155ac)) +- **ApplicationCommand:** Fix ApplicationCommandOptionChoice (#7794) ([f1d0084](https://github.com/discordjs/discord.js/commit/f1d0084da26b0111ca029c789ad9e8e6c2882b4d)) +- Add back static properties and methods (#7706) ([520f471](https://github.com/discordjs/discord.js/commit/520f471ac56cbc01402b79197333a8a34c4ac5c9)) +- **InteractionCollector:** Document channel option type (#7551) ([e787cd5](https://github.com/discordjs/discord.js/commit/e787cd5fa5d013319347392ee4f799a677f6f512)) +- Correctly type getters (#7500) ([ffecf08](https://github.com/discordjs/discord.js/commit/ffecf084956f954cf10e1b844e00326e443a86f2)) +- ApplicationCommandData typedef (#7389) ([d32db88](https://github.com/discordjs/discord.js/commit/d32db8833e1058fb36f2e83af79d5353a9f2f693)) +- **channel:** Fix `isDMBased` docs (#7411) ([f2a7a9f](https://github.com/discordjs/discord.js/commit/f2a7a9f1b30af272a6a8d81825d09f84e749cc24)) +- **messageattachment:** Fix `contentType` docs (#7413) ([2800e07](https://github.com/discordjs/discord.js/commit/2800e07e5974e07b9f8ce043722b9b99a5bcc80d)) +- Add supported option types for autocomplete (#7368) ([8bb3751](https://github.com/discordjs/discord.js/commit/8bb37513400d646d784d59875d6b6a6ec10160cd)) +- Add external builder docs links (#7390) ([0b866c9](https://github.com/discordjs/discord.js/commit/0b866c9fb284971113e288e52327d4506db28011)) +- Add EnumResolvers (#7353) ([72767a1](https://github.com/discordjs/discord.js/commit/72767a1059526bdf617e80d5a9e5da1fbd2936d3)) +- **locales:** Update Discord API docs link (#7266) ([b640272](https://github.com/discordjs/discord.js/commit/b6402723c31bed3c49f8b8cde873b65b9f373fd7)) +- **StageInstance:** Deprecate discoverableDisabled (#7179) ([bd33ebb](https://github.com/discordjs/discord.js/commit/bd33ebb507eab36bc2219103dbd1e0217b9f38c0)) +- **shardingmanager:** Fix type of `execArgv` option (#7284) ([e65da44](https://github.com/discordjs/discord.js/commit/e65da44d9c564d1ffcb0f4df2bcdaf0ce0636f35)) +- **interaction:** Add locale list link (#7261) ([37ec0bd](https://github.com/discordjs/discord.js/commit/37ec0bda6df75fb1dc69b7a1eafbb8ea19e68457)) +- Fix a typo and use milliseconds instead of ms (#7251) ([0dd56af](https://github.com/discordjs/discord.js/commit/0dd56afe1cdf16f1e7d9afe1f8c29c31d1833a25)) +- Fix command interaction docs (#7212) ([137ea24](https://github.com/discordjs/discord.js/commit/137ea249df3aa6b8375ecb42aa456a6fdb811f19)) +- **TextBasedChannel:** Fixed syntax error in examples (#7163) ([b454740](https://github.com/discordjs/discord.js/commit/b454740ae87b6c3c13536181965519c7277e5840)) +- **TextBasedChannel:** Fix #createMessageComponentCollector description (#7168) ([d4e6e03](https://github.com/discordjs/discord.js/commit/d4e6e0370857dff00185d59faf8aaac12b343a7a)) +- Fixes the examples for kick and ban (#7170) ([db669b8](https://github.com/discordjs/discord.js/commit/db669b897132ec458d50ca6c1e3afa761e98ffc3)) +- **RoleManager:** Fix incorrect example (#7174) ([f79ea67](https://github.com/discordjs/discord.js/commit/f79ea67d3a9ba134a9acef0a443bd089c4e173a6)) + +## Features + +- **builder:** Add max min length in string option (#8214) ([96c8d21](https://github.com/discordjs/discord.js/commit/96c8d21f95eb366c46ae23505ba9054f44821b25)) +- **applicationCommand:** Add max min length in string option (#8215) ([94ee60d](https://github.com/discordjs/discord.js/commit/94ee60d3d438f6657bdef51471528769af09624c)) +- Add website documentation early mvp (#8183) ([d95197c](https://github.com/discordjs/discord.js/commit/d95197cc78593df4d0a8d1cc492b0e41b4ab58b8)) +- **BaseInteraction:** Add support for `app_permissions` (#8194) ([002d6a5](https://github.com/discordjs/discord.js/commit/002d6a5aede3d1c0e08bd58eeef38a3b9202f525)) +- **util:** ParseWebhookURL (#8166) ([c4653f9](https://github.com/discordjs/discord.js/commit/c4653f97b1529eb0b99fccdba67c37eb4f467ff9)) +- **AutocompleteInteraction:** Add `commandGuildId` (#8086) ([10a6c42](https://github.com/discordjs/discord.js/commit/10a6c4287dd45a30290814e50fa29a086f85da02)) +- **guild:** Add support for setting MFA level (#8024) ([c5176be](https://github.com/discordjs/discord.js/commit/c5176be14b697ff506eb973c4119644eab544304)) +- **vcs:** Add missing property and methods (#8002) ([0415300](https://github.com/discordjs/discord.js/commit/0415300243877ddbcb501c0a26b1ff65618a1da7)) +- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21)) +- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc)) +- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86)) +- Backport handle zombie connection (#7626) ([e1176fa](https://github.com/discordjs/discord.js/commit/e1176faa27898d4f127c293c099201cb294e10ee)) +- **CommandInteraction:** Add 'commandGuildId' (#8018) ([aa59a40](https://github.com/discordjs/discord.js/commit/aa59a409b36c7ef7018d1785d2dba4da17b57864)) +- Allow builders to accept rest params and arrays (#7874) ([ad75be9](https://github.com/discordjs/discord.js/commit/ad75be9a9cf90c8624495df99b75177e6c24022f)) +- **MessageReaction:** Add react method (#7810) ([a328778](https://github.com/discordjs/discord.js/commit/a3287782b57c28b94c390c24e7d5f2d8c303301f)) +- **Collector:** Add `ignore` event (#7644) ([5244fe3](https://github.com/discordjs/discord.js/commit/5244fe3c1cd400985b00e95d8e5ec73823cf4f25)) +- **GuildMemberManager:** Add `GuildMemberManager#fetchMe()` (#7526) ([349766d](https://github.com/discordjs/discord.js/commit/349766dd6925e2d5e5597cc78c73e46f17c56eab)) +- **guildChannelManager:** Add `videoQualityMode` option for `create()` (#7980) ([cdd2ba0](https://github.com/discordjs/discord.js/commit/cdd2ba036ab1559783eb067786c52aff61807557)) +- **EnumResolvers:** Remove Enumresolvers (#7876) ([76694c1](https://github.com/discordjs/discord.js/commit/76694c1497de1b083a792fd1fda20f0eace50c48)) +- Move `me` to `GuildMemberManager` manager (#7669) ([aed687b](https://github.com/discordjs/discord.js/commit/aed687b09f87862eb2f33fb9f95b2cbd0b770585)) +- **rest:** Use undici (#7747) ([d1ec8c3](https://github.com/discordjs/discord.js/commit/d1ec8c37ffb7fe3b63eaa8c382f22ca1fb348c9b)) +- **VoiceChannel:** Add support for text in voice (#6921) ([4ba0f56](https://github.com/discordjs/discord.js/commit/4ba0f56b6af64bac30eea807fb3e9f3c41c3c83c)) +- **SelectMenu:** Allow emojis in options and option constructors (#7797) ([f22245e](https://github.com/discordjs/discord.js/commit/f22245e9d072ac4ef63b0ae0d84d5ba94608ce22)) +- Allow `createMessageComponentCollector` without using `fetchReply` (#7623) ([a58556a](https://github.com/discordjs/discord.js/commit/a58556adc02b2b9239c8f277a4387c743c9d6f04)) +- Add guild directory support (#6788) ([b01f414](https://github.com/discordjs/discord.js/commit/b01f4147d4f3bca021bc269c9f06463f06e3db53)) +- **GuildBanManager:** Support pagination results (#7734) ([fc2a8bb](https://github.com/discordjs/discord.js/commit/fc2a8bb6750919ecd6ee7c872df05f4b677ff5d3)) +- **CommandInteraction:** Add support for localized slash commands (#7684) ([01a423d](https://github.com/discordjs/discord.js/commit/01a423d110cfcddb3d794fcc32579a1547dd472d)) +- Allow emoji strings to be passed through constructors (#7718) ([0faac04](https://github.com/discordjs/discord.js/commit/0faac04b69f1dda3dc860cd584af100e36a40917)) +- **StageInstanceManager:** Add `sendStartNotification` option to create (#7730) ([29f8807](https://github.com/discordjs/discord.js/commit/29f88079559cc02ccfef7a7c16458d481e573fb5)) +- Add `makeURLSearchParams` utility function (#7744) ([8eaec11](https://github.com/discordjs/discord.js/commit/8eaec114a98026024c21545988860c123948c55d)) +- **modal:** Add `awaitModalSubmit` (#7751) ([3037fca](https://github.com/discordjs/discord.js/commit/3037fca196a0f9238d53bb51394daf737bbf3742)) +- **Actions:** Add parent structure to events parameters (#7577) ([3f3e432](https://github.com/discordjs/discord.js/commit/3f3e4327c86da86734c19a96e97115bd505b4532)) +- Export `UnsafeModalBuilder` and `UnsafeTextInputBuilder` (#7628) ([6fec252](https://github.com/discordjs/discord.js/commit/6fec25239dfed46a30826d38dc97f3680f24ec65)) +- **VoiceChannel:** Support `video_quality_mode` (#7722) ([3b3dabf](https://github.com/discordjs/discord.js/commit/3b3dabf3da2e2f24b81967d68b581d7f7452273f)) +- Add API v10 support (#7477) ([72577c4](https://github.com/discordjs/discord.js/commit/72577c4bfd02524a27afb6ff4aebba9301a690d3)) +- **embed:** Remove Embed.setColor (#7662) ([9b0d8cb](https://github.com/discordjs/discord.js/commit/9b0d8cb2d8f7b55753de584eb3a3f347f87596c2)) +- **StageInstance:** Add support for associated guild event (#7576) ([3dff31f](https://github.com/discordjs/discord.js/commit/3dff31f63fe4afdcc818193d737e1917f1ac8105)) +- **VoiceState:** Add edit method (#7569) ([b162f27](https://github.com/discordjs/discord.js/commit/b162f27e46524bfc64515969d753c6e8f30e6c40)) +- **ModalSubmitInteraction:** Add boolean properties (#7596) ([8907390](https://github.com/discordjs/discord.js/commit/89073903a253d9408839573502c72cae93fe70b6)) +- Add Modals and Text Inputs (#7023) ([ed92015](https://github.com/discordjs/discord.js/commit/ed920156344233241a21b0c0b99736a3a855c23c)) +- **discord.js:** Partial transition to undici (#7482) ([5158332](https://github.com/discordjs/discord.js/commit/51583320d3b0f6452cd96bad1021f2a57e4cc6f6)) +- **message:** Add `reason` on pin and unpin (#7520) ([00728f7](https://github.com/discordjs/discord.js/commit/00728f72b36123b607502624b4b02a02ee524d4a)) +- Re-export AuditLogEvent enum (#7528) ([6a2fa70](https://github.com/discordjs/discord.js/commit/6a2fa70b8e79a460be38916eeb605976ad6fe68b)) +- **options:** Add support for custom JSON transformers (#7476) ([dee27db](https://github.com/discordjs/discord.js/commit/dee27db35af379b0835f9fd5cc19563f7bf3dfc0)) +- Add CategoryChannelChildManager (#7320) ([5cf5071](https://github.com/discordjs/discord.js/commit/5cf5071061760c2f9c1e36d7648aef544b03323a)) + - **Co-authored-by:** Antonio Román <kyradiscord@gmail.com> +- Attachment application command option type (#7200) ([0034396](https://github.com/discordjs/discord.js/commit/003439671d359dcfe481446ef12b90bd71c57835)) +- **builders:** Add attachment command option type (#7203) ([ae0f35f](https://github.com/discordjs/discord.js/commit/ae0f35f51d68dfa5a7dc43d161ef9365171debdb)) +- **scheduledevents:** Add image option (#7436) ([fbc71ef](https://github.com/discordjs/discord.js/commit/fbc71ef6b668c4b1e2b065d9b65541d9303db0a0)) +- Add methods to managers (#7300) ([dd751ae](https://github.com/discordjs/discord.js/commit/dd751ae19da196cc2f90ccd35c7d8e99878daaf9)) +- **channel:** Add .url getter (#7402) ([f59d630](https://github.com/discordjs/discord.js/commit/f59d6305cb0cd0d154a909f18be76407c4d452d3)) +- **components:** Add unsafe message component builders (#7387) ([6b6222b](https://github.com/discordjs/discord.js/commit/6b6222bf513d1ee8cd98fba0ad313def560b864f)) +- **thread:** Add `newlyCreated` to `threadCreate` event (#7386) ([51beda5](https://github.com/discordjs/discord.js/commit/51beda56f74e44ed013b5d25044b8d5fd1978b29)) +- **channel:** Add isDMBased typeguard (#7362) ([388f535](https://github.com/discordjs/discord.js/commit/388f53550cca7ded7350a050fda03c36e4c1fdf7)) +- **`Interaction`:** Add `.commandType` property to `CommandInteraction` and `AutocompleteInteraction` (#7357) ([567db60](https://github.com/discordjs/discord.js/commit/567db60475c8704661b2e788c9905ef364d6c00c)) +- **scheduledevent:** Add support for event cover images (#7337) ([355f579](https://github.com/discordjs/discord.js/commit/355f579771771a28a293c327a38574c8918d18f8)) +- **enumResolvers:** Strengthen typings (#7344) ([9a566e8](https://github.com/discordjs/discord.js/commit/9a566e8068f28fce87c07861ef1d2877c6ae105f)) +- Allow setting message flags when sending (#7312) ([706db92](https://github.com/discordjs/discord.js/commit/706db9228a91ef42e49d2ec749eac153b9ef75d0)) +- **minor:** Add application_id to Webhook (#7317) ([5ccdb0a](https://github.com/discordjs/discord.js/commit/5ccdb0ab266e4f74c331386ac2d6dd32bc225c62)) +- **threadchannel:** Add `createdTimestamp` field (#7306) ([9a16234](https://github.com/discordjs/discord.js/commit/9a1623425ae2d69f5c16f0096af4951ff5096e80)) +- **GuildPreview:** Add stickers (#7152) ([cf25de9](https://github.com/discordjs/discord.js/commit/cf25de9373df98b3c1cd0ca0a092d9dc8172929d)) +- Enum resolvers & internal enum string removal (#7290) ([213acd7](https://github.com/discordjs/discord.js/commit/213acd799738b888d550cdf3f08906764f8288e0)) +- **guildemojimanager:** Add `delete` and `edit` methods (#7286) ([9181a31](https://github.com/discordjs/discord.js/commit/9181a31e0ba330502052c94da544bb15c8b66f11)) +- **interaction:** Add `isRepliable` type guard (#7259) ([da05a88](https://github.com/discordjs/discord.js/commit/da05a8856b11cc1bf0df424c88a1cf9573e5b654)) +- **Channel:** Improve typeguards (#6957) ([37a22e0](https://github.com/discordjs/discord.js/commit/37a22e04c27724c2a65b05c701e3000ba3653ba1)) +- Add Locales to Interactions (#7131) ([9052e32](https://github.com/discordjs/discord.js/commit/9052e321d1c9c8841962d4e8dc5d9e060b104438)) +- **Permissions:** Remove deprecated thread-related permissions (#6755) ([ab3ff5a](https://github.com/discordjs/discord.js/commit/ab3ff5a262caf7d6225b8d6b54ab2c6b6613c0d0)) +- **VoiceRegion:** Remove the unsent vip field (#6759) ([caaef53](https://github.com/discordjs/discord.js/commit/caaef53dd97ecac9f714072ddba5ae9a99ab1027)) +- **richpresenceassets:** Add YouTube and custom image support (#7184) ([d06d70c](https://github.com/discordjs/discord.js/commit/d06d70ccf26c04c1122fac8430922588a489f95e)) +- **Collector:** Yield all collected values (#7073) ([2b480cb](https://github.com/discordjs/discord.js/commit/2b480cb14e6f52855efcb372da7fb455c15b13b1)) + +## Refactor + +- **Util:** Rename `fetchRecommendedShards` (#8298) ([cafde77](https://github.com/discordjs/discord.js/commit/cafde77d73452d729ba8e2cb1cac3f14235b889b)) +- **Embed:** Add all the types (#8254) ([64f8140](https://github.com/discordjs/discord.js/commit/64f814066cc4adebaca47eb8d7a2040a8df399ae)) +- **rest:** Add content-type(s) to uploads (#8290) ([103a358](https://github.com/discordjs/discord.js/commit/103a3584c95a7b7f57fa62d47b86520d5ec32303)) +- Make `GuildAuditLogsEntry.action` return an `AuditLogEvent` (#8256) ([f0b68d5](https://github.com/discordjs/discord.js/commit/f0b68d57368d7ac3db97925df68c11a945ccd84c)) +- **builder:** Remove `unsafe*Builder`s (#8074) ([a4d1862](https://github.com/discordjs/discord.js/commit/a4d18629828234f43f03d1bd4851d4b727c6903b)) +- Make `ShardEvents` the events of `Shard` (#8185) ([c5750d5](https://github.com/discordjs/discord.js/commit/c5750d59f529ab48a5bc88a73a1c449ef6ddbffd)) +- **Util:** Make single `replace` call in `cleanContent` (#8210) ([6b20645](https://github.com/discordjs/discord.js/commit/6b206457400ce31d566b02a0c135042afb540853)) +- **ApplicationCommandManager:** Use `makeURLSearchParams` (#8196) ([cb3dca4](https://github.com/discordjs/discord.js/commit/cb3dca4ae029724421f3d04a784ace0ae2de75e2)) +- Use `Base` prefix for channel and interaction base classes (#8099) ([e24970e](https://github.com/discordjs/discord.js/commit/e24970e3c3d24f71ba711e59666cd8a49a33e33b)) +- **Constants:** Remove leftover code (#8156) ([cd17aad](https://github.com/discordjs/discord.js/commit/cd17aad720430d23af51c364caeb8b22bf6cb6b5)) +- Errors (#8068) ([e68effa](https://github.com/discordjs/discord.js/commit/e68effa822f064a324ed5b92e797c9fc3ce5e211)) +- **ClientOptions:** Remove `$` prefix from `ws.properties` keys (#8094) ([90a98fe](https://github.com/discordjs/discord.js/commit/90a98fee16b7d1d06768461f4e85127c0edf8419)) +- Use `GuildFeature` enum (#8101) ([e5ec1c4](https://github.com/discordjs/discord.js/commit/e5ec1c4dbc3fa54b2c43d1fec24932d7363e17cb)) +- **util:** Make utility functions top level (#8052) ([e53d162](https://github.com/discordjs/discord.js/commit/e53d1621986035b0c92a1782f6e013d408480e00)) +- **ApplicationCommand:** Permissions v2 (#7857) ([c7391db](https://github.com/discordjs/discord.js/commit/c7391db11b3efd4b1a6904affb26887ad06d6db4)) +- ***:** Include name/reason/etc fields into options/data params (#8026) ([9c8b310](https://github.com/discordjs/discord.js/commit/9c8b3102ce00d1f2c1255c150fb3030f8b6dd026)) +- **ThreadMemberManager:** Consistent thread member fetching (#8021) ([da9107c](https://github.com/discordjs/discord.js/commit/da9107c007536952107bd92943b6c714538d5aeb)) +- **interactions:** Remove redundant interaction typeguards (#8027) ([f57d676](https://github.com/discordjs/discord.js/commit/f57d6768ad24f6e37dc598f9c93709449d3bc4dd)) +- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a)) +- **channel:** Remove redundant channel type guards (#8012) ([70c733b](https://github.com/discordjs/discord.js/commit/70c733bb9a5bde0f79e6bea0bdc416458bda4c06)) +- Always return `Message` instances in interactions (#7917) ([9720e55](https://github.com/discordjs/discord.js/commit/9720e555340431c3b3ad7bd670ad0ac7eee8865f)) +- **attachment:** Don't return attachment builders from API (#7852) ([dfadcbc](https://github.com/discordjs/discord.js/commit/dfadcbc2fd50be64c8a0c1cae3be10f83678c5ee)) +- Clean up modal submissions (#7994) ([643dab3](https://github.com/discordjs/discord.js/commit/643dab3b1b5305d002fcefed62755bbe11fc3267)) +- **ThreadChannel:** Remove `MAX` helper from threads (#7846) ([dfd9eb2](https://github.com/discordjs/discord.js/commit/dfd9eb20b2d3e0e7db26744b1f15134ac6eda139)) +- **Activity:** Remove undocumented properties (#7844) ([5ba7740](https://github.com/discordjs/discord.js/commit/5ba7740fcfefda1eeba81ace4e6351eac02522a4)) +- **MessageAttachment:** Use `Attachment` instead (#7691) ([ab4c608](https://github.com/discordjs/discord.js/commit/ab4c608b97ff319935e1a7f23564622bfd7ddd57)) +- **Util:** Remove splitting (#7780) ([54e5629](https://github.com/discordjs/discord.js/commit/54e56299865a6746744544ba25d5540a1166d27c)) +- Tidy up builders and components (#7711) ([96a0d83](https://github.com/discordjs/discord.js/commit/96a0d83a1366703ecae40b5e0d5171be9123d079)) +- Remove nickname parsing (#7736) ([78a3afc](https://github.com/discordjs/discord.js/commit/78a3afcd7fdac358e06764cc0d675e1215c785f3)) +- Remove store channels (#7634) ([aedddb8](https://github.com/discordjs/discord.js/commit/aedddb875e740e1f1bd77f06ce1b361fd3b7bc36)) +- **IntegrationApplication:** Remove `summary` (#7729) ([eb6b472](https://github.com/discordjs/discord.js/commit/eb6b472f72488cad7e96befccc00270cf6dc01b8)) +- **GuildAuditLogs:** Remove build (#7704) ([cedd053](https://github.com/discordjs/discord.js/commit/cedd0536baa1301984daf89dfda4e63a7be595a2)) +- **InteractionCollector:** Simplify constructor logic (#7667) ([07b23a9](https://github.com/discordjs/discord.js/commit/07b23a99c7088a7c740f23051f3f755f091519b0)) +- Remove undocumented checks (#7637) ([9a6e691](https://github.com/discordjs/discord.js/commit/9a6e691eaa6c3d133098b2734414590cb838de2e)) +- Allow builders to accept emoji strings (#7616) ([fb9a9c2](https://github.com/discordjs/discord.js/commit/fb9a9c221121ee1c7986f9c775b77b9691a0ae15)) +- Use `static` fields (#7701) ([e805777](https://github.com/discordjs/discord.js/commit/e805777a7a81d1dc7a2edd9741ecb04e685a3886)) +- **EmbedBuilder:** Allow hex strings in setColor (#7673) ([f472975](https://github.com/discordjs/discord.js/commit/f4729759f600372455f062c75859f084e23a5d78)) +- Don't return builders from API data (#7584) ([549716e](https://github.com/discordjs/discord.js/commit/549716e4fcec89ca81216a6d22aa8e623175e37a)) +- **embed:** Allow hex strings in `setColor()` (#7593) ([79d6c04](https://github.com/discordjs/discord.js/commit/79d6c0489c3d563fdd05de63c4fcf93a6deefce1)) +- **InteractionResponses:** Use ClientOptions.jsonTransformer (#7599) ([fac55bc](https://github.com/discordjs/discord.js/commit/fac55bcfd1e8b76aae1273415f74fa6de7aca66d)) +- Deprecate invite stage instance (#7437) ([d2bc9d4](https://github.com/discordjs/discord.js/commit/d2bc9d444f42a70a3c4cc4c68eb107bcaebec509)) +- **guild:** Move `premiumSubscriptionCount` to `AnonymousGuild` (#7451) ([6d3da22](https://github.com/discordjs/discord.js/commit/6d3da226d3c003d137639e719394a807330e4844)) +- **actions:** Use optional chaining (#7460) ([d1bb362](https://github.com/discordjs/discord.js/commit/d1bb36256f2f86022884e6ee9e05b0536cb6384d)) +- **guildbanmanager:** Rename days option to deleteMessageDays (#7447) ([0dfdb2c](https://github.com/discordjs/discord.js/commit/0dfdb2cf11e236e67dd34277108973b5b79790a8)) +- Make public builder props getters (#7422) ([e8252ed](https://github.com/discordjs/discord.js/commit/e8252ed3b981a4b7e4013f12efadd2f5d9318d3e)) +- Remove redundant API defaults (#7449) ([532846b](https://github.com/discordjs/discord.js/commit/532846b1f8260d85022a022d093553310052afc9)) +- Allow discord.js builders to accept camelCase (#7424) ([94bf727](https://github.com/discordjs/discord.js/commit/94bf727cc3a2f11c88e95cdb151b235f775cd1ca)) +- Replace `WSCodes`, `WSEvents`, and `InviteScopes` with `discord-api-types` equivalent (#7409) ([cc25455](https://github.com/discordjs/discord.js/commit/cc25455d2c75177e3eddc880b7fd53cb122387c4)) +- Make constants enums top level and `PascalCase` (#7379) ([d8184f9](https://github.com/discordjs/discord.js/commit/d8184f94dd08daab37195f52828e06af5ed1c1e0)) +- **`Bitfield`:** Use discord-api-types enums instead (#7313) ([fbb1d03](https://github.com/discordjs/discord.js/commit/fbb1d0328bcd517027ad2eedb8753d17489ed851)) +- Use `@discordjs/rest` (#7298) ([ec0fba1](https://github.com/discordjs/discord.js/commit/ec0fba1ed0d3c5b1bb18171ece6fe5ee42d48497)) +- Switch to /builders `Embed` (#7067) ([d2d3a80](https://github.com/discordjs/discord.js/commit/d2d3a80c556a104099a1ddb1b24f1b921c553257)) +- Remove transformPermissions (#7303) ([b4ed8fd](https://github.com/discordjs/discord.js/commit/b4ed8fd3ed953085cd908b2845d4384c8555d3a2)) +- Remove VoiceChannel#editable (#7291) ([164589c](https://github.com/discordjs/discord.js/commit/164589c5516a847457444d11098981d557b6778b)) +- Remove boolean option for `Webhook#fetchMessage` (#7293) ([347ff80](https://github.com/discordjs/discord.js/commit/347ff80bbc9bc5243b7f68ba5d745782eadeba21)) +- **subcommandgroup:** Required default to false (#7217) ([6112767](https://github.com/discordjs/discord.js/commit/6112767128a664f32205425f52ba52220d57834f)) +- **invite:** Make `channel` and `inviter` getters (#7278) ([18b0ed4](https://github.com/discordjs/discord.js/commit/18b0ed4cbe8285637a971c7c99ee49d18060a403)) +- Remove required from getMember (#7188) ([c90e47f](https://github.com/discordjs/discord.js/commit/c90e47f90403e5b1b3499b213dcdf2704fd96b66)) +- Remove djs components and use /builders components instead (#7252) ([101d7c5](https://github.com/discordjs/discord.js/commit/101d7c5ffa03edcf8cb8a0647b77d5c9a38e4bdd)) +- Default *URL methods to animated hash (#7149) ([7c07976](https://github.com/discordjs/discord.js/commit/7c07976018728154be0ce0314d3e8dfe8eb9ed5b)) +- Use setPosition inside edit (#7263) ([0b23b7f](https://github.com/discordjs/discord.js/commit/0b23b7f0394a20596c8d85b82870c3f35ea6b0e0)) +- Don't disable import order lint (#7262) ([0a5d5f3](https://github.com/discordjs/discord.js/commit/0a5d5f38c0b1a249fa2efe16f3b601c90622a4d5)) +- Remove discord.js enums and use discord-api-types enums instead (#7077) ([aa6d1c7](https://github.com/discordjs/discord.js/commit/aa6d1c74de01dd9a8f020c43fb2c193c4729df8d)) +- **application:** Remove fetchAssets (#7250) ([1479e40](https://github.com/discordjs/discord.js/commit/1479e40bcecc4c28ecb9f05fa4fbbdfe3bd387e1)) +- PresenceUpdate and demuxProbe (#7248) ([1745973](https://github.com/discordjs/discord.js/commit/174597302408f13c5bb685e2fb02ae2137cb481d)) +- **embeds:** Don't create new embed instances when unnecessary (#7227) ([822dc67](https://github.com/discordjs/discord.js/commit/822dc678da626de7b4fb22a747cd3cd2e8376732)) +- **GuildMember:** Throw better errors on #kickable and #bannable (#7137) ([4fd127e](https://github.com/discordjs/discord.js/commit/4fd127e79edfa1851f8a10242838f9d7aa68c8c3)) +- **SnowflakeUtil:** Switch to `@sapphire/snowflake` (#7079) ([e082dfb](https://github.com/discordjs/discord.js/commit/e082dfb1584926e4c05face5966d16e4a2921bc5)) +- **InteractionCreate:** Remove interaction event (#6326) ([ae876d9](https://github.com/discordjs/discord.js/commit/ae876d962453ccf843f8e6f70666a98a3173bb75)) +- **MessageCreate:** Remove message event (#6324) ([171e917](https://github.com/discordjs/discord.js/commit/171e917fb96b6bf39a6ad70e83be646f72fe451e)) +- **integration:** Turn undefined into null and consistency (#7209) ([13eb782](https://github.com/discordjs/discord.js/commit/13eb78256da901e6c3c405f546f36617ef5e8239)) +- Remove `deleted` field (#7092) ([cee7fd1](https://github.com/discordjs/discord.js/commit/cee7fd181c464e44eabf20b511d12589f2453722)) +- **Dates:** Save timestamps everywhere and use Date.parse (#7108) ([55e21f5](https://github.com/discordjs/discord.js/commit/55e21f53663a91863c63b6d9f3a8c35564664061)) +- **RoleManager:** Remove `comparePositions()` (#7201) ([fbbac27](https://github.com/discordjs/discord.js/commit/fbbac279789427b2c36869dc47b65fb08431e14d)) +- Better Command Terminology (#7197) ([b7856e7](https://github.com/discordjs/discord.js/commit/b7856e7809ff6fa21fe00286f885808535624f7c)) +- **Actions:** Remove deleted maps (#7076) ([5022b14](https://github.com/discordjs/discord.js/commit/5022b14da09e9b421f947e9bc385a0574cbf07d1)) +- **Client:** Remove applicationCommand events (#6492) ([6085b4f](https://github.com/discordjs/discord.js/commit/6085b4f72723d4ff82f7fea504241d14c94af21e)) +- Remove `Util.removeMentions()` (#6530) ([0c24cc8](https://github.com/discordjs/discord.js/commit/0c24cc8ec0d818315cc8f8bcf74fce060847ac79)) +- **Constants:** Change APPLICATION_COMMAND -> CHAT_INPUT_COMMAND (#7018) ([75616a3](https://github.com/discordjs/discord.js/commit/75616a305f9af33013486b13a872a39212101ce7)) +- **Guild:** Remove deprecated setXPositions methods (#6897) ([43e5e3c](https://github.com/discordjs/discord.js/commit/43e5e3c339a96fa895267d4538eee1d5e5843d05)) +- **UserFlags:** Update flag names (#6938) ([b246fc4](https://github.com/discordjs/discord.js/commit/b246fc4101b8e4957ffd1af8e2e4986a020ca211)) + +## Styling + +- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629)) + +## Typings + +- **GuildFeature:** Allow feature strings to be passed (#8264) ([b7d4e55](https://github.com/discordjs/discord.js/commit/b7d4e55419207d4e25f5c40cab221c7c04a617bf)) +- **CategoryChannelChildManager:** Fix Holds type (#8288) ([33a7a5c](https://github.com/discordjs/discord.js/commit/33a7a5cbdc00d2a5034dc1ec91fec5da7042f9d0)) +- Remove `MemberMention` (#8292) ([bf65b37](https://github.com/discordjs/discord.js/commit/bf65b37d1a9ea8417e26ad4afacea1eb45a0ff5a)) +- **GuildMemberManager:** Fix placement for `fetchMe()` (#8258) ([7525615](https://github.com/discordjs/discord.js/commit/75256153a9923d94ca709a37aaccc48dfb43c153)) +- Convert `Events` to an enum (#8246) ([feb3bdd](https://github.com/discordjs/discord.js/commit/feb3bdda0a3c3da80378c8cbcafca2968551eef9)) +- **GuildMemberManager:** Non-void return of `edit()` (#8186) ([c7a205f](https://github.com/discordjs/discord.js/commit/c7a205f7b992eea43af13a4638e2a03db7bc0d8a)) +- Add missing shard types (#8180) ([27d8deb](https://github.com/discordjs/discord.js/commit/27d8deb4716a87704370a95103b16fa1b763de18)) +- Implement `GuildChannelEditOptions` (#8184) ([b83e0c0](https://github.com/discordjs/discord.js/commit/b83e0c0caffc2b767aa1ba4412580970a6901899)) +- **Status:** Add missing members (#8179) ([8421f92](https://github.com/discordjs/discord.js/commit/8421f9203bd2d85ef8e64c3fb9a991c74223a75d)) +- **GuildScheduledEvent#scheduledStartAt:** Should be nullish (#8111) ([65dc8d6](https://github.com/discordjs/discord.js/commit/65dc8d677ee81469c0eeb4ecdd83fe2f68cc8982)) +- Fix modal builder constructor data type (#8143) ([7279f9c](https://github.com/discordjs/discord.js/commit/7279f9c31b14bc1e78c63b7298e80e37ca5dfe0c)) +- Use `ThreadAutoArchiveDuration` from discord-api-types (#8145) ([a3799f9](https://github.com/discordjs/discord.js/commit/a3799f9ebb027904830457119708d550e2009200)) +- **Shard#reconnecting:** Fix event name (#8118) ([95e6d6e](https://github.com/discordjs/discord.js/commit/95e6d6ede03c4fb92a8d8027a085e84b043fd895)) +- **ApplicationCommand:** Fix typo in setDMPermission (#8097) ([4df491c](https://github.com/discordjs/discord.js/commit/4df491ce8578a1b01ee8412a4df8137a302e7202)) +- Fix `setType()` parameter and `ChannelData.type` (#8089) ([b4e28a8](https://github.com/discordjs/discord.js/commit/b4e28a8ff6bf165c54a8726d3bc3a3cc0c1e469b)) +- Fix `ApplicationCommandPermissionsUpdate` event typings (#8071) ([9964454](https://github.com/discordjs/discord.js/commit/9964454c2944a0523399481a5f609144486e549b)) +- **AutocompleteOption:** Fix and improve types (#8069) ([476b7d5](https://github.com/discordjs/discord.js/commit/476b7d519c719152ea04e207f6dd09bb23e733db)) +- **ThreadMemberManager:** Fix return type of fetching members with no arguments (#8060) ([2392a6f](https://github.com/discordjs/discord.js/commit/2392a6f5de2efcf6b326173d26295c928b94adb6)) +- Remove isAutocomplete typeguard from typings (#8063) ([c0f079d](https://github.com/discordjs/discord.js/commit/c0f079d2325a636c83ac676c525bfa89ce308b3c)) +- **AttachmentBuilder:** Fix data type (#8016) ([7fa698d](https://github.com/discordjs/discord.js/commit/7fa698d23e548987762c4c66c96c510d9ea56eb4)) +- **modal:** Fix `showModal()` typings (#8014) ([0ccc243](https://github.com/discordjs/discord.js/commit/0ccc243c8ffbf852660c899cc2ad47bd5ebb65cb)) +- Fix some attachment related typings (#8013) ([6aa6232](https://github.com/discordjs/discord.js/commit/6aa623240ee94b117c7e69c1d09b50923a8f7a4c)) +- **AttachmentBuilder:** Remove name parameter from constructor (#8008) ([6266b0c](https://github.com/discordjs/discord.js/commit/6266b0c1e323f9522010f90f34ce6f17fcb6e769)) +- Add types to `EventEmitter` static methods (#7986) ([d60c464](https://github.com/discordjs/discord.js/commit/d60c464e618e4159d2656e7832798909832f33cd)) +- Nullify `guildScheduledEventUpdate`'s old parameter (#7955) ([fdeac9d](https://github.com/discordjs/discord.js/commit/fdeac9d9fba06c532eca296ddd8479047bc732bf)) +- Make `CacheType` generic more accurate for return values (#7868) ([e07b910](https://github.com/discordjs/discord.js/commit/e07b910e684bc3cf71fb93417951ad42351bace4)) +- **guildScheduledEvent:** Mark `entityMetadata` as nullable (#7908) ([64bdf53](https://github.com/discordjs/discord.js/commit/64bdf53116945ffb51764bb8ec539d530aefcfb1)) +- **discord.js:** Export missing enums (#7864) ([5eeef3f](https://github.com/discordjs/discord.js/commit/5eeef3f708eb900ec994d837fb4cd414a4f4b437)) +- Fix return type of `toString()` on channels (#7836) ([ece6289](https://github.com/discordjs/discord.js/commit/ece628986c7eb1a66f46076d8f8518c9ff00aaf3)) +- **Message#activity:** Make `partyId` optional and use enum for `type` (#7845) ([bfeaf85](https://github.com/discordjs/discord.js/commit/bfeaf856f76eb7cb756ac55aac13636ccdb345b6)) +- Cleanup *Data type definitions (#7716) ([585169f](https://github.com/discordjs/discord.js/commit/585169f2f097ffb1940d17f549e4290aa55acde2)) +- Fix BooleanCache never resolving to true (#7809) ([440ac24](https://github.com/discordjs/discord.js/commit/440ac243ca1d6f8cd04603e63e3f2f6ea1722ee8)) +- **CommandInteraction:** Add awaitModalSubmit (#7811) ([a6d9ce5](https://github.com/discordjs/discord.js/commit/a6d9ce57c6cae90d0afc60010cad44fdc2c2d06c)) +- **ThreadChannel:** Fix autoArchiveDuration types (#7816) ([0857476](https://github.com/discordjs/discord.js/commit/08574763eb665b5a43ccfb826929f1e3f0d1c3a7)) +- Add missing typing (#7781) ([f094e33](https://github.com/discordjs/discord.js/commit/f094e338617a1a3c9f48a325e4b8e9b5a405aa91)) +- **VoiceChannel:** Nullify property (#7793) ([446eb39](https://github.com/discordjs/discord.js/commit/446eb390ce58b7e7f60e297b25f53773a55f7fb9)) +- **ModalSubmitInteraction:** Message (#7705) ([b577bcc](https://github.com/discordjs/discord.js/commit/b577bcc1df5c6424fef9984e19a5f11c77371cf3)) +- **Embed:** Add missing getters and add video to EmbedData (#7728) ([fd1dc72](https://github.com/discordjs/discord.js/commit/fd1dc72c0a77dbe18753d8db22972dfa5fe4ab36)) +- **ModalSubmitInteraction:** Fix `components` type (#7732) ([6f4e97b](https://github.com/discordjs/discord.js/commit/6f4e97bfafe4a058f6ec85d321676401d701ee55)) +- **interactionCollector:** Filter should have a collected argument (#7753) ([e4f2705](https://github.com/discordjs/discord.js/commit/e4f27051ca921d299c302b600a8c2917e9356ef6)) +- Fix regressions (#7649) ([5748dbe](https://github.com/discordjs/discord.js/commit/5748dbe08783beb80c526de38ccd105eb0e82664)) +- **Constants:** Add `NonSystemMessageTypes` (#7678) ([9afc030](https://github.com/discordjs/discord.js/commit/9afc03054e4c8973702d6c18e618643f76382dd9)) +- Fix auto archive duration type (#7688) ([8e3b2d7](https://github.com/discordjs/discord.js/commit/8e3b2d7abd38136534969cf77c6a748ee3a20355)) +- **InteractionResponseFields:** Add webhook (#7597) ([daf2829](https://github.com/discordjs/discord.js/commit/daf2829cb58d1a44cb1f1ece21e428d1a23e99c9)) +- **Embed:** Add forgotten `footer` type (#7665) ([8fb9816](https://github.com/discordjs/discord.js/commit/8fb98165a9d098ab316475d6baacb015783eb638)) +- **ColorResolvable:** Simplify string types (#7643) ([2297c2b](https://github.com/discordjs/discord.js/commit/2297c2b9479ace16f5f7155479605a4ac2718e3d)) +- Allow component classes in action row data (#7614) ([230c0c4](https://github.com/discordjs/discord.js/commit/230c0c4cb137882ff7bab783a4aeaa83ae941de5)) +- **ActionRow:** Allow components to be passed to constructors (#7531) ([e71c76c](https://github.com/discordjs/discord.js/commit/e71c76c7f795837dbcc3576e507bd286640b4296)) +- **showModal:** Align types with the documentation (#7600) ([0d7e4ed](https://github.com/discordjs/discord.js/commit/0d7e4edd969513692c061c107be4bbe7e4b54321)) +- Modals type and doc fixes (#7608) ([93854a8](https://github.com/discordjs/discord.js/commit/93854a8013d07234cb849bfcbfa99f74a4c3cdb4)) +- **InteractionResponseFields:** Add boolean properties (#7565) ([53defb8](https://github.com/discordjs/discord.js/commit/53defb82e36108468e35077b887ee28b811891ab)) +- Allow raw components for reply and message options (#7573) ([2d4971b](https://github.com/discordjs/discord.js/commit/2d4971b032a01c05b55c93d6475e61b0d25d69d3)) +- Fix component *Data types (#7536) ([a8321d8](https://github.com/discordjs/discord.js/commit/a8321d8026df2e6a09d867939986bf77f894f3a8)) +- Use discord-api-types `Locale` (#7541) ([8346003](https://github.com/discordjs/discord.js/commit/83460037be840ba623f3b02a3e6f218943f9d2b7)) +- **anychannel:** Add PartialGroupDMChannel (#7472) ([cf66930](https://github.com/discordjs/discord.js/commit/cf669301c7be8eaecf91d7f764eccc67d7a5b4c6)) +- Remove `ApplicationCommandInteractionOptionResolver` (#7491) ([71f4fa8](https://github.com/discordjs/discord.js/commit/71f4fa82ed6206d6843345a5394119f2a728aa35)) +- **embed:** Fix timestamp allowed types (#7470) ([7959a68](https://github.com/discordjs/discord.js/commit/7959a68d8ec600af248f5506f39871cae7eeeb04)) +- Remove duplicate rate limit for thread creation (#7465) ([2d2de1d](https://github.com/discordjs/discord.js/commit/2d2de1d3fd15a098d69e09710e9a7a3352234fef)) +- Correct types for InteractionCollector guild and channel (#7452) ([6ce906a](https://github.com/discordjs/discord.js/commit/6ce906a02fcb051cb6df3e9f453ba9f53db03bd0)) +- Fix `GuildAuditLogsTypes` keys & typos (#7423) ([3d8c776](https://github.com/discordjs/discord.js/commit/3d8c77600be51a86a99b526078bb1b1fcb9a0811)) +- Remove duplicate `GuildChannelOverwriteOptions` interface (#7428) ([83458ff](https://github.com/discordjs/discord.js/commit/83458ff7c782b8efdaaac931d2dee1764dad25bf)) +- Use `GuildFeature` enum from `discord-api-types` (#7397) ([a7b80b9](https://github.com/discordjs/discord.js/commit/a7b80b9d9bf4902bd85b592986771eadf7a765dc)) +- Fix *BitField.Flags properties (#7363) ([e6a26d2](https://github.com/discordjs/discord.js/commit/e6a26d25b3cf8dfcc8aa8997b021f1774f3b754b)) +- Fix MessageMentions channel types (#7316) ([c05b388](https://github.com/discordjs/discord.js/commit/c05b38873bb3c37c6e4ebcb6b6373a8858cc03de)) +- Fix channel create overloads (#7294) ([1c6c944](https://github.com/discordjs/discord.js/commit/1c6c9449ad68601c6c98748d73be8114401d38ef)) +- Fix regressions and inconsistencies (#7260) ([26a9dc3](https://github.com/discordjs/discord.js/commit/26a9dc32062cd071917bbe7264050315b4d6dd3c)) +- **interaction:** Remove renamed typeguards (#7220) ([68b9564](https://github.com/discordjs/discord.js/commit/68b9564f1821726377a1e929a3ca1fc65b4ad598)) +- AssertType -> expectType ([3f36746](https://github.com/discordjs/discord.js/commit/3f36746561a40cd61a7cd2e054b7ef80d58fc707)) +- Fix cache types resolving to `never` (#7164) ([c978dbb](https://github.com/discordjs/discord.js/commit/c978dbb6233bcd85408caf0bca7619c9c5d508f0)) + +# [14.13.0](https://github.com/discordjs/discord.js/compare/14.12.1...14.13.0) - (2023-08-17) + +## Bug Fixes + +- **Action:** Do not add the client user as a recipient (#9774) ([24fbb11](https://github.com/discordjs/discord.js/commit/24fbb11ba2f7e8f8f604752159d2053f2cee16ec)) +- **DMChannel:** Correct partial typo (#9773) ([c1ff545](https://github.com/discordjs/discord.js/commit/c1ff545bf1c018875f5a9ceb828c9f84ed391920)) +- **CachedManager:** Allow overriding constructor for makeCache (#9763) ([346fa57](https://github.com/discordjs/discord.js/commit/346fa57f95a99d5b4e1169bb85706c4c25bf71d0)) +- **types:** Fixed CachedManager constructor arguments in type (#9761) ([b3c85d3](https://github.com/discordjs/discord.js/commit/b3c85d34a6ced8a8e2cd15a6e3879fb2dd5121d0)) +- **Action:** Do not set `undefined` values (#9755) ([d8e3755](https://github.com/discordjs/discord.js/commit/d8e37551ceefe9f82566e3f45edc69bb7f9d1463)) + +## Documentation + +- **EmbedBuilder:** `@readonly` length (#9778) ([8f572a6](https://github.com/discordjs/discord.js/commit/8f572a6badd45b916d3a46dd489653d2d6efb2a8)) +- **WebhookEditOptions:** Add all of the types (#9776) ([d5be424](https://github.com/discordjs/discord.js/commit/d5be4242c6a6f90b90af54e27071ecc0f5422944)) +- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6)) + +## Features + +- **Client:** Add deleteWebhook method (#9777) ([d90ba8d](https://github.com/discordjs/discord.js/commit/d90ba8dce8de630db14b77764ec35201998c7ce7)) +- **ClientPresence:** Allow setting activity state (#9743) ([9ed1b59](https://github.com/discordjs/discord.js/commit/9ed1b59df6acb6356d5950b43d04885d5e692887)) +- **ClientApplication:** Approximate guild count and new `GET` route (#9713) ([632a9b4](https://github.com/discordjs/discord.js/commit/632a9b4965cd24ffffdf0f88f1a9eedeb6b284f7)) +- **Role:** Add `flags` (#9694) ([3b18e5b](https://github.com/discordjs/discord.js/commit/3b18e5b08dc3ec2aba37d3e6a55e42ce8af7dbab)) +- **Attachment:** Add `flags` (#9686) ([692f0fc](https://github.com/discordjs/discord.js/commit/692f0fc96d9f92161b64fb83f02b71d43d2d7c9c)) +- Add `Client#webhooksUpdate` (#9732) ([0de071d](https://github.com/discordjs/discord.js/commit/0de071d0a5524ba1fbb8cab5d7e74567103f7129)) + +## Typings + +- **GuildInvitableChannelResolvable:** Allow forum channels (#9775) ([727dc09](https://github.com/discordjs/discord.js/commit/727dc094d52a5b169e46917b64308ab87a7144b1)) +- Make activity name required (#9765) ([0a9a3ed](https://github.com/discordjs/discord.js/commit/0a9a3ede292b92235a103b6776477a707da4d84b)) +- **BaseButtonComponentData:** Narrow component type (#9735) ([a30d46c](https://github.com/discordjs/discord.js/commit/a30d46c5f5909eee86704bbb9e34fb7bb09b2c27)) + +# [14.12.1](https://github.com/discordjs/discord.js/compare/14.12.0...14.12.1) - (2023-08-01) + +## Bug Fixes + +- **BaseClient:** Fix destroy method (#9742) ([1af7e5a](https://github.com/discordjs/discord.js/commit/1af7e5a0bb4eca35221cb342c1c53dc18263c789)) + +# [14.12.0](https://github.com/discordjs/discord.js/compare/14.11.0...14.12.0) - (2023-07-31) + +## Bug Fixes + +- **ChannelUpdate:** Check against unknown channels (#9697) ([7fb91c5](https://github.com/discordjs/discord.js/commit/7fb91c57f72b74395d67f2207246033c703f1f19)) +- **Action:** Use existing recipients if available (#9653) ([719e54a](https://github.com/discordjs/discord.js/commit/719e54a921f74890519f066a9f56e52fdcfacf07)) +- Everyone role members (#9685) ([0803eb5](https://github.com/discordjs/discord.js/commit/0803eb562bdc7644fa611a0a87dea3e8b0d4c7af)) +- `awaitMessageComponent` with `MessageComponentInteraction`s (#8598) ([b61e4fb](https://github.com/discordjs/discord.js/commit/b61e4fb0dcb9e5d43a7626c5a4760f5801e06fae)) +- **ThreadManager:** Fix internal crash upon conditionally resolving thread members (#9648) ([a6dbe16](https://github.com/discordjs/discord.js/commit/a6dbe163dd3df12ad98465b1dfc040b8eff8805e)) +- **User:** Check global name in equals (#9631) ([8f3bd38](https://github.com/discordjs/discord.js/commit/8f3bd3807233fca2a057948406bdc8aef008b6cb)) +- **WebSocketManager:** Await WebSocket destroy (#9519) ([75308f2](https://github.com/discordjs/discord.js/commit/75308f266933454301b10ee8e1d940d782fdb637)) +- **Client:** Safe call for possibly null WebSocket (#9600) ([24a6149](https://github.com/discordjs/discord.js/commit/24a61495b9bf07887dd535a05ffbec2895faa888)) +- **ThreadManager:** Ensure `fetchActive()` only returns active threads in a channel (#9568) ([53aa24d](https://github.com/discordjs/discord.js/commit/53aa24d41809382c1af57bd1871107c8359e4a15)) +- **LimitedCollection:** Allow items to be stored if keepOverLimit is true when maxSize is 0 (#9534) ([9345d1b](https://github.com/discordjs/discord.js/commit/9345d1b1ac4f7b1f66b919602dff995782151407)) +- **AutocompleteInteraction:** Prevent snake casing of locales (#9565) ([7196fe3](https://github.com/discordjs/discord.js/commit/7196fe36e8089dde7bcaf0db4dd09cf524125e0c)) + +## Documentation + +- Change `Channel` to `BaseChannel` (#9718) ([e5effb6](https://github.com/discordjs/discord.js/commit/e5effb6f6a3e547006eb9bc054cc168844a157f2)) +- **BaseChannel:** Remove `APIChannel` (#9717) ([125405f](https://github.com/discordjs/discord.js/commit/125405f1cf11433c69ff1ae9d6b8f7e713fc37c0)) +- **BuildersSelectMenuOption:** Update link (#9690) ([ede9f4e](https://github.com/discordjs/discord.js/commit/ede9f4e5e203bcfb8820ae7ec3418482735ff9c1)) +- **ClientOptions:** Change default value of sweepers in docs (#9591) ([911e6ef](https://github.com/discordjs/discord.js/commit/911e6eff75f5d05e837d5dfaacf557d6594df16a)) +- **Client:** Correct invite gateway permission checks (#9597) ([e1b6eee](https://github.com/discordjs/discord.js/commit/e1b6eeed0e2e18f9900bc945c9f82d2d05f28a78)) +- Fix broken links to new documentation (#9563) ([d01e8aa](https://github.com/discordjs/discord.js/commit/d01e8aa8af00f5caacffe98caef3ead02e80a9bf)) + +## Features + +- Add ws option support for "buildIdentifyThrottler" (#9728) ([6307f81](https://github.com/discordjs/discord.js/commit/6307f813854ed9dc76d2c4351bd69dd0490d0928)) +- **Client:** Add `guildAvailable` event (#9692) ([3c85fb2](https://github.com/discordjs/discord.js/commit/3c85fb21e62b30e75a7200b704e242c3a0adeda1)) +- User avatar decorations (#8914) ([8d97017](https://github.com/discordjs/discord.js/commit/8d9701745840e23854e8f0b057d21cb10e7d1d54)) +- Add silent option to ShardingManager (#9506) ([df40dcd](https://github.com/discordjs/discord.js/commit/df40dcdb850c398642ebc5cd6e4c48034280f464)) +- **EmbedBuilder:** Add `.length` (#8682) ([53c17e0](https://github.com/discordjs/discord.js/commit/53c17e00c0668c3d1497142dde7384c058c46c64)) +- Guild onboarding (#9120) ([dc73c93](https://github.com/discordjs/discord.js/commit/dc73c938ff9d04a0d7d57630faeb8e81ea343006)) +- Add resume event in shard (#9650) ([a73d54e](https://github.com/discordjs/discord.js/commit/a73d54e43a01719f683e8fd21714e85ffe737add)) +- **presence:** Re-introduce image resolving for other platforms (#9637) ([73c2f8a](https://github.com/discordjs/discord.js/commit/73c2f8aa17aac51b05382444148cb1f60081ee03)) +- Add message to send resume event to shard (#9626) ([a873ec1](https://github.com/discordjs/discord.js/commit/a873ec1e8511829ba95e85bbc9a4074e40c76086)) +- Support new username system (#9512) ([1ab60f9](https://github.com/discordjs/discord.js/commit/1ab60f9da4d6b7ea144fa05b97b029a4bfaeede2)) +- **GuildAuditLogsEntry#extra:** Add missing `channel` property (#9518) ([2272321](https://github.com/discordjs/discord.js/commit/227232112d1cd9f211e177996b7cdee2940f471e)) + +## Performance + +- **Channel:** Linear speed position getter (#9497) ([09b0382](https://github.com/discordjs/discord.js/commit/09b0382c458ed0f3df5b8fa778c504b3e658ac49)) +- **Role:** Improve `members` getter (#9529) ([37181ab](https://github.com/discordjs/discord.js/commit/37181ab2322e48e17ff0d1040bcc510dc7c34e93)) + +## Refactor + +- **User:** Remove deprecation warning from tag (#9660) ([cf8012c](https://github.com/discordjs/discord.js/commit/cf8012c20022aff184d7bce0ad436c136e428d9c)) +- **GuildMember:** Make `_roles` property non-enumerable (#9387) ([46167a7](https://github.com/discordjs/discord.js/commit/46167a79d7d0cac5599459a31c33b2bbcf6e06da)) +- **rest:** Switch api to fetch-like and provide strategies (#9416) ([cdaa0a3](https://github.com/discordjs/discord.js/commit/cdaa0a36f586459f1e5ede868c4250c7da90455c)) + - **BREAKING CHANGE:** NodeJS v18+ is required when using node due to the use of global `fetch` + - **BREAKING CHANGE:** The raw method of REST now returns a web compatible `Respone` object. + - **BREAKING CHANGE:** The `parseResponse` utility method has been updated to operate on a web compatible `Response` object. + - **BREAKING CHANGE:** Many underlying internals have changed, some of which were exported. + - **BREAKING CHANGE:** `DefaultRestOptions` used to contain a default `agent`, which is now set to `null` instead. + +## Typings + +- **MessageManager:** Allow comparison of messages again (#9612) ([a48d0ef](https://github.com/discordjs/discord.js/commit/a48d0efb09613eac6bf3c1bd996f58f5fff7667c)) +- **AutoModerationActionExecution:** Add forum channels as a possible type in `channel()` (#9623) ([d64330a](https://github.com/discordjs/discord.js/commit/d64330a1570b3a2047ef959a6bce268372c70e99)) +- **ModalSubmitFields:** Components is an array (#9406) ([1cab79f](https://github.com/discordjs/discord.js/commit/1cab79f6fde6f367141c9f7ed91bcb70ed2e5c17)) +- Use `readonly` arrays and `const` type parameters in places (#9641) ([cd69868](https://github.com/discordjs/discord.js/commit/cd6986854f4c2d143d2cd9b81d096738480dfa63)) +- **BaseInteraction:** `appPermissions` not `null` in guilds (#9601) ([6c2242f](https://github.com/discordjs/discord.js/commit/6c2242f4f970b1c75c243f74ae64f30ecbf8ba0d)) + +# [14.11.0](https://github.com/discordjs/discord.js/compare/14.10.2...14.11.0) - (2023-05-06) + +## Bug Fixes + +- **WebSocketManager:** Properly emit shard error events (#9521) ([e627468](https://github.com/discordjs/discord.js/commit/e6274681fd10b0d75e1d3b448c94b50ec6810367)) +- **WebSocketManager:** Emit raw ws events again (#9502) ([c429763](https://github.com/discordjs/discord.js/commit/c429763be8e94f0f0cbc630e8bb1d415d46f1465)) + +## Documentation + +- **Client:** Update Sapphire's snowflake utility links (#9501) ([1b7981e](https://github.com/discordjs/discord.js/commit/1b7981e4696b8ae74ceffa876fc0a9be7d0b9f93)) + +## Features + +- **Guild:** Safety alerts channel and mention raid protection (#8959) ([6b2c3fb](https://github.com/discordjs/discord.js/commit/6b2c3fb9d0571de808e990cf064f73240ab93451)) + +## Performance + +- **Role:** Linear speed position getter (#9493) ([8e9a2b4](https://github.com/discordjs/discord.js/commit/8e9a2b4630f78bb9e45345ec2a16812bfac70a20)) + +## Refactor + +- **GuildChannel:** Simplify constructor (#9499) ([f2ad076](https://github.com/discordjs/discord.js/commit/f2ad0762c521422ab64e5b10344a6fd67961031b)) + +## Typings + +- **StringSelectMenuComponentData:** `options` is required (#9515) ([d7b18f0](https://github.com/discordjs/discord.js/commit/d7b18f0681d4147ff192c98108c035d6d0f96cce)) + +# [14.10.2](https://github.com/discordjs/discord.js/compare/14.10.1...14.10.2) - (2023-05-01) + +## Bug Fixes + +- Correct `isJSONEncodable()` import (#9495) ([201b002](https://github.com/discordjs/discord.js/commit/201b002ad405b845ace5f708077c1f157bb4126d)) +- **Client:** `generateInvite()` scope validation (#9492) ([b327f49](https://github.com/discordjs/discord.js/commit/b327f4925ff557e0aa8273d7f017aa616226ca06)) + +# [14.10.1](https://github.com/discordjs/discord.js/compare/14.10.0...14.10.1) - (2023-05-01) + +## Bug Fixes + +- **Client:** Spelling of InvalidScopesWithPermissions ([ac9bf3a](https://github.com/discordjs/discord.js/commit/ac9bf3ac06ec78dbaca2ce4a82cceb0d82484211)) + +## Refactor + +- **ShardClientUtil:** Logic de-duplication (#9491) ([a9f2bff](https://github.com/discordjs/discord.js/commit/a9f2bff82a18c6a3afdee99e5830e1d7b4da65dc)) + +# [14.10.0](https://github.com/discordjs/discord.js/compare/14.9.0...14.10.0) - (2023-05-01) + +## Bug Fixes + +- **ShardClientUtil:** Fix client event names (#9474) ([ad217cc](https://github.com/discordjs/discord.js/commit/ad217cc7604dda6a33df73db82799fd5bb4e85a9)) +- **BaseClient:** Prevent user agent mutation (#9425) ([217e5d8](https://github.com/discordjs/discord.js/commit/217e5d81005a2506c96335f7fb96fa21d7dbb04c)) +- **BitField:** Use only enum names in iterating (#9357) ([40d07fb](https://github.com/discordjs/discord.js/commit/40d07fbbbd51d62793d9ea541f41f157b5dad224)) +- Use new permission name (#9274) ([d2d27ce](https://github.com/discordjs/discord.js/commit/d2d27ce7346bc37b34938c84bd3b106a4fa51f53)) +- **Message#editable:** Fix permissions check in locked threads (#9319) ([d4c1fec](https://github.com/discordjs/discord.js/commit/d4c1fecbe264bc52a70aaf0ec303d35e2f15bbcd)) +- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2)) + +## Documentation + +- **AutoModerationRule:** Update docs (#9464) ([1b15d31](https://github.com/discordjs/discord.js/commit/1b15d31b5ae1b1739716fab00b18083c1d7d389a)) +- **APITypes:** Document role & user select menu components (#9435) ([c6ca5a8](https://github.com/discordjs/discord.js/commit/c6ca5a83e7b72613f95c2145606a1330f64ae894)) +- **BaseMessageOptions:** Fix embeds and components (#9437) ([5c52bb9](https://github.com/discordjs/discord.js/commit/5c52bb95906250518a8813820d543f43dd7abdf9)) +- **InteractionResponses:** ShowModal docs change (#9434) ([7d34100](https://github.com/discordjs/discord.js/commit/7d341000d44b762a2fe0434a6b518f7d63539d34)) +- Use ESM code in examples (#9427) ([ce287f2](https://github.com/discordjs/discord.js/commit/ce287f21d1540da7f17cac8a57dc33a67f391ef3)) +- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9)) +- **Options:** Fix links and invalid syntax (#9322) ([86e5f5a](https://github.com/discordjs/discord.js/commit/86e5f5a119c6d2588b988a33236d358ded357847)) +- Cleanup MessageCreateOptions and MessageReplyOptions (#9283) ([300059c](https://github.com/discordjs/discord.js/commit/300059cb266e6cca42c30ee7f997c48ab2cc565e)) +- **Events:** Document auto moderation events (#9342) ([79bcdfa](https://github.com/discordjs/discord.js/commit/79bcdfa767e7e842164e1174b6f4834ed731d329)) +- Add `SnowflakeUtil` (#9371) ([8ffcf77](https://github.com/discordjs/discord.js/commit/8ffcf77840b62590fcb4731380d28b22d0b98741)) +- Use stable tag (#9343) ([c0f2dd7](https://github.com/discordjs/discord.js/commit/c0f2dd713151a29c98e1eebad66721a208be1fc0)) +- Remove `JSONEncondable` (#9344) ([b2eec5f](https://github.com/discordjs/discord.js/commit/b2eec5f9fcf37ebb3b7f87a67a6ee3160c182183)) + +## Features + +- **Attachment:** Voice messages (#9392) ([3e01f91](https://github.com/discordjs/discord.js/commit/3e01f91bbba2cbacacc6c921ed664752f679960b)) +- **BaseInteraction:** Support new channel payload (#9337) ([29389e3](https://github.com/discordjs/discord.js/commit/29389e39f479b832e54c7cb3ddd363aebe99674f)) +- **RoleTagData:** Add guildConnections (#9366) ([2dddbe1](https://github.com/discordjs/discord.js/commit/2dddbe1f321f2e2722dba4a28f7d18384cf50353)) + +## Performance + +- **RoleManager:** Dont call Role#position getter twice per role (#9352) ([bfee6c8](https://github.com/discordjs/discord.js/commit/bfee6c8d889502ea39ad919dd9b1e6253a2af571)) + +## Refactor + +- **WebSocketManager:** Use /ws package internally (#9099) ([a9e0de4](https://github.com/discordjs/discord.js/commit/a9e0de4288ea39a6a089b8379dcd44ac0053dac7)) +- Remove `fromInteraction` in internal channel creation (#9335) ([794abe8](https://github.com/discordjs/discord.js/commit/794abe8450bae000cd0544922cdf53e7b3e4c59c)) + +## Typings + +- **AutoModerationActionMetadataOptions:** Make channel property optional (#9460) ([d26df5f](https://github.com/discordjs/discord.js/commit/d26df5fabaf227fb9d10ba5cc1ab326de55aadbc)) +- **CategoryChannel:** Ensure `parent` and `parentId` are `null` (#9327) ([8218ffc](https://github.com/discordjs/discord.js/commit/8218ffc78d23234b32c05a97fde2f4bea64d7aa6)) +- **GuildTextBasedChannel:** Remove unnecessary exclusion of forum channels (#9326) ([7ff3d52](https://github.com/discordjs/discord.js/commit/7ff3d528d942a0daa990194915ff8328dec99149)) + +# [14.9.0](https://github.com/discordjs/discord.js/compare/14.8.0...14.9.0) - (2023-04-01) + +## Bug Fixes + +- Add support for new guild feature `GUILD_WEB_PAGE_VANITY_URL` (#9219) ([de1aac6](https://github.com/discordjs/discord.js/commit/de1aac674acb3830124646fcd52cdd98cdb71ba5)) +- Resolving string bitfield (#9262) ([7987565](https://github.com/discordjs/discord.js/commit/79875658cf4a8daa25210c2c620c73a710ca22de)) +- **AutocompleteInteraction:** Send `name_localizations` correctly (#9238) ([1864d37](https://github.com/discordjs/discord.js/commit/1864d37d36e53d127e74b6969a5f542193bfc3c7)) +- Keep symbols in actions manager (#9293) ([984bd55](https://github.com/discordjs/discord.js/commit/984bd55b437507e7ebfdf09ac944c8eba0340d27)) +- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b)) +- **ClientUser:** No mutation on edit (#9259) ([abd6ae9](https://github.com/discordjs/discord.js/commit/abd6ae9fc8ea03722e8b36e29c3fdc1c2cfc93e8)) +- **Message#editable:** Update editable check in threads locked (#9216) ([22e880a](https://github.com/discordjs/discord.js/commit/22e880aaa0d8c644fc8d16a524d17f4f53a056f6)) +- **ThreadManager:** Add `members` and conditionally include `hasMore` (#9164) ([e9a8eb3](https://github.com/discordjs/discord.js/commit/e9a8eb323f3a554dc8f9dab361cd1bac7b88e1cc)) +- **ThreadManager:** Respect `cache` and `force` in fetching (#9239) ([cc57563](https://github.com/discordjs/discord.js/commit/cc57563e73d78a0d71d1444d1ee8215a26a81fa8)) +- **TextBasedChannelTypes:** Add `GuildStageVoice` (#9232) ([51edba7](https://github.com/discordjs/discord.js/commit/51edba78bc4d4cb44b4dd2b79e4bbc515dc46f5b)) + +## Documentation + +- Describe private properties (#8879) ([2792e48](https://github.com/discordjs/discord.js/commit/2792e48119f1cf5fa7d5e6b63369457b0719d4e4)) +- Differ `User#send` (#9251) ([384b4d1](https://github.com/discordjs/discord.js/commit/384b4d10e8642f0f280ea1651f33cd378c341333)) +- Fix compare position example (#9272) ([d16114c](https://github.com/discordjs/discord.js/commit/d16114c52646ca92c53f9b44a0dd10af98dbddcd)) +- **Role:** Fix example for `comparePositionTo()` (#9270) ([bc641fa](https://github.com/discordjs/discord.js/commit/bc641fa9360b851642bc51839cef6bd5600d71f7)) +- Add more examples (#9252) ([bf507ab](https://github.com/discordjs/discord.js/commit/bf507ab2659d95e2991e83293b3834f21283ff33)) +- **FetchArchivedThreadOptions:** `before` respects `archive_timestamp`, not creation timestamp (#9240) ([178c8dc](https://github.com/discordjs/discord.js/commit/178c8dcfeea1c4a6a32835baea389f25feefbac7)) +- Update `APISelectMenuComponent` (#9235) ([56cf138](https://github.com/discordjs/discord.js/commit/56cf138e029e7884a4e7efb606055687ca67b4ac)) + +## Features + +- **Guild:** Add `max_stage_video_channel_users` (#8422) ([34bc36a](https://github.com/discordjs/discord.js/commit/34bc36ac4b04ad033d0dcc3d2701fcf2e682743c)) +- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b)) +- Add GuildBasedTextChannelTypes (#9234) ([5f93dcc](https://github.com/discordjs/discord.js/commit/5f93dcce466286f0fdead8faf4131e98d1c9db55)) + +## Refactor + +- Call `GuildBanManager#create()` directly (#9263) ([f340f3b](https://github.com/discordjs/discord.js/commit/f340f3b1fd719e8f7cf6fa28a41835bc16039fc7)) +- **FetchThreadsOptions:** Remove `active` (#9241) ([519e163](https://github.com/discordjs/discord.js/commit/519e163f8aa3b55420f86d2d60c2584b3a2eb327)) + +# [14.8.0](https://github.com/discordjs/discord.js/compare/14.7.1...14.8.0) - (2023-03-12) + +## Bug Fixes + +- **snowflake:** Snowflakes length (#9144) ([955e8fe](https://github.com/discordjs/discord.js/commit/955e8fe312c42ad4937cc1994d1d81e517c413c8)) +- **Actions:** Inject built data by using a symbol (#9203) ([a63ac88](https://github.com/discordjs/discord.js/commit/a63ac88fcca5b61209892a6e560e35d58f5adc3b)) +- **Message#deletable:** Add check for deletable message types (#9168) ([e78b8ad](https://github.com/discordjs/discord.js/commit/e78b8ad3fb6692cba2c565b508254c723f185f0c)) +- **Message:** `bulkDeletable` permissions should be retrieved later for DMs (#9146) ([a9495bd](https://github.com/discordjs/discord.js/commit/a9495bd8f014c8021a214b83ffc531a2af5defef)) +- **AutoModerationActionExecution:** Transform `action` (#9111) ([9156a28](https://github.com/discordjs/discord.js/commit/9156a2889cd0946dfd0b30a5f8365abfbc377b3d)) +- **MessageReaction:** `toJSON()` infinite recursion (#9070) ([f268e1d](https://github.com/discordjs/discord.js/commit/f268e1d9798744e169ae87089ea2e1f214364d95)) +- **ThreadChannel:** Insert starter message from threads created in forum channels (#9100) ([0b76ab4](https://github.com/discordjs/discord.js/commit/0b76ab4c403dd646c71482856ab993b263b7c474)) +- **ApplicationRoleConnectionMetadata:** Export the class correctly (#9076) ([071516c](https://github.com/discordjs/discord.js/commit/071516c35239bd4e1cae572c855d86b335c8536d)) +- Don't auth for interaction `showModal()` (#9046) ([b803a9a](https://github.com/discordjs/discord.js/commit/b803a9a899aaa75a3ea2bc6623c6afb28f495e8c)) +- **WebSocketShard:** Zombie connection fix (#8989) ([876b181](https://github.com/discordjs/discord.js/commit/876b1813128ec702d3ef1e7b0074a4613e88c332)) +- Keep other properties in triggerMetadata (#8977) ([d8dd197](https://github.com/discordjs/discord.js/commit/d8dd197a936dfffc05f9e5bc3184ec9022c56b51)) +- **escapeX:** Emojis with underlines (#8945) ([07b597d](https://github.com/discordjs/discord.js/commit/07b597df16b9412c23ec2387d54564e4d1bcf7ed)) +- **WebSocketShard:** Either start close timeout or emit destroyed but never both (#8956) ([43ce2a5](https://github.com/discordjs/discord.js/commit/43ce2a572eb8977b6994680171ac0c5f9bda1703)) +- **DMChannel:** `recipientId` edge case (#8950) ([7ce9909](https://github.com/discordjs/discord.js/commit/7ce990954e2f73d7a996df0afa42ab287cb12514)) +- Return only boolean for `disabled` (#8965) ([6614603](https://github.com/discordjs/discord.js/commit/66146033268a4db1279b2eaee4bd418f326c0d4b)) +- Export missing `escapeX()` functions (#8944) ([25c27ea](https://github.com/discordjs/discord.js/commit/25c27eac1417e75c9b601b17cf177b1f47b699a9)) +- **WebSocketShard:** Only cleanup the connection if a connection still exists (#8946) ([5eab5fc](https://github.com/discordjs/discord.js/commit/5eab5fc06ca6be36ecf1557f2ad29a670d4d5ae7)) +- Add `@discordjs/formatters` to dependency list (#8939) ([18b3a19](https://github.com/discordjs/discord.js/commit/18b3a19810a6436fa8bb4b490ec5137eaecbd465)) +- **resolveColor:** Invalid colors (#8933) ([c76e170](https://github.com/discordjs/discord.js/commit/c76e17078602914c3e1d227a3acc98eaa99c18d4)) +- **WebSocketShard:** Clear listeners on reconnect (#8927) ([aa8c57d](https://github.com/discordjs/discord.js/commit/aa8c57dab60104549e28451abf35c0387595d67e)) +- Re-export formatters (#8909) ([b14604a](https://github.com/discordjs/discord.js/commit/b14604abdecca575b1fca693c1593e3585bcca8c)) + +## Documentation + +- **MessageManager:** Add clarification to fetch messages (#9222) ([f5ec1ca](https://github.com/discordjs/discord.js/commit/f5ec1cada5ebf0ca4093bdfc81aaf56900c794ef)) +- Make interactionResponse as optional (#9179) ([664cccb](https://github.com/discordjs/discord.js/commit/664cccb2706db33635aa2556954de57f93b3d3db)) +- Fix typos (#9127) ([1ba1f23](https://github.com/discordjs/discord.js/commit/1ba1f238f04221ec890fc921678909b5b7d92c26)) +- **chatInputApplicationCommandMention:** Parameters are not nullable (#9091) ([6f78e82](https://github.com/discordjs/discord.js/commit/6f78e8285b3ce762de010e68d49b377a47dc5a63)) +- No `@type` description and reveal info block (#9097) ([405f940](https://github.com/discordjs/discord.js/commit/405f9400e8e3ffea9f3847ab5abb431a34538a96)) +- **ThreadEditOptions:** Move info tag back to `invitable` (#9020) ([f3fe3ce](https://github.com/discordjs/discord.js/commit/f3fe3ced622676b406a62b43f085aedde7a621aa)) +- Fix a typo in the MentionableSelectMenuInteraction link (#9000) ([6d7a143](https://github.com/discordjs/discord.js/commit/6d7a143667f33ef2ea45d8016ac4738237707881)) +- **ApplicationRoleConnectionMetadata:** Add documentation (#8976) ([2e22b31](https://github.com/discordjs/discord.js/commit/2e22b31892d9b858fcb24fa580b486b4154e823f)) +- Fix malformed overridden documentation (#8954) ([0b8b114](https://github.com/discordjs/discord.js/commit/0b8b114761f961a2bf8e5aae342ed711b154a89e)) +- **GuildForumThreadManager:** Fix `sticker` type (#8940) ([dd62be0](https://github.com/discordjs/discord.js/commit/dd62be077d3e4fbd73a0c10ca344d93d3d19fa38)) +- Fix deprecated links (#8907) ([976b234](https://github.com/discordjs/discord.js/commit/976b234e9dc9999e5dee47b58c85afbc1cd494c2)) +- **UserFlagsBitField:** Make `.Flags` static (#8902) ([c48ff5e](https://github.com/discordjs/discord.js/commit/c48ff5e4205899e3b6cd35812ca857236bef6864)) + +## Features + +- **Collector:** Add lastCollectedTimestamp (#9044) ([4458a13](https://github.com/discordjs/discord.js/commit/4458a13925164762b519ded1037ae8775d879f71)) +- **StageChannel:** Add messages (#9134) ([ffdb197](https://github.com/discordjs/discord.js/commit/ffdb197f988657100e2a9ff0ca17b759339a1dda)) +- **AutoModerationActionExecution:** Add `channel`, `user` and `member` getters (#9142) ([095bd77](https://github.com/discordjs/discord.js/commit/095bd77515aa31bb0e95a350b4355980fea9268d)) +- **AutoModeration:** Support `custom_message` (#9171) ([c1000b8](https://github.com/discordjs/discord.js/commit/c1000b86ed6d5413afcd6ee7e80505e5a845430b)) +- **ThreadMemberManager:** Support pagination fetching (#9035) ([765d5a3](https://github.com/discordjs/discord.js/commit/765d5a3b2d5529c3a2a4b29512f6932264443ed1)) +- **InteractionResponse:** Add new methods (#9132) ([dc9924f](https://github.com/discordjs/discord.js/commit/dc9924fb5f24c8dac963d6b86ba279a89545e73b)) +- **GuildMember:** Add `flags` (#9087) ([76b2116](https://github.com/discordjs/discord.js/commit/76b21162aca7cd4897826437da3063524e1e7553)) +- **Client:** `guildAuditLogEntryCreate` event (#9058) ([9439107](https://github.com/discordjs/discord.js/commit/9439107a1d6a9b77b5f991973d96bc6100da4753)) +- Add role subscription data (#9025) ([1ba22f4](https://github.com/discordjs/discord.js/commit/1ba22f4c9e4173f8866339d3eadb2939d4b32034)) +- **Sticker:** Add support for gif stickers (#9038) ([6a9875d](https://github.com/discordjs/discord.js/commit/6a9875da054a875a4711394547d47439bbe66fb6)) +- **GuildAuditLogs:** Support `after` (#9011) ([0076589](https://github.com/discordjs/discord.js/commit/0076589ccc93e09d77a448874d1ceff5d0e91aa2)) +- Add role subscriptions (#8915) ([3407e1e](https://github.com/discordjs/discord.js/commit/3407e1eea3c8d5629465553f342ac30ceae27a47)) +- Add `not_found` to guild member chunk data (#8975) ([be294ea](https://github.com/discordjs/discord.js/commit/be294eaf9901ea139ce485deeec9178959ffa91f)) +- **ClientApplication:** Add role connections (#8855) ([22e2bbb](https://github.com/discordjs/discord.js/commit/22e2bbb0d24e3f30516f262308d5786f2f666713)) +- **CommandInteractionOptionResolver:** Add `channelTypes` option to `getChannel` (#8934) ([429dbcc](https://github.com/discordjs/discord.js/commit/429dbccc85cabd9986b2e8bf443bf384e4ddc61a)) +- **ForumChannel:** Add `defaultForumLayout` (#8895) ([cbafd47](https://github.com/discordjs/discord.js/commit/cbafd479b331633ed97f7b1a22ef03c6a2f4cf31)) +- Add support for nsfw commands (#7976) ([7a51344](https://github.com/discordjs/discord.js/commit/7a5134459c5f06864bf74631d83b96d9c21b72d8)) +- **InteractionResponse:** CreatedTimestamp (#8917) ([627511d](https://github.com/discordjs/discord.js/commit/627511d6522f772b84c25e6a3f6da06b06bb912e)) +- **Guild:** Add disableInvites method (#8801) ([45faa19](https://github.com/discordjs/discord.js/commit/45faa199820e7c4ccdb2997c7e3b353f566d2312)) + +## Refactor + +- Compare with `undefined` directly (#9191) ([869153c](https://github.com/discordjs/discord.js/commit/869153c3fdf155783e7c0ecebd3627b087c3a026)) +- **GuildMemberManager:** Tidy up fetching guild members (#8972) ([4e0e125](https://github.com/discordjs/discord.js/commit/4e0e1250399aa12c340ac92a86ec2c05704fe2bb)) +- **BitField:** Reverse iterator/toArray responsibilities (#9118) ([f70df91](https://github.com/discordjs/discord.js/commit/f70df910ed12e397066d0bdb27343af21ead4d92)) +- Moved the escapeX functions from discord.js to @discord.js/formatters (#8957) ([13ce78a](https://github.com/discordjs/discord.js/commit/13ce78af6e3aedc793f53a099a6a615df44311f7)) +- Use `deprecate()` directly (#9026) ([1c871b5](https://github.com/discordjs/discord.js/commit/1c871b5b576dddef12c5afacecf416dbd6243dea)) +- **Guild:** Destructure object in guild editing (#8971) ([d3e9f2a](https://github.com/discordjs/discord.js/commit/d3e9f2a355a1f5272d62a507eb6ecd8808904fff)) +- **GuildManager:** Better handling of creation code (#8974) ([d7a09f6](https://github.com/discordjs/discord.js/commit/d7a09f6fcee30c31b4418166bf7bf9e894841f87)) +- **sharding:** Use switch statement (#8928) ([6540914](https://github.com/discordjs/discord.js/commit/6540914b4a7f244f5e40fe2a3b7e73986763d81b)) +- Use consistent naming for options (#8901) ([a7b55c1](https://github.com/discordjs/discord.js/commit/a7b55c1460cf63fb482f7d05657120eec96bee82)) +- **CommandInteractionOptionResolver:** Loosen mentionable checks (#8910) ([1b151db](https://github.com/discordjs/discord.js/commit/1b151db59c4340417f8a28a88064f45336ac8c78)) + +## Styling + +- Run prettier (#9041) ([2798ba1](https://github.com/discordjs/discord.js/commit/2798ba1eb3d734f0cf2eeccd2e16cfba6804873b)) + +## Typings + +- Allow sending messages with `SuppressNotifications` flag (#9177) ([71a427f](https://github.com/discordjs/discord.js/commit/71a427f6322be76fe2d1cb265de09f171b1b354a)) +- Remove `EscapeMarkdownOptions` (#9153) ([fd0246c](https://github.com/discordjs/discord.js/commit/fd0246ca4c75e60d8e117d9ac5af7067c7a63277)) +- **Attachment:** Make `attachment` private (#8982) ([da23cd5](https://github.com/discordjs/discord.js/commit/da23cd5d69de4856d075f00738f75c68c555ae5b)) +- Fix type of Attachment#name (#9101) ([4e0a89f](https://github.com/discordjs/discord.js/commit/4e0a89f58f43f362bfde80d8319dce767c62850f)) +- Allow builders to set channel types in discord.js (#8990) ([7dec892](https://github.com/discordjs/discord.js/commit/7dec892218f7b470a5f8e78732a524a53da24d26)) +- Swap message reaction and emoji identifier types (#8969) ([ad49845](https://github.com/discordjs/discord.js/commit/ad4984526020f2baeefaeeebbded66c6848c4b85)) +- **widget:** Add missing `name` (#8978) ([898b5ac](https://github.com/discordjs/discord.js/commit/898b5ac416cbbb415b125bb27221d0901fdd180e)) +- Use StringSelectMenuOptionBuilder (#8949) ([bec51de](https://github.com/discordjs/discord.js/commit/bec51de1038c35c6edaaa13934781758fe1951de)) +- Fix actions type in automod (#8962) ([5915f39](https://github.com/discordjs/discord.js/commit/5915f39810b712c05a46fa21ab4e12b4cfa3c25a)) +- Subcommand group `options` is required (#8966) ([5dc5e90](https://github.com/discordjs/discord.js/commit/5dc5e902688fc563087cd5061dcb59dd68fd4eda)) +- Add generic to `ActionRowBuilder.from()` (#8414) ([153352a](https://github.com/discordjs/discord.js/commit/153352ad7a1ccb4a9461523cf2597d81df93b69c)) + +# [14.7.1](https://github.com/discordjs/discord.js/compare/14.7.0...14.7.1) - (2022-12-01) + +## Bug Fixes + +- Prevent crash on no select menu option (#8881) ([11d195d](https://github.com/discordjs/discord.js/commit/11d195d04ff57d51adb0f0d3a0a7342f9e34aba0)) + +# [14.7.0](https://github.com/discordjs/discord.js/compare/14.6.0...14.7.0) - (2022-11-28) + +## Bug Fixes + +- **MessageMentions:** Add `InGuild` generic (#8828) ([f982803](https://github.com/discordjs/discord.js/commit/f9828034cd21e6f702762a46923e0f42115596f6)) +- **Activity:** Fix equals() not checking for differing emoji (#8841) ([7e06f68](https://github.com/discordjs/discord.js/commit/7e06f68185423ba7cb310220b213f445b6571e29)) +- Fixed react/astro/guide/discord.js build, updated dependencies, fix crawlvatar (#8861) ([d0c8256](https://github.com/discordjs/discord.js/commit/d0c82561b8a1765a1daa362ca903f3ffb3fa33ee)) +- **escapeMarkdown:** Fix double escaping (#8798) ([d6873b7](https://github.com/discordjs/discord.js/commit/d6873b7159352479475b3a0daa215bddbdd3a79b)) +- **Transfomers:** Call `.toJSON` in `toSnakeCase` (#8790) ([017f9b1](https://github.com/discordjs/discord.js/commit/017f9b1ed4014dc1db0b78c1a77e463b4403de5d)) +- Censor token in debug output (#8764) ([53d8e87](https://github.com/discordjs/discord.js/commit/53d8e87d7f3a329608250656950bd0a200adb1c7)) +- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4)) + +## Documentation + +- Describe InteractionEditReplyOptions (#8840) ([cb77fd0](https://github.com/discordjs/discord.js/commit/cb77fd02d083438de2aff6f0769baf7d1797bc65)) +- **AutoModerationRuleManager:** Describe cache (#8848) ([d275480](https://github.com/discordjs/discord.js/commit/d2754802cc3479e6288cdbfcd48c76bf57e09a07)) +- Fix message action row components (#8819) ([65bc0ad](https://github.com/discordjs/discord.js/commit/65bc0adbf4d7870d33b92585ca18f964f24bc84e)) +- Specify `ActionRowBuilder` for `components` (#8834) ([8ed5c1b](https://github.com/discordjs/discord.js/commit/8ed5c1beb622f71ce0bd89e4cbeff50e464da8fe)) +- Add `@extends` for select menu classes (#8824) ([09f65b7](https://github.com/discordjs/discord.js/commit/09f65b724b0d2f36bbe89b83570c0d18093b5126)) +- Make WebSocketShard.lastPingTimestamp public (#8768) ([68c9cb3](https://github.com/discordjs/discord.js/commit/68c9cb37bc3df6326b720291827ea477e421faf2)) +- **MessageReplyOptions:** Remove duplicate stickers field (#8766) ([6e348ff](https://github.com/discordjs/discord.js/commit/6e348ffd1d8db8d8ad2da7823460814695e01a43)) + +## Features + +- **Webhook:** Add `channel` property (#8812) ([decbce4](https://github.com/discordjs/discord.js/commit/decbce401062af75f633e6acacc88207b115a719)) +- Auto Moderation (#7938) ([fd4ba5e](https://github.com/discordjs/discord.js/commit/fd4ba5eaba66898699127fc0d5f0ab52c18e3db0)) +- **SelectMenuInteractions:** Add `values` property (#8805) ([b2fabd1](https://github.com/discordjs/discord.js/commit/b2fabd130a76ea54cfbfa1b871ef8659513c2c7a)) +- **ThreadChannel:** Add a helper for pin and unpin (#8786) ([e74aa7f](https://github.com/discordjs/discord.js/commit/e74aa7f6b0fe04e3473fc4a62a73a7db87307685)) +- Add `Message#bulkDeletable` (#8760) ([ff85481](https://github.com/discordjs/discord.js/commit/ff85481d3e7cd6f7c5e38edbe43b27b104e82fba)) +- New select menus (#8793) ([5152abf](https://github.com/discordjs/discord.js/commit/5152abf7285581abf7689e9050fdc56c4abb1e2b)) +- **InteractionResponses:** Add message parameter (#8773) ([8b400ca](https://github.com/discordjs/discord.js/commit/8b400ca975c6bad00060b9c67068f42bd53524ba)) +- Support resume urls (#8784) ([88cd9d9](https://github.com/discordjs/discord.js/commit/88cd9d906074eb79e85df0ef49287f11133d2e0d)) +- Allow deletion of ephemeral messages (#8774) ([fc10774](https://github.com/discordjs/discord.js/commit/fc107744618857bf28c2167f204253baf690ede8)) +- **GuildChannelManager:** Add `.addFollower()` method (#8567) ([caeb1cb](https://github.com/discordjs/discord.js/commit/caeb1cbfdb2f2f007252c4d7e9f47a575c24bcb5)) + +## Refactor + +- **Embed:** Use `embedLength` function from builders (#8735) ([cb3826c](https://github.com/discordjs/discord.js/commit/cb3826ce6dbcd3cf7ab639af6cdfcea80336aa1d)) + +# [14.6.0](https://github.com/discordjs/discord.js/compare/14.5.0...14.6.0) - (2022-10-10) + +## Bug Fixes + +- **ClientOptions:** Make `ClientOptions#intents` returns an IntentsBitField (#8617) ([4c2955a](https://github.com/discordjs/discord.js/commit/4c2955a5de6779c29c09e63ba9ad2b235904f842)) +- Correctly construct a builder (#8727) ([e548e6a](https://github.com/discordjs/discord.js/commit/e548e6a10b7e1720f5e8f3c859b0b64d5134a012)) +- **Components:** Error with unknown components (#8724) ([6fd331d](https://github.com/discordjs/discord.js/commit/6fd331dd528e78fd023c908bd58af3faa9ed6c65)) +- **Client:** Don't auth for webhook fetches with token (#8709) ([01d75c8](https://github.com/discordjs/discord.js/commit/01d75c8b8b14f33c95a4da83a8494db848beeb8c)) +- Re-export util (#8699) ([a306219](https://github.com/discordjs/discord.js/commit/a306219673335584accd2ff77ab34d2812ef6c5d)) +- Throw discord.js errors correctly (#8697) ([ace974f](https://github.com/discordjs/discord.js/commit/ace974fc1fdbc5bcaa0d7f6f6d17de185c9f9cbf)) + +## Documentation + +- **Utils:** Remove `private` from `parseEmoji` (#8718) ([a31e605](https://github.com/discordjs/discord.js/commit/a31e605e09064a300e31a3c91466b613654ba98e)) +- Update UserContextMenuCommandInteraction documentation (#8717) ([7556db2](https://github.com/discordjs/discord.js/commit/7556db243d9480949835668fcb5724fdd5d70e08)) +- Fix `AwaitMessageComponentOptions` typedef (#8696) ([9effd82](https://github.com/discordjs/discord.js/commit/9effd82abe82ba71ae627673da21ba07e1ede23e)) + +## Features + +- **Util:** Escape more markdown characters (#8701) ([7b8966b](https://github.com/discordjs/discord.js/commit/7b8966bca156db79933403289741893a6e10ccd5)) +- **GuildChannelManager:** Allow creating channels with a default auto archive duration (#8693) ([628759b](https://github.com/discordjs/discord.js/commit/628759bcff8b0d4c77926cee2b8c18d8fdb4c260)) +- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3)) +- **ForumChannel:** Add `defaultSortOrder` (#8633) ([883f6e9](https://github.com/discordjs/discord.js/commit/883f6e9202a559c986f4b15fccb422b5aea7bea8)) + +## Refactor + +- Rename Error to DiscordjsError internally (#8706) ([aec44a0](https://github.com/discordjs/discord.js/commit/aec44a0c93f620b22242f35e626d817e831fc8cb)) + +## Typings + +- Fix events augmentation (#8681) ([ac83ada](https://github.com/discordjs/discord.js/commit/ac83ada306ec153c13260d2bd53e4d704884b68a)) +- **Message:** Remove `& this` from `#inGuild` typeguard (#8704) ([c0f7a1a](https://github.com/discordjs/discord.js/commit/c0f7a1a89a4cf62edc7065bd200b2ce4018e0a27)) +- **ModalBuilder:** Fix constructor typings (#8690) ([2ea2a85](https://github.com/discordjs/discord.js/commit/2ea2a85e6335d57f44689f9b6e284129104de8fc)) + +# [14.5.0](https://github.com/discordjs/discord.js/compare/14.4.0...14.5.0) - (2022-09-25) + +## Bug Fixes + +- **ThreadChannel:** Add forum channel to parent (#8664) ([0126d9b](https://github.com/discordjs/discord.js/commit/0126d9b810a156c4bf1b8b93f2121f3319855bac)) +- **GuildChannelManager:** Allow creating webhooks on forums (#8661) ([16fcdc3](https://github.com/discordjs/discord.js/commit/16fcdc36877d1a65ce9995c9fe3502aa268c9388)) +- **ForumChannel:** Implement missing properties and methods (#8662) ([8622939](https://github.com/discordjs/discord.js/commit/862293922924f453f69b0b0f8efe87ddebbd387d)) +- RepliableInteraction respect cached generic (#8667) ([578bc95](https://github.com/discordjs/discord.js/commit/578bc951bdcdc21ec5aee86e7a47a17e8c867dfc)) +- **ThreadChannel:** Allow editing flags (#8671) ([1244854](https://github.com/discordjs/discord.js/commit/1244854e1365d7e4a8d01703a7ec13610ed100c7)) +- **GuildChannelManager:** Typo in `flags` property name when editing (#8669) ([fc8ed81](https://github.com/discordjs/discord.js/commit/fc8ed816e643754a938211a17b41a2cec95df265)) + +## Documentation + +- Fix duplicate typedefs (#8677) ([d79aa2d](https://github.com/discordjs/discord.js/commit/d79aa2d0d0b186bd28cbfc82f3d6ecf3deb41c50)) +- **ForumChannel:** Add `@implements` (#8678) ([8ca407e](https://github.com/discordjs/discord.js/commit/8ca407e089c3050b61a51a52b9100e4613ad1666)) + +## Features + +- **GuildChannelManager:** Allow editing `flags` (#8637) ([abb7226](https://github.com/discordjs/discord.js/commit/abb7226af3445f5b724815bb2f7a121a52a563b5)) + +## Refactor + +- **GuildBanManager:** Add deprecation warning for `deleteMessageDays` (#8659) ([e993122](https://github.com/discordjs/discord.js/commit/e9931229ae62a120ae0761ee2a2c10ea0cb1a6fb)) + +## Typings + +- **GuildChannelManager:** Handle forum channel overload (#8660) ([1486bc9](https://github.com/discordjs/discord.js/commit/1486bc9336369d229972df5e28b9428365b92bff)) +- **Caches:** Allow `GuildForumThreadManager` and `GuildTextThreadManager` (#8665) ([2487e3b](https://github.com/discordjs/discord.js/commit/2487e3bf76260a4a2fbf375e0b01a43f347922a3)) + +# [14.4.0](https://github.com/discordjs/discord.js/compare/14.3.0...14.4.0) - (2022-09-21) + +## Bug Fixes + +- Correct applied tags type (#8641) ([f6f15d8](https://github.com/discordjs/discord.js/commit/f6f15d8e877d4ffbe908a093e64809ef9015e0ff)) +- **ThreadChannel:** Make `fetchStarterMessage()` work in forum posts (#8638) ([a7f816e](https://github.com/discordjs/discord.js/commit/a7f816eeb7fa1e193cf0901efbdcaf629f72465f)) +- Update `messageCount`/`totalMessageSent` on message events (#8635) ([145eb2f](https://github.com/discordjs/discord.js/commit/145eb2fc5db5ca739aa9782d5ec5210f81a6aeeb)) +- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9)) + +## Documentation + +- Correctly overwrite `setRTCRegion` method (#8642) ([f049734](https://github.com/discordjs/discord.js/commit/f0497343f1193635b260b9e2085cac7b43991f74)) +- **GuildTextThreadManager:** Document correct `@extend` (#8639) ([802b239](https://github.com/discordjs/discord.js/commit/802b2394b08151faab6810695fd5c8f27ce84d58)) +- Fix regexps incorrectly being called global (#8624) ([fc9653f](https://github.com/discordjs/discord.js/commit/fc9653f5aea4013da15fb8de0a4452400eaa7739)) +- Update misleading `Client#guildMemberAvailable` event description (#8626) ([22ac6b4](https://github.com/discordjs/discord.js/commit/22ac6b4660db6b02f62b9851e9e3bcfe5fb506b5)) +- **Options:** Update DefaultMakeCacheSettings (#8585) ([3252332](https://github.com/discordjs/discord.js/commit/32523325c6610e95fe3ffcc31d005b3418c6bc68)) +- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0)) + +## Features + +- **Widget:** Allow forum channels (#8645) ([b106956](https://github.com/discordjs/discord.js/commit/b1069563086fc616fe21abb789f28f69e57c8851)) +- **WelcomeChannel:** Add forum channel as a type (#8643) ([6f1f465](https://github.com/discordjs/discord.js/commit/6f1f465a77e362e20ec50067be0e634d35946ba5)) +- Allow forum channels in webhook update event (#8646) ([5048a3d](https://github.com/discordjs/discord.js/commit/5048a3d17ace22336e74451d30b513b3db42a26f)) +- Add support for guild forums (#7791) ([8a8d519](https://github.com/discordjs/discord.js/commit/8a8d519c9c4c082370fc6935b56dafb525b873df)) +- **GuildBanManager#create:** Add `deleteMessageSeconds` (#8326) ([03fb5b0](https://github.com/discordjs/discord.js/commit/03fb5b0a2f45275dec7885175ad691a1d9c449c4)) +- Add typeguard to BaseInteraction#isRepliable (#8565) ([55c3ee2](https://github.com/discordjs/discord.js/commit/55c3ee20ae700e78d18a3c4c04b6a7426cffc060)) +- **Integration:** Add `scopes` (#8483) ([8b3d006](https://github.com/discordjs/discord.js/commit/8b3d0061180cfd5d9ba8beae3e8d623b5ce43ea4)) +- Add `chatInputApplicationCommandMention` formatter (#8546) ([d08a57c](https://github.com/discordjs/discord.js/commit/d08a57cadd9d69a734077cc1902d931ab10336db)) + +## Refactor + +- Replace usage of deprecated `ChannelType`s (#8625) ([669c3cd](https://github.com/discordjs/discord.js/commit/669c3cd2566eac68ef38ab522dd6378ba761e8b3)) +- Split message send/edit types/documentation (#8590) ([8e1afae](https://github.com/discordjs/discord.js/commit/8e1afaebdb686033555ca58e53f34bb97f7369c8)) +- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67)) + +## Typings + +- Narrow channel type in thread managers (#8640) ([14bbc91](https://github.com/discordjs/discord.js/commit/14bbc9150a748e7ac1660c2375c7f065fcc55a6c)) +- **interactions:** Pass `Cached` type to return type of methods (#8619) ([053da5b](https://github.com/discordjs/discord.js/commit/053da5bc91d5cfa8d842b13b0b05083d2f7f086d)) +- Ensure events possess `Client<true>` (#8612) ([a9f003a](https://github.com/discordjs/discord.js/commit/a9f003ac9b56d31166cbf353d02140dad0b2517e)) +- **GuildChannelManager:** Correct `fetch` return type (#8549) ([1d4cdee](https://github.com/discordjs/discord.js/commit/1d4cdee321ab25bb0f109d55a000582825dd79f9)) +- **ThreadChannel:** `fetchStarterMessage` must return a `Message<true>` (#8560) ([b9c62ac](https://github.com/discordjs/discord.js/commit/b9c62ac0f0f534c33f9913135095f8b3d98ec05e)) +- **webhook:** Avatar can be null (#8541) ([f77612a](https://github.com/discordjs/discord.js/commit/f77612a55e9c593a21bc27e58c9fbd03d85787e3)) + +# [14.3.0](https://github.com/discordjs/discord.js/compare/14.2.0...14.3.0) - (2022-08-22) + +## Bug Fixes + +- **GuildMemberManager:** `add()` method throws an error (#8539) ([3bef901](https://github.com/discordjs/discord.js/commit/3bef9018c0be3c5dc51d03b796d08b925dc4e1b9)) +- **Guild:** Widget channel types and fixes (#8530) ([23a0b6c](https://github.com/discordjs/discord.js/commit/23a0b6ccf27410963bd4f5c53d9ee2ce019e90a8)) +- **Embed:** Reference video in video (#8473) ([c97977a](https://github.com/discordjs/discord.js/commit/c97977a3e806bd5d8682bc7fb22ebec1a8ceecdc)) + +## Documentation + +- **GuildAuditLogsEntry:** Correct `action` wording (#8499) ([7d25072](https://github.com/discordjs/discord.js/commit/7d2507279cc9d1397c7d61e7c7b856ff4bc17c86)) + +## Features + +- **GuildMemberManager:** AddRole and removeRole (#8510) ([cda3f00](https://github.com/discordjs/discord.js/commit/cda3f005b1546fdb8410e9550526956f840857fc)) +- Deprecate `ActionRow.from()` (#8504) ([f9c25dd](https://github.com/discordjs/discord.js/commit/f9c25ddcfe68f089e13f1090c3df4bd7cd74d2b7)) +- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166)) + +## Refactor + +- **GuildAuditLogsEntry:** Remove `guild` from application command permission update extra (#8520) ([2b8074d](https://github.com/discordjs/discord.js/commit/2b8074dd12f2f1e957caffb57e5fd4d7be88dc25)) + +## Typings + +- Inference of guild in `MessageManager` (#8538) ([6bb1474](https://github.com/discordjs/discord.js/commit/6bb1474d2001b76773954c959b2c2687e1df0136)) +- Allow choice's value type to be strictly inferred (#8529) ([b3f7c32](https://github.com/discordjs/discord.js/commit/b3f7c32f7f91f12766178f5e17585856e81d9a87)) +- **GuildAuditLogs:** Allow fetching to return all possible values (#8522) ([0dba8ad](https://github.com/discordjs/discord.js/commit/0dba8adbd2e6efd634bd3eb31df09467ba8a8a0d)) +- Correct `EventEmitter.on (static)` return type (#8524) ([16bbc8a](https://github.com/discordjs/discord.js/commit/16bbc8aa208a8a16c22be24696f57d5f7a5faf2b)) +- **GuildAuditLogs:** Remove static `Entry` (#8521) ([7a3d18d](https://github.com/discordjs/discord.js/commit/7a3d18dd6d1fe27393d00019b9ecd35c98b95ee7)) +- Disallow some channel types from webhook creation (#8531) ([4882b17](https://github.com/discordjs/discord.js/commit/4882b17a77484f801faa19fb971f2e6abd88e59f)) +- Implement max/min values for autocomplete (#8498) ([812f7f1](https://github.com/discordjs/discord.js/commit/812f7f1ea86fc953aa796875cbc7ccc434203d77)) +- **ModalMessageModalSubmitInteraction:** ChannelId is not nullable (#8496) ([c31a5cf](https://github.com/discordjs/discord.js/commit/c31a5cfcc82706667768eac77b5f99ba69cf3c91)) +- Change type of ApplicationCommandSubCommand.options (#8476) ([ebaf158](https://github.com/discordjs/discord.js/commit/ebaf158006d3c7db3b8c695e7c027b8af11999ba)) + +# [14.2.0](https://github.com/discordjs/discord.js/compare/14.1.2...14.2.0) - (2022-08-10) + +## Bug Fixes + +- **ThreadChannel:** Handle possibly `null` parent (#8466) ([afa27b1](https://github.com/discordjs/discord.js/commit/afa27b15c5b92bc8d55b8285834d8e03f6692d06)) +- Remove DM channels from `Client#messageDeleteBulk`'s types (#8460) ([6c6fe74](https://github.com/discordjs/discord.js/commit/6c6fe74dd84859c5319efa999404e8168f189710)) +- **Transformers:** Do not transform `Date` objects (#8463) ([0e2a095](https://github.com/discordjs/discord.js/commit/0e2a09571c8e5ee61153b04e45334a226a1b4534)) +- **ModalSubmitInteraction:** Allow deferUpdate (#8455) ([0fab869](https://github.com/discordjs/discord.js/commit/0fab869e5179dca7ddec75b5519615278e51ad82)) +- **Guild:** Unable to fetch templates (#8420) ([aac8acc](https://github.com/discordjs/discord.js/commit/aac8acc22be7d7af99933ef099eca7deda43cb40)) +- **MessageMentions:** Infinite loop in `parsedUsers` getter (#8430) ([b8a3136](https://github.com/discordjs/discord.js/commit/b8a31360a220e3d796f5381bd215d30a379ecb7c)) +- **DataResolver:** Make `Buffer` from string (#8416) ([e72b986](https://github.com/discordjs/discord.js/commit/e72b986939e2958547c0e54d6d27472c8d111609)) + +## Documentation + +- Change registration example to use global commands (#8454) ([64a4041](https://github.com/discordjs/discord.js/commit/64a4041a05e9514334a9f9e1f38a1ea18bb676d5)) +- **Colors:** Provide enum descriptions (#8437) ([6ef4754](https://github.com/discordjs/discord.js/commit/6ef4754d40c5ec65715fc1e00e643c52fe0a6209)) +- **AttachmentBuilder:** Fix #8407 (#8421) ([5b053cf](https://github.com/discordjs/discord.js/commit/5b053cf82ec2f2b717a490485af052dc956fe3c9)) + +## Features + +- **Guild:** Add `max_video_channel_users` (#8423) ([3a96ce7](https://github.com/discordjs/discord.js/commit/3a96ce7970947f6268c21a1323d986aac8cb736d)) + +## Typings + +- **Message:** Correct `bulkDelete` return type (#8465) ([c5b96a1](https://github.com/discordjs/discord.js/commit/c5b96a185cb8ba836b7cd10526c14059866f218f)) +- Fix missing types for mentionable options (#8443) ([452e94f](https://github.com/discordjs/discord.js/commit/452e94fd3ecc12de9e3408982c5c7fd931bae634)) +- **ApplicationCommandOption:** Add `ApplicationCommandBooleanOption` (#8434) ([38275fc](https://github.com/discordjs/discord.js/commit/38275fc53d633ce77ed2b142aff788dcbd4fad8c)) + +# [14.1.2](https://github.com/discordjs/discord.js/compare/14.1.1...14.1.2) - (2022-07-30) + +## Bug Fixes + +- **errors:** Error codes (#8398) ([480c85c](https://github.com/discordjs/discord.js/commit/480c85c9c3d129204b3399ed726a4e570e0b2852)) + +## Documentation + +- **Embed:** Ensure height and width are numbers (#8396) ([fca3dad](https://github.com/discordjs/discord.js/commit/fca3dada2a565eecfc7e5275cc9317df1d261871)) + +# [14.1.0](https://github.com/discordjs/discord.js/compare/14.0.3...14.1.0) - (2022-07-29) + +## Bug Fixes + +- **MessageMentions:** `ignoreRepliedUser` option in `has()` (#8202) ([b4e2c0c](https://github.com/discordjs/discord.js/commit/b4e2c0c4d5538b945f9d597c6410a6f84b315084)) +- **GuildChannelManager:** Allow unsetting rtcRegion (#8359) ([a7d49e5](https://github.com/discordjs/discord.js/commit/a7d49e56fc7c34d2e4548d9e5bf0aec45273506e)) +- **ThreadChannel:** Omit webhook fetching (#8351) ([3839958](https://github.com/discordjs/discord.js/commit/3839958e3f682c715f1017da05436d2fe34900fd)) +- **GuildAuditLogsEntry:** Replace OverwriteType with AuditLogOptionsType (#8345) ([58c1b51](https://github.com/discordjs/discord.js/commit/58c1b51c5ceab137ad9851919b338419eeeab69e)) +- **ShardClientUtil#_respond:** Construct global error (#8348) ([8e520f9](https://github.com/discordjs/discord.js/commit/8e520f946a5b9f93a939290facf4ccca2c05ff21)) +- **Presence:** Do not return NaN for activity timestamp (#8340) ([df42fdf](https://github.com/discordjs/discord.js/commit/df42fdfc421f1190f0a2267a66efd3c921ec2348)) +- **Client:** Omit private properties from toJSON (#8337) ([830c670](https://github.com/discordjs/discord.js/commit/830c670c61dcb17d8ab2a894a3203c68917d27e0)) +- **ApplicationCommandManager:** Allow passing 0n to defaultMemberPermissions (#8311) ([1fb7b30](https://github.com/discordjs/discord.js/commit/1fb7b30963cfe7ea4c05b1f3b42171c879c46a1d)) + +## Documentation + +- **InteractionResponses:** Add `showModal()` return type (#8376) ([0b61dbf](https://github.com/discordjs/discord.js/commit/0b61dbf720e844322b066e30080c3537ab3d8174)) +- **WebhookClient:** Document working options (#8375) ([ba6797e](https://github.com/discordjs/discord.js/commit/ba6797e74209161b64c412de1b6f307cb28736b8)) +- **Message:** Document gateway intent for content (#8364) ([2130aae](https://github.com/discordjs/discord.js/commit/2130aae3210a8eaf91c5ccae5463940d49052c7d)) +- Use info blocks for requirements (#8361) ([80b9738](https://github.com/discordjs/discord.js/commit/80b9738957ebf5b6eb7c9858cec0fb1c897d0a1f)) +- **WebhookClient:** Make constructor a union (#8370) ([e9920a9](https://github.com/discordjs/discord.js/commit/e9920a9c98ffb78bd7d0ae00d486476367296646)) +- Update docs and examples to PascalCase links (#8305) ([34ba9d1](https://github.com/discordjs/discord.js/commit/34ba9d1c4c80eff7e6ac199a40232d07491432cc)) + +## Features + +- Add channel & message URL formatters (#8371) ([a7deb8f](https://github.com/discordjs/discord.js/commit/a7deb8f89830ead6185c5fb46a49688b6d209ed1)) +- Restore missing typeguards (#8328) ([77ed407](https://github.com/discordjs/discord.js/commit/77ed407f6aadb68e729470c5269e9b526cb1b3f0)) +- **GuildMember:** Add dmChannel getter (#8281) ([4fc2c60](https://github.com/discordjs/discord.js/commit/4fc2c60a3bb43671b4b0202ae75eab42aba163ff)) + +## Refactor + +- Deprecate `Formatter` class (#8373) ([7fd9ed8](https://github.com/discordjs/discord.js/commit/7fd9ed8f13d17ce7e98e34f7454d9047054d8467)) +- **PermissionOverwriteManager:** Use `OverwriteType` (#8374) ([6d24805](https://github.com/discordjs/discord.js/commit/6d248051cfd431e9cb1c65cb98f56aa0a6556407)) + +## Typings + +- **GuildAuditLogsEntryExtraField:** Use `AuditLogOptionsType` (#8349) ([200ab91](https://github.com/discordjs/discord.js/commit/200ab91f527d8a5706d277b89a975096f75d141a)) + +# [14.0.3](https://github.com/discordjs/discord.js/compare/14.0.2...14.0.3) - (2022-07-19) + +## Bug Fixes + +- **Components:** Support emoji id strings (#8310) ([660e212](https://github.com/discordjs/discord.js/commit/660e212e83df026c684ee2cda7fb4e98870f342e)) + +# [14.0.2](https://github.com/discordjs/discord.js/compare/14.0.1...14.0.2) - (2022-07-18) + +## Bug Fixes + +- **DataResolver#resolveImage:** Adjust to updated resolveFile (#8308) ([3a7e93d](https://github.com/discordjs/discord.js/commit/3a7e93df576172c797f1d8bd6483234bb6af2d00)) + +# [14.0.0](https://github.com/discordjs/discord.js/compare/9.3.1...14.0.0) - (2022-07-17) + +## Bug Fixes + +- **GuildMemberManager:** Allow setting own nickname (#8066) ([52a9e21](https://github.com/discordjs/discord.js/commit/52a9e213c2dc13ee52ee0234593fdce392f43890)) +- **PermissionOverwriteManager:** Mutates user (#8283) ([3bf30b1](https://github.com/discordjs/discord.js/commit/3bf30b1e6d2d6f583f7069a1e24e7842d59fab2f)) +- **GuildChannelManager:** Access `resolveId` correctly (#8296) ([3648f6d](https://github.com/discordjs/discord.js/commit/3648f6d567cd834c301de913ce19f786a265240d)) +- **GuildChannelManager:** Edit lockPermissions (#8269) ([7876548](https://github.com/discordjs/discord.js/commit/787654816d2b6a5168d199d32cdaeb4ef6d270b9)) +- **`SelectMenuBuilder`:** Properly accept `SelectMenuOptionBuilder`s (#8174) ([31d5930](https://github.com/discordjs/discord.js/commit/31d593046466438c55f5784b0f2098e233c5edc4)) +- Remove global flag on regular expressions (#8177) ([cdd9214](https://github.com/discordjs/discord.js/commit/cdd9214212892e30b3eaa161837c37516c5bcaa0)) +- **MessagePayload:** Guard against `repliedUser` property (#8211) ([fa010b5](https://github.com/discordjs/discord.js/commit/fa010b516254c4ab2762278817f31bf289f0ab6a)) +- **ApplicationCommandManager:** Explicitly allow passing builders to methods (#8209) ([50d55bd](https://github.com/discordjs/discord.js/commit/50d55bd6b819307c86701f4808c087f359c6ccff)) +- **GuildMemberRemove:** Remove member's presence (#8181) ([11b1739](https://github.com/discordjs/discord.js/commit/11b173931968c548f8504649ae7090865892e62d)) +- Edit() data can be partial and `defaultMemberPermissions` can be `null` (#8163) ([0ffbef5](https://github.com/discordjs/discord.js/commit/0ffbef506a97a0bf22cb134fc007c2aec29cbffc)) +- **WebSocketShard:** Keep an error handler on connections (#8150) ([c34c02a](https://github.com/discordjs/discord.js/commit/c34c02ab8d119bf16d8d14d125a9b650b4bb18f4)) +- **DJSError:** Error code validation (#8149) ([31f6582](https://github.com/discordjs/discord.js/commit/31f658247fe0e1047897edab629643d140e77e07)) +- **vcs:** Nsfw property (#8132) ([2eeaad6](https://github.com/discordjs/discord.js/commit/2eeaad6f27fdf8868364fa95ed20755ee09bda87)) +- **WebSocketManager:** Correct error name (#8138) ([db2b033](https://github.com/discordjs/discord.js/commit/db2b0333d912fe83381db2ffe16829d7d03d6c2e)) +- **WebSocketShard:** Disconnected casing (#8117) ([23e183a](https://github.com/discordjs/discord.js/commit/23e183a9ac7aaa3bca2bc4eb8634d1738ec34a26)) +- **webhooks:** Revert webhook caching (and returning Message) (#8038) ([d54bf5d](https://github.com/discordjs/discord.js/commit/d54bf5d286f4057db130901591b192fd4d1668c1)) +- **ApplicationCommand:** Remove `autocomplete` check at the top level and correctly check for `dmPermission` (#8100) ([0a44b05](https://github.com/discordjs/discord.js/commit/0a44b05db83948857afbe18471e7a867da47177a)) +- **ApplicationCommand:** Fix default member permissions assignment (#8067) ([96053ba](https://github.com/discordjs/discord.js/commit/96053babe1bd65ebe1fc6a261f5eb052906afdb9)) +- **scripts:** Read directory and rerun (#8065) ([f527dea](https://github.com/discordjs/discord.js/commit/f527dea36ead194aaae1bf5da1e953df59d692fd)) +- Select menu options to accept both rest and array (#8032) ([fbe67e1](https://github.com/discordjs/discord.js/commit/fbe67e102502b4b49690cbf8ff891ead2232ecf3)) +- **CommandInteractionOptionResolver:** Handle autocompletion interactions (#8058) ([d8077c6](https://github.com/discordjs/discord.js/commit/d8077c6839dc8ceb57d3c3a86bf9746be2a91ada)) +- **scripts:** Add quotes around blob arguments (#8054) ([598f61b](https://github.com/discordjs/discord.js/commit/598f61b992fab1b3fdcab8ff960366f7af0b37ea)) +- **Message:** Force fetching (#8047) ([f2b267c](https://github.com/discordjs/discord.js/commit/f2b267c079dd8aa7277910471f3db2f88af6efb2)) +- **Attachment:** Do not destructure `data` (#8041) ([1afae90](https://github.com/discordjs/discord.js/commit/1afae909d72e648cf48d63d7de2708737a78c126)) +- **DirectoryChannel:** Type `name` and handle `url` (#8023) ([86d8fbc](https://github.com/discordjs/discord.js/commit/86d8fbc023e3925e8f86799d6ebf2d423f7bf2ec)) +- Readd `isThread` type guard (#8019) ([f8ed71b](https://github.com/discordjs/discord.js/commit/f8ed71bfca6e47e3d44ad063e23804354bd23604)) +- Add static method `from` in builders (#7990) ([ad36c0b](https://github.com/discordjs/discord.js/commit/ad36c0be7744ea4214ccf345fe80a5a1a9e89101)) +- Typings (#7965) ([7a1095b](https://github.com/discordjs/discord.js/commit/7a1095b66be3c5d81185e026281e2908c10c1695)) +- **GuildAuditLogs:** Cache guild scheduled events (#7951) ([2f03f9a](https://github.com/discordjs/discord.js/commit/2f03f9ad3f63abee5b5c46d02f1afa8885e8977c)) +- Make sure action row builders create djs builders (#7945) ([adf461b](https://github.com/discordjs/discord.js/commit/adf461baf49be754c7a10c61faf1ef3df333413a)) +- **TextBasedChannel#bulkDelete:** Return deleted message (#7943) ([191510b](https://github.com/discordjs/discord.js/commit/191510b7f87903e4bd93b891649cb290fd50c47e)) +- Remove trailing invites on channel deletion (#7932) ([5e9b757](https://github.com/discordjs/discord.js/commit/5e9b757a3733e6526770eb60a15072612294eb21)) +- **DataResolver:** Fix check for readable streams (#7928) ([28172ca](https://github.com/discordjs/discord.js/commit/28172ca7b57357436d3252ec01ec17dad865d87f)) +- **AuditLog:** Default changes to empty array (#7880) ([19eaed6](https://github.com/discordjs/discord.js/commit/19eaed63905367ef4604366b8839023384524d1f)) +- **Util:** Flatten ignoring certain fields (#7773) ([df64d3e](https://github.com/discordjs/discord.js/commit/df64d3ea382c07e66bc7cc8877ee430206c31d63)) +- Possibly missing (#7829) ([6239d83](https://github.com/discordjs/discord.js/commit/6239d83c4d5f0a396678410d7fef35e39ed29009)) +- `endReason` not being properly set in base Collector (#7833) ([0c18dab](https://github.com/discordjs/discord.js/commit/0c18dab1280205b8855d17d075b7421860d59c14)) +- **SelectMenuBuilder:** Options array (#7826) ([3617093](https://github.com/discordjs/discord.js/commit/361709332bdc871822c2b9919f14fd090d68666a)) +- **Activity:** Platform type (#7805) ([4ac91c6](https://github.com/discordjs/discord.js/commit/4ac91c61d08111ae4d49d1e64caf94e6e49832c8)) +- **ApplicationCommand:** Equal nameLocalizations and descriptionLocalizations (#7802) ([4972bd8](https://github.com/discordjs/discord.js/commit/4972bd87c17cbc6a94c9608ba2ab39c475f9921f)) +- **InteractionResponses:** Use optional chaining on nullable property (#7812) ([c5fb548](https://github.com/discordjs/discord.js/commit/c5fb54852906898ffb19282dd60168dfc6fb2eba)) +- **MessageManager:** Allow caching option of an unspecified limit (#7763) ([1b2d8de](https://github.com/discordjs/discord.js/commit/1b2d8decb638faeae8184119c5cedfcdaf9485e3)) +- **builders:** Add constructor default param (#7788) ([c286650](https://github.com/discordjs/discord.js/commit/c2866504a3824005fe756556fec4b349898b7d22)) +- **MessagePayload:** ResolveBody check body instead of data (#7738) ([3db20ab](https://github.com/discordjs/discord.js/commit/3db20abdd2d502a1ed457842181b164dc6390ba1)) +- **ActionRow:** ToJSON should include components (#7739) ([ebb4dfa](https://github.com/discordjs/discord.js/commit/ebb4dfa262adb2086c83db487002bb2e1ed5ab88)) +- Prevent `NaN` for nullable timestamps (#7750) ([8625d81](https://github.com/discordjs/discord.js/commit/8625d817145eb642aeb0da05184352f438586986)) +- **InteractionCreateAction:** Ensure text-based channel for caching messages (#7755) ([25fdb38](https://github.com/discordjs/discord.js/commit/25fdb3894d33dc395a376a3d962a063eb5735253)) +- Pass `force` correctly (#7721) ([402514f](https://github.com/discordjs/discord.js/commit/402514ff323ccf1f8c95d295f044cf0bb5547c2e)) +- Support reason in setRTCRegion helpers (#7723) ([905a6a1](https://github.com/discordjs/discord.js/commit/905a6a11663f9469ada67f8310a969453ffc5b2a)) +- **GuildMemberManager:** Return type can be null (#7680) ([74bf7d5](https://github.com/discordjs/discord.js/commit/74bf7d57ab959eb820ab1c213ac86ab1ea660398)) +- **gateway:** Use version 10 (#7689) ([8880de0](https://github.com/discordjs/discord.js/commit/8880de0cecdf273fd6df23988e4cb77774a75390)) +- Audit log static reference (#7703) ([85e531f](https://github.com/discordjs/discord.js/commit/85e531f22d7a8f8ad043647ce445726ae0df26c0)) +- Handle possibly missing property (#7641) ([0c32332](https://github.com/discordjs/discord.js/commit/0c32332a5aacbbb6c415da75c166d09cfdb34bbd)) +- **util:** Allow `escapeInlineCode` to escape double backtics (#7638) ([d5369a5](https://github.com/discordjs/discord.js/commit/d5369a56e3fcf50513f3bc582552c2838b04d199)) +- **GuildEditData:** Some fields can be null (#7632) ([4d2b559](https://github.com/discordjs/discord.js/commit/4d2b55955d1a3ff05c3047599232becdc3f2c445)) +- TOKEN_INVALID error not thrown at login with invalid token (#7630) ([cd79bef](https://github.com/discordjs/discord.js/commit/cd79bef2547594f4d0c744faa8fa67fb9fd61526)) +- **GuildScheduledEvent:** Handle missing `image` (#7625) ([c684ac5](https://github.com/discordjs/discord.js/commit/c684ac55e1d225740e67ab7bd5643de1b35f4594)) +- **guild:** Throw if ownerId falsey (#7575) ([98177aa](https://github.com/discordjs/discord.js/commit/98177aa38d3d6516d4c5354d6c7edea925dc881d)) +- Remove Modal export (#7654) ([87a6b84](https://github.com/discordjs/discord.js/commit/87a6b8445bfbf3981cd39813fe961dfa1c7f2bce)) +- **Embed:** Fix incorrect destructuring import (#7615) ([cbdb408](https://github.com/discordjs/discord.js/commit/cbdb408dffd1c7f2193c15989528a3de5fd9f13a)) +- **ThreadMembersUpdate:** Only emit added & removed thread members (#7539) ([c12d61a](https://github.com/discordjs/discord.js/commit/c12d61a3421afcdc41f77c0fddde4efbb257fa69)) +- **Util:** EscapeInlineCode properly (#7587) ([851f380](https://github.com/discordjs/discord.js/commit/851f380eb10d23ffd08e8b845aed4039abbcd03b)) +- **GuildStickerManager:** Correctly access guild ID (#7605) ([4b08d9b](https://github.com/discordjs/discord.js/commit/4b08d9b376bda7a7f4bb3fb8c555d25cca648de4)) +- **MessageManager:** Pin route (#7610) ([cb566c8](https://github.com/discordjs/discord.js/commit/cb566c8b6abff489a944db7952e5c5a48e0c98b0)) +- Handle partial data for `Typing#user` (#7542) ([c6cb5e9](https://github.com/discordjs/discord.js/commit/c6cb5e9ebbf46d81404119a6aa11bb8ebb17d5a4)) +- **guild:** Fix typo accessing user instead of users (#7537) ([8203c5d](https://github.com/discordjs/discord.js/commit/8203c5d843f2431c0f49023282f1bf73d85881d1)) +- **test:** `MessageActionRow` to `ActionRow` (#7523) ([d1d1b07](https://github.com/discordjs/discord.js/commit/d1d1b076bebf7cb706b2436a40d87c6efaed1e1d)) +- **MessagePayload:** Don't set reply flags to target flags (#7514) ([4f30652](https://github.com/discordjs/discord.js/commit/4f306521d829fef21ebd70557b37f8199b82572b)) +- **invite:** Add back channelId property (#7501) ([78aa36f](https://github.com/discordjs/discord.js/commit/78aa36f9f5913b86c82376ecdf20653b15340bbe)) +- Properly serialize `undefined` values (#7497) ([8dbd345](https://github.com/discordjs/discord.js/commit/8dbd34544cbeb499282f01dda9d35ed9bca93591)) +- Allow unsafe embeds to be serialized (#7494) ([942ea1a](https://github.com/discordjs/discord.js/commit/942ea1acbfb49289ccb3a1882b5a2da0a7d0bccf)) +- Attachment types (#7478) ([395a68f](https://github.com/discordjs/discord.js/commit/395a68ff49c622d5136d6b775beaf8e88a2d8610)) +- Use case converter for json component serialization (#7464) ([2d45544](https://github.com/discordjs/discord.js/commit/2d4554440ed9329a5876a9c674c3eb2de0f2f917)) +- **GuildAuditLogs:** Typings and consistency (#7445) ([c1b27f8](https://github.com/discordjs/discord.js/commit/c1b27f8eed8ea04a48bc106453892bddcdc6b73e)) +- **dataresolver:** Ensure fetched file is convert to a buffer (#7457) ([9311fa7](https://github.com/discordjs/discord.js/commit/9311fa7b42b2b5a74e411aa263daa4fbfc270645)) +- **messagepayload:** ResolveFile property names (#7458) ([a8106f7](https://github.com/discordjs/discord.js/commit/a8106f7c586f0ecac76e7f72c53b0da215a6fbf1)) +- **ci:** Ci error (#7454) ([0af9bc8](https://github.com/discordjs/discord.js/commit/0af9bc841ffe1a297d308500d696bad4b85abda9)) +- **threads:** Require being sendable to be unarchivable (#7406) ([861f0e2](https://github.com/discordjs/discord.js/commit/861f0e2134662ab64a11d313130aff58b413d495)) +- **guildmember:** Check if member has administrator permission (#7384) ([81d8b54](https://github.com/discordjs/discord.js/commit/81d8b54ff6b98b0e7ee2c57eaee6bc0b707e135a)) +- **guild:** Remove `maximumPresences` default value (#7440) ([55b388a](https://github.com/discordjs/discord.js/commit/55b388a763dc7223e88b62ae928fe85fe8b8fe58)) +- **guildchannelmanager:** Edit always sets parent to null (#7446) ([b97aedd](https://github.com/discordjs/discord.js/commit/b97aedd8e15f9358960cb59403f3a8ea24b87141)) +- **guildmember:** Make `pending` nullable (#7401) ([fe11ff5](https://github.com/discordjs/discord.js/commit/fe11ff5f6e85571a981e90eba5b9f3bda7a2cd04)) +- **clientpresence:** Fix used opcodes (#7415) ([a921ec7](https://github.com/discordjs/discord.js/commit/a921ec7dc525c58d40b4678e66270f9238abed31)) +- Correctly export UnsafeSelectMenuComponent from builders (#7421) ([aadfbda](https://github.com/discordjs/discord.js/commit/aadfbda586d57a7b775ad26c201f0dc34618180b)) +- MessageReaction.me being false when it shouldn't (#7378) ([04502ce](https://github.com/discordjs/discord.js/commit/04502ce702da53c4b00bf391d0fd936746851381)) +- Fix some typos (#7393) ([92a04f4](https://github.com/discordjs/discord.js/commit/92a04f4d98f6c6760214034cc8f5a1eaa78893c7)) +- **messagementions:** Fix `has` method (#7292) ([3a5ab2c](https://github.com/discordjs/discord.js/commit/3a5ab2c4e54de4e67ab6e323d7eac86482da7382)) +- **guildmembermanager:** Use rest in edit (#7356) ([00ce1c5](https://github.com/discordjs/discord.js/commit/00ce1c56ac224691a8691a3525cb14ae002319c6)) +- **typings:** Mark `RESTOptions` as Partial in `ClientOptions` (#7349) ([e1ecc1a](https://github.com/discordjs/discord.js/commit/e1ecc1a80a9358cdbafbe8542c40b9de8cad467e)) +- **Webhook:** Use correct method name (#7348) ([11e5e5a](https://github.com/discordjs/discord.js/commit/11e5e5ac5b70138f56332eb3e61a42443670b0de)) +- **thread:** Don't assign directly to getters (#7346) ([2db0cdd](https://github.com/discordjs/discord.js/commit/2db0cdd357c3a02decb4fd4168db87888efba283)) +- Missed enums and typings from #7290 (#7331) ([47633f0](https://github.com/discordjs/discord.js/commit/47633f0fd2435d6d8c694d8d37b26039a7b3797a)) +- **guildchannelmanager:** Remove reverse enum lookup (#7304) ([857bba4](https://github.com/discordjs/discord.js/commit/857bba448029f3f070c67fb40b59a3a2a2e5c6f4)) +- Import `clear{Timeout,Interval}` from `node:timers` (#7269) ([8ddd44e](https://github.com/discordjs/discord.js/commit/8ddd44ed85b32c86243efe0ec35b283eaaa8212c)) +- **ApplicationCommand:** Use new ApplicationCommandOptionType enums (#7257) ([06f5210](https://github.com/discordjs/discord.js/commit/06f5210f58bbba6102173033a9f1e6fb004fdf5d)) +- Use enums from discord-api-types (#7258) ([f284a46](https://github.com/discordjs/discord.js/commit/f284a4641fd68de9190bda97ec1eab0981149630)) +- **exports:** Export ApplicationCommandType properly (#7256) ([f753882](https://github.com/discordjs/discord.js/commit/f75388259262bf6b4a64375b97800bd72378f3bc)) +- **Shard:** EventEmitter listener warning (#7240) ([ff3a8b8](https://github.com/discordjs/discord.js/commit/ff3a8b83234d3826fc49c5a8c3cb52ef9f281ffd)) +- **timestamps:** Account for timestamps of 0 when creating Dates (#7226) ([a8509c9](https://github.com/discordjs/discord.js/commit/a8509c91ca0147393b407221405b6b917677961a)) +- **MessageEmbed:** CreatedAt field can be zero (#7218) ([37cad54](https://github.com/discordjs/discord.js/commit/37cad54dbdade39607397b8ad697eca94f1b7197)) +- **BaseClient:** Do not append default options if provided is not an object (#6453) ([b92a7d7](https://github.com/discordjs/discord.js/commit/b92a7d72332c35b607db54aa6aca24b8e10e00ad)) +- Snowflakeutil import (#7219) ([962f4bf](https://github.com/discordjs/discord.js/commit/962f4bf88211dbfb5ad0295a9467dede1e2688ee)) +- **Role:** Remove unused process (#7215) ([63034b4](https://github.com/discordjs/discord.js/commit/63034b44c9849087e391684d9b6c0c6ae9a21113)) +- **WebhookClient:** Updated webhook url regex (#6804) ([1c615d1](https://github.com/discordjs/discord.js/commit/1c615d1bb2606d5f19e55076d4ecab95c619518e)) +- **Sweepers:** Add sweepStickers function (#7213) ([95f8375](https://github.com/discordjs/discord.js/commit/95f8375d425f58f501f32ead03f7927e6596f8e6)) +- **InteractionCreate:** Use ChatInputCommandInteraction instead (#7210) ([49dada3](https://github.com/discordjs/discord.js/commit/49dada35f92470d3e4426362510847b93dd42d1a)) +- **Structues:** Rename old module's name (#7207) ([fbef454](https://github.com/discordjs/discord.js/commit/fbef45489457a2198357dc4dd303740d79036784)) +- **WebSocket:** Remove application command handler (#7202) ([033151c](https://github.com/discordjs/discord.js/commit/033151cf92fe43536b8a4c0f4d7d9ed75a2095c5)) +- **User:** `bannerURL()` should not throw when not present (#6789) ([3872acf](https://github.com/discordjs/discord.js/commit/3872acfeb8390f6f7202d69cf1f7f8616a7b0b34)) +- **VoiceState:** Ensure `suppress` & `streaming` have proper fallback values (#6377) ([a0d5f13](https://github.com/discordjs/discord.js/commit/a0d5f13dd9b27c44f5183a2a9af4c4fdecb312c0)) +- **sweepers:** Provide default for object param (#7182) ([ae2f013](https://github.com/discordjs/discord.js/commit/ae2f013653c8a9f9ffb12ae8fcdb1bb604b39236)) + +## Deprecation + +- **Caching:** Clean up deprecated cache sweeping (#7118) ([12ffa06](https://github.com/discordjs/discord.js/commit/12ffa069aa8b247e945fef16a543f41c2c391bf1)) + +## Documentation + +- Align webhook method return types with implementation (#8253) ([5aeed99](https://github.com/discordjs/discord.js/commit/5aeed9935058241648507d7f651679226a89dbb3)) +- Remove `@private` constructor documentation (#8255) ([452dec5](https://github.com/discordjs/discord.js/commit/452dec57ca422f5e7424a0f0e78c3e152717f413)) +- **ApplicationCommand:** Add `min_length` and `max_length` to ApplicationCommandOptionData (#8239) ([43f62bb](https://github.com/discordjs/discord.js/commit/43f62bb6678ec332795c8cfbe0c01854b95aa61e)) +- **MessageInteraction#commandName:** Updated description (#8212) ([ab238a9](https://github.com/discordjs/discord.js/commit/ab238a9046e0201dbd4755fa41fa69c44b186912)) +- Add missing `@extends` (#8205) ([e0c8282](https://github.com/discordjs/discord.js/commit/e0c82824905dcebf62c2d1afcc5e5590a5594838)) +- **Constants:** Fix SweeperKeys type (#8157) ([af04992](https://github.com/discordjs/discord.js/commit/af04992ed3c2617fda686c2bc7338dcada283dc6)) +- **Channels:** Internally document channel creation (#8154) ([5e5853a](https://github.com/discordjs/discord.js/commit/5e5853a4e885c47e3dde519761dd59a5ec0e06fc)) +- Update threads to use `ThreadAutoArchiveDuration` (#8153) ([ee36d60](https://github.com/discordjs/discord.js/commit/ee36d60dc6714c83569a20716fa8ca8e1bd7de4f)) +- **APITypes:** Remove duplicate type definition (#8144) ([a061233](https://github.com/discordjs/discord.js/commit/a0612335101c7ce2a07d95da4b79f0d4a2b1a6a0)) +- Document missing type definitions (#8130) ([203bc4a](https://github.com/discordjs/discord.js/commit/203bc4a2cf0c2d90a003093318aa0741605610f5)) +- **InteractionResponse:** Fix return (#8141) ([f1ac17c](https://github.com/discordjs/discord.js/commit/f1ac17c961cf95d99e205133605d10d8be5bd737)) +- **PermissionsBitField:** Fix `@name` of bitfield (#8115) ([3a77ce0](https://github.com/discordjs/discord.js/commit/3a77ce0b18c60a0b21ba088590ff89f2ace94087)) +- `TextBasedChannel` -> `TextBasedChannels` typos (#8110) ([db663a5](https://github.com/discordjs/discord.js/commit/db663a55c2ed2faf61e217009158da50dfcf274f)) +- Remove `number`s from enums (#8098) ([0a138da](https://github.com/discordjs/discord.js/commit/0a138dab95a86512f08ac3be356f77f38f2ea880)) +- **GuildAuditLogs:** Fix and reimplement type definitions (#8108) ([4155136](https://github.com/discordjs/discord.js/commit/415513696c7b7e139d1b958e480bf0c7e4d14111)) +- **WebSocketOptions:** Add `version` to docs and typings (#8050) ([386c41f](https://github.com/discordjs/discord.js/commit/386c41f24fb3c9d06967d9c1881a57645c3a71f2)) +- **BaseGuildTextChannel:** Update `setType()`'s parameter type (#8088) ([9c0f190](https://github.com/discordjs/discord.js/commit/9c0f190de1f743d9bd597ffd656503c672db71c1)) +- Update outdated examples (#8081) ([51eadf3](https://github.com/discordjs/discord.js/commit/51eadf37371a6138847efdb4b5b81ee132001cf0)) +- **ThreadMemberManager:** Require `member` in `FetchThreadMemberOptions` (#8079) ([552ec72](https://github.com/discordjs/discord.js/commit/552ec72542ec3b2b3ebf35c9fd84ab502dd746cf)) +- **AutocompleteInteraction:** Change useless log in responds example (#8077) ([ac7bf69](https://github.com/discordjs/discord.js/commit/ac7bf692bfce8204e278205dde811515a51f154b)) +- Description and missing `@typedef` fixes (#8087) ([a2eebf6](https://github.com/discordjs/discord.js/commit/a2eebf6c66f3e4c96ece9d2ae2a1133c84257f42)) +- Ignore docs of unexported functions (#8051) ([94bdcac](https://github.com/discordjs/discord.js/commit/94bdcaca62414a77d4ee0b8b79752a2be937320b)) +- **ClientOptions:** Fix closeTimeout default (#8049) ([b2eea1c](https://github.com/discordjs/discord.js/commit/b2eea1c900ba73d4b98b72f5c196f51e27d3ab8f)) +- **DirectoryChannel:** Extend `Channel` (#8022) ([f3f34f0](https://github.com/discordjs/discord.js/commit/f3f34f07b3b396015b130b8e9d938a3eec688fc3)) +- **Attachment:** Remove constructor doc (#8009) ([0a7953e](https://github.com/discordjs/discord.js/commit/0a7953e46310c77483d277539b47f1a7ab051fd9)) +- **VoiceChannel:** Annotate that it is implementing TextBasedChannel (#8007) ([5987dbe](https://github.com/discordjs/discord.js/commit/5987dbe5cff6991ae6905b0387411fa042d3e9b7)) +- Add missing discord-api-types external types (#8001) ([546d486](https://github.com/discordjs/discord.js/commit/546d48655f36ed9a6c6c5ce3c2eabcca1a86a945)) +- **InteractionResponses:** Replace outdated Embed example for reply (#7875) ([d308c66](https://github.com/discordjs/discord.js/commit/d308c66eeca6bdc3471637ae3aaaaa0a2f5c9989)) +- Require parameter (#7838) ([f4ccc67](https://github.com/discordjs/discord.js/commit/f4ccc6772c15e32489ca22fb2c3e803b85d4dbf9)) +- **ApplicationCommand:** Fix and improve localization docs (#7804) ([61a44c5](https://github.com/discordjs/discord.js/commit/61a44c509c40abaf7ffb95b10942889cbbf155ac)) +- **ApplicationCommand:** Fix ApplicationCommandOptionChoice (#7794) ([f1d0084](https://github.com/discordjs/discord.js/commit/f1d0084da26b0111ca029c789ad9e8e6c2882b4d)) +- Add back static properties and methods (#7706) ([520f471](https://github.com/discordjs/discord.js/commit/520f471ac56cbc01402b79197333a8a34c4ac5c9)) +- **InteractionCollector:** Document channel option type (#7551) ([e787cd5](https://github.com/discordjs/discord.js/commit/e787cd5fa5d013319347392ee4f799a677f6f512)) +- Correctly type getters (#7500) ([ffecf08](https://github.com/discordjs/discord.js/commit/ffecf084956f954cf10e1b844e00326e443a86f2)) +- ApplicationCommandData typedef (#7389) ([d32db88](https://github.com/discordjs/discord.js/commit/d32db8833e1058fb36f2e83af79d5353a9f2f693)) +- **channel:** Fix `isDMBased` docs (#7411) ([f2a7a9f](https://github.com/discordjs/discord.js/commit/f2a7a9f1b30af272a6a8d81825d09f84e749cc24)) +- **messageattachment:** Fix `contentType` docs (#7413) ([2800e07](https://github.com/discordjs/discord.js/commit/2800e07e5974e07b9f8ce043722b9b99a5bcc80d)) +- Add supported option types for autocomplete (#7368) ([8bb3751](https://github.com/discordjs/discord.js/commit/8bb37513400d646d784d59875d6b6a6ec10160cd)) +- Add external builder docs links (#7390) ([0b866c9](https://github.com/discordjs/discord.js/commit/0b866c9fb284971113e288e52327d4506db28011)) +- Add EnumResolvers (#7353) ([72767a1](https://github.com/discordjs/discord.js/commit/72767a1059526bdf617e80d5a9e5da1fbd2936d3)) +- **locales:** Update Discord API docs link (#7266) ([b640272](https://github.com/discordjs/discord.js/commit/b6402723c31bed3c49f8b8cde873b65b9f373fd7)) +- **StageInstance:** Deprecate discoverableDisabled (#7179) ([bd33ebb](https://github.com/discordjs/discord.js/commit/bd33ebb507eab36bc2219103dbd1e0217b9f38c0)) +- **shardingmanager:** Fix type of `execArgv` option (#7284) ([e65da44](https://github.com/discordjs/discord.js/commit/e65da44d9c564d1ffcb0f4df2bcdaf0ce0636f35)) +- **interaction:** Add locale list link (#7261) ([37ec0bd](https://github.com/discordjs/discord.js/commit/37ec0bda6df75fb1dc69b7a1eafbb8ea19e68457)) +- Fix a typo and use milliseconds instead of ms (#7251) ([0dd56af](https://github.com/discordjs/discord.js/commit/0dd56afe1cdf16f1e7d9afe1f8c29c31d1833a25)) +- Fix command interaction docs (#7212) ([137ea24](https://github.com/discordjs/discord.js/commit/137ea249df3aa6b8375ecb42aa456a6fdb811f19)) +- **TextBasedChannel:** Fixed syntax error in examples (#7163) ([b454740](https://github.com/discordjs/discord.js/commit/b454740ae87b6c3c13536181965519c7277e5840)) +- **TextBasedChannel:** Fix #createMessageComponentCollector description (#7168) ([d4e6e03](https://github.com/discordjs/discord.js/commit/d4e6e0370857dff00185d59faf8aaac12b343a7a)) +- Fixes the examples for kick and ban (#7170) ([db669b8](https://github.com/discordjs/discord.js/commit/db669b897132ec458d50ca6c1e3afa761e98ffc3)) +- **RoleManager:** Fix incorrect example (#7174) ([f79ea67](https://github.com/discordjs/discord.js/commit/f79ea67d3a9ba134a9acef0a443bd089c4e173a6)) + +## Features + +- **builder:** Add max min length in string option (#8214) ([96c8d21](https://github.com/discordjs/discord.js/commit/96c8d21f95eb366c46ae23505ba9054f44821b25)) +- **applicationCommand:** Add max min length in string option (#8215) ([94ee60d](https://github.com/discordjs/discord.js/commit/94ee60d3d438f6657bdef51471528769af09624c)) +- Add website documentation early mvp (#8183) ([d95197c](https://github.com/discordjs/discord.js/commit/d95197cc78593df4d0a8d1cc492b0e41b4ab58b8)) +- **BaseInteraction:** Add support for `app_permissions` (#8194) ([002d6a5](https://github.com/discordjs/discord.js/commit/002d6a5aede3d1c0e08bd58eeef38a3b9202f525)) +- **util:** ParseWebhookURL (#8166) ([c4653f9](https://github.com/discordjs/discord.js/commit/c4653f97b1529eb0b99fccdba67c37eb4f467ff9)) +- **AutocompleteInteraction:** Add `commandGuildId` (#8086) ([10a6c42](https://github.com/discordjs/discord.js/commit/10a6c4287dd45a30290814e50fa29a086f85da02)) +- **guild:** Add support for setting MFA level (#8024) ([c5176be](https://github.com/discordjs/discord.js/commit/c5176be14b697ff506eb973c4119644eab544304)) +- **vcs:** Add missing property and methods (#8002) ([0415300](https://github.com/discordjs/discord.js/commit/0415300243877ddbcb501c0a26b1ff65618a1da7)) +- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21)) +- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc)) +- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86)) +- Backport handle zombie connection (#7626) ([e1176fa](https://github.com/discordjs/discord.js/commit/e1176faa27898d4f127c293c099201cb294e10ee)) +- **CommandInteraction:** Add 'commandGuildId' (#8018) ([aa59a40](https://github.com/discordjs/discord.js/commit/aa59a409b36c7ef7018d1785d2dba4da17b57864)) +- Allow builders to accept rest params and arrays (#7874) ([ad75be9](https://github.com/discordjs/discord.js/commit/ad75be9a9cf90c8624495df99b75177e6c24022f)) +- **MessageReaction:** Add react method (#7810) ([a328778](https://github.com/discordjs/discord.js/commit/a3287782b57c28b94c390c24e7d5f2d8c303301f)) +- **Collector:** Add `ignore` event (#7644) ([5244fe3](https://github.com/discordjs/discord.js/commit/5244fe3c1cd400985b00e95d8e5ec73823cf4f25)) +- **GuildMemberManager:** Add `GuildMemberManager#fetchMe()` (#7526) ([349766d](https://github.com/discordjs/discord.js/commit/349766dd6925e2d5e5597cc78c73e46f17c56eab)) +- **guildChannelManager:** Add `videoQualityMode` option for `create()` (#7980) ([cdd2ba0](https://github.com/discordjs/discord.js/commit/cdd2ba036ab1559783eb067786c52aff61807557)) +- **EnumResolvers:** Remove Enumresolvers (#7876) ([76694c1](https://github.com/discordjs/discord.js/commit/76694c1497de1b083a792fd1fda20f0eace50c48)) +- Move `me` to `GuildMemberManager` manager (#7669) ([aed687b](https://github.com/discordjs/discord.js/commit/aed687b09f87862eb2f33fb9f95b2cbd0b770585)) +- **rest:** Use undici (#7747) ([d1ec8c3](https://github.com/discordjs/discord.js/commit/d1ec8c37ffb7fe3b63eaa8c382f22ca1fb348c9b)) +- **VoiceChannel:** Add support for text in voice (#6921) ([4ba0f56](https://github.com/discordjs/discord.js/commit/4ba0f56b6af64bac30eea807fb3e9f3c41c3c83c)) +- **SelectMenu:** Allow emojis in options and option constructors (#7797) ([f22245e](https://github.com/discordjs/discord.js/commit/f22245e9d072ac4ef63b0ae0d84d5ba94608ce22)) +- Allow `createMessageComponentCollector` without using `fetchReply` (#7623) ([a58556a](https://github.com/discordjs/discord.js/commit/a58556adc02b2b9239c8f277a4387c743c9d6f04)) +- Add guild directory support (#6788) ([b01f414](https://github.com/discordjs/discord.js/commit/b01f4147d4f3bca021bc269c9f06463f06e3db53)) +- **GuildBanManager:** Support pagination results (#7734) ([fc2a8bb](https://github.com/discordjs/discord.js/commit/fc2a8bb6750919ecd6ee7c872df05f4b677ff5d3)) +- **CommandInteraction:** Add support for localized slash commands (#7684) ([01a423d](https://github.com/discordjs/discord.js/commit/01a423d110cfcddb3d794fcc32579a1547dd472d)) +- Allow emoji strings to be passed through constructors (#7718) ([0faac04](https://github.com/discordjs/discord.js/commit/0faac04b69f1dda3dc860cd584af100e36a40917)) +- **StageInstanceManager:** Add `sendStartNotification` option to create (#7730) ([29f8807](https://github.com/discordjs/discord.js/commit/29f88079559cc02ccfef7a7c16458d481e573fb5)) +- Add `makeURLSearchParams` utility function (#7744) ([8eaec11](https://github.com/discordjs/discord.js/commit/8eaec114a98026024c21545988860c123948c55d)) +- **modal:** Add `awaitModalSubmit` (#7751) ([3037fca](https://github.com/discordjs/discord.js/commit/3037fca196a0f9238d53bb51394daf737bbf3742)) +- **Actions:** Add parent structure to events parameters (#7577) ([3f3e432](https://github.com/discordjs/discord.js/commit/3f3e4327c86da86734c19a96e97115bd505b4532)) +- Export `UnsafeModalBuilder` and `UnsafeTextInputBuilder` (#7628) ([6fec252](https://github.com/discordjs/discord.js/commit/6fec25239dfed46a30826d38dc97f3680f24ec65)) +- **VoiceChannel:** Support `video_quality_mode` (#7722) ([3b3dabf](https://github.com/discordjs/discord.js/commit/3b3dabf3da2e2f24b81967d68b581d7f7452273f)) +- Add API v10 support (#7477) ([72577c4](https://github.com/discordjs/discord.js/commit/72577c4bfd02524a27afb6ff4aebba9301a690d3)) +- **embed:** Remove Embed.setColor (#7662) ([9b0d8cb](https://github.com/discordjs/discord.js/commit/9b0d8cb2d8f7b55753de584eb3a3f347f87596c2)) +- **StageInstance:** Add support for associated guild event (#7576) ([3dff31f](https://github.com/discordjs/discord.js/commit/3dff31f63fe4afdcc818193d737e1917f1ac8105)) +- **VoiceState:** Add edit method (#7569) ([b162f27](https://github.com/discordjs/discord.js/commit/b162f27e46524bfc64515969d753c6e8f30e6c40)) +- **ModalSubmitInteraction:** Add boolean properties (#7596) ([8907390](https://github.com/discordjs/discord.js/commit/89073903a253d9408839573502c72cae93fe70b6)) +- Add Modals and Text Inputs (#7023) ([ed92015](https://github.com/discordjs/discord.js/commit/ed920156344233241a21b0c0b99736a3a855c23c)) +- **discord.js:** Partial transition to undici (#7482) ([5158332](https://github.com/discordjs/discord.js/commit/51583320d3b0f6452cd96bad1021f2a57e4cc6f6)) +- **message:** Add `reason` on pin and unpin (#7520) ([00728f7](https://github.com/discordjs/discord.js/commit/00728f72b36123b607502624b4b02a02ee524d4a)) +- Re-export AuditLogEvent enum (#7528) ([6a2fa70](https://github.com/discordjs/discord.js/commit/6a2fa70b8e79a460be38916eeb605976ad6fe68b)) +- **options:** Add support for custom JSON transformers (#7476) ([dee27db](https://github.com/discordjs/discord.js/commit/dee27db35af379b0835f9fd5cc19563f7bf3dfc0)) +- Add CategoryChannelChildManager (#7320) ([5cf5071](https://github.com/discordjs/discord.js/commit/5cf5071061760c2f9c1e36d7648aef544b03323a)) + - **Co-authored-by:** Antonio Román <kyradiscord@gmail.com> +- Attachment application command option type (#7200) ([0034396](https://github.com/discordjs/discord.js/commit/003439671d359dcfe481446ef12b90bd71c57835)) +- **builders:** Add attachment command option type (#7203) ([ae0f35f](https://github.com/discordjs/discord.js/commit/ae0f35f51d68dfa5a7dc43d161ef9365171debdb)) +- **scheduledevents:** Add image option (#7436) ([fbc71ef](https://github.com/discordjs/discord.js/commit/fbc71ef6b668c4b1e2b065d9b65541d9303db0a0)) +- Add methods to managers (#7300) ([dd751ae](https://github.com/discordjs/discord.js/commit/dd751ae19da196cc2f90ccd35c7d8e99878daaf9)) +- **channel:** Add .url getter (#7402) ([f59d630](https://github.com/discordjs/discord.js/commit/f59d6305cb0cd0d154a909f18be76407c4d452d3)) +- **components:** Add unsafe message component builders (#7387) ([6b6222b](https://github.com/discordjs/discord.js/commit/6b6222bf513d1ee8cd98fba0ad313def560b864f)) +- **thread:** Add `newlyCreated` to `threadCreate` event (#7386) ([51beda5](https://github.com/discordjs/discord.js/commit/51beda56f74e44ed013b5d25044b8d5fd1978b29)) +- **channel:** Add isDMBased typeguard (#7362) ([388f535](https://github.com/discordjs/discord.js/commit/388f53550cca7ded7350a050fda03c36e4c1fdf7)) +- **`Interaction`:** Add `.commandType` property to `CommandInteraction` and `AutocompleteInteraction` (#7357) ([567db60](https://github.com/discordjs/discord.js/commit/567db60475c8704661b2e788c9905ef364d6c00c)) +- **scheduledevent:** Add support for event cover images (#7337) ([355f579](https://github.com/discordjs/discord.js/commit/355f579771771a28a293c327a38574c8918d18f8)) +- **enumResolvers:** Strengthen typings (#7344) ([9a566e8](https://github.com/discordjs/discord.js/commit/9a566e8068f28fce87c07861ef1d2877c6ae105f)) +- Allow setting message flags when sending (#7312) ([706db92](https://github.com/discordjs/discord.js/commit/706db9228a91ef42e49d2ec749eac153b9ef75d0)) +- **minor:** Add application_id to Webhook (#7317) ([5ccdb0a](https://github.com/discordjs/discord.js/commit/5ccdb0ab266e4f74c331386ac2d6dd32bc225c62)) +- **threadchannel:** Add `createdTimestamp` field (#7306) ([9a16234](https://github.com/discordjs/discord.js/commit/9a1623425ae2d69f5c16f0096af4951ff5096e80)) +- **GuildPreview:** Add stickers (#7152) ([cf25de9](https://github.com/discordjs/discord.js/commit/cf25de9373df98b3c1cd0ca0a092d9dc8172929d)) +- Enum resolvers & internal enum string removal (#7290) ([213acd7](https://github.com/discordjs/discord.js/commit/213acd799738b888d550cdf3f08906764f8288e0)) +- **guildemojimanager:** Add `delete` and `edit` methods (#7286) ([9181a31](https://github.com/discordjs/discord.js/commit/9181a31e0ba330502052c94da544bb15c8b66f11)) +- **interaction:** Add `isRepliable` type guard (#7259) ([da05a88](https://github.com/discordjs/discord.js/commit/da05a8856b11cc1bf0df424c88a1cf9573e5b654)) +- **Channel:** Improve typeguards (#6957) ([37a22e0](https://github.com/discordjs/discord.js/commit/37a22e04c27724c2a65b05c701e3000ba3653ba1)) +- Add Locales to Interactions (#7131) ([9052e32](https://github.com/discordjs/discord.js/commit/9052e321d1c9c8841962d4e8dc5d9e060b104438)) +- **Permissions:** Remove deprecated thread-related permissions (#6755) ([ab3ff5a](https://github.com/discordjs/discord.js/commit/ab3ff5a262caf7d6225b8d6b54ab2c6b6613c0d0)) +- **VoiceRegion:** Remove the unsent vip field (#6759) ([caaef53](https://github.com/discordjs/discord.js/commit/caaef53dd97ecac9f714072ddba5ae9a99ab1027)) +- **richpresenceassets:** Add YouTube and custom image support (#7184) ([d06d70c](https://github.com/discordjs/discord.js/commit/d06d70ccf26c04c1122fac8430922588a489f95e)) +- **Collector:** Yield all collected values (#7073) ([2b480cb](https://github.com/discordjs/discord.js/commit/2b480cb14e6f52855efcb372da7fb455c15b13b1)) + +## Refactor + +- **Util:** Rename `fetchRecommendedShards` (#8298) ([cafde77](https://github.com/discordjs/discord.js/commit/cafde77d73452d729ba8e2cb1cac3f14235b889b)) +- **Embed:** Add all the types (#8254) ([64f8140](https://github.com/discordjs/discord.js/commit/64f814066cc4adebaca47eb8d7a2040a8df399ae)) +- **rest:** Add content-type(s) to uploads (#8290) ([103a358](https://github.com/discordjs/discord.js/commit/103a3584c95a7b7f57fa62d47b86520d5ec32303)) +- Make `GuildAuditLogsEntry.action` return an `AuditLogEvent` (#8256) ([f0b68d5](https://github.com/discordjs/discord.js/commit/f0b68d57368d7ac3db97925df68c11a945ccd84c)) +- **builder:** Remove `unsafe*Builder`s (#8074) ([a4d1862](https://github.com/discordjs/discord.js/commit/a4d18629828234f43f03d1bd4851d4b727c6903b)) +- Make `ShardEvents` the events of `Shard` (#8185) ([c5750d5](https://github.com/discordjs/discord.js/commit/c5750d59f529ab48a5bc88a73a1c449ef6ddbffd)) +- **Util:** Make single `replace` call in `cleanContent` (#8210) ([6b20645](https://github.com/discordjs/discord.js/commit/6b206457400ce31d566b02a0c135042afb540853)) +- **ApplicationCommandManager:** Use `makeURLSearchParams` (#8196) ([cb3dca4](https://github.com/discordjs/discord.js/commit/cb3dca4ae029724421f3d04a784ace0ae2de75e2)) +- Use `Base` prefix for channel and interaction base classes (#8099) ([e24970e](https://github.com/discordjs/discord.js/commit/e24970e3c3d24f71ba711e59666cd8a49a33e33b)) +- **Constants:** Remove leftover code (#8156) ([cd17aad](https://github.com/discordjs/discord.js/commit/cd17aad720430d23af51c364caeb8b22bf6cb6b5)) +- Errors (#8068) ([e68effa](https://github.com/discordjs/discord.js/commit/e68effa822f064a324ed5b92e797c9fc3ce5e211)) +- **ClientOptions:** Remove `$` prefix from `ws.properties` keys (#8094) ([90a98fe](https://github.com/discordjs/discord.js/commit/90a98fee16b7d1d06768461f4e85127c0edf8419)) +- Use `GuildFeature` enum (#8101) ([e5ec1c4](https://github.com/discordjs/discord.js/commit/e5ec1c4dbc3fa54b2c43d1fec24932d7363e17cb)) +- **util:** Make utility functions top level (#8052) ([e53d162](https://github.com/discordjs/discord.js/commit/e53d1621986035b0c92a1782f6e013d408480e00)) +- **ApplicationCommand:** Permissions v2 (#7857) ([c7391db](https://github.com/discordjs/discord.js/commit/c7391db11b3efd4b1a6904affb26887ad06d6db4)) +- ***:** Include name/reason/etc fields into options/data params (#8026) ([9c8b310](https://github.com/discordjs/discord.js/commit/9c8b3102ce00d1f2c1255c150fb3030f8b6dd026)) +- **ThreadMemberManager:** Consistent thread member fetching (#8021) ([da9107c](https://github.com/discordjs/discord.js/commit/da9107c007536952107bd92943b6c714538d5aeb)) +- **interactions:** Remove redundant interaction typeguards (#8027) ([f57d676](https://github.com/discordjs/discord.js/commit/f57d6768ad24f6e37dc598f9c93709449d3bc4dd)) +- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a)) +- **channel:** Remove redundant channel type guards (#8012) ([70c733b](https://github.com/discordjs/discord.js/commit/70c733bb9a5bde0f79e6bea0bdc416458bda4c06)) +- Always return `Message` instances in interactions (#7917) ([9720e55](https://github.com/discordjs/discord.js/commit/9720e555340431c3b3ad7bd670ad0ac7eee8865f)) +- **attachment:** Don't return attachment builders from API (#7852) ([dfadcbc](https://github.com/discordjs/discord.js/commit/dfadcbc2fd50be64c8a0c1cae3be10f83678c5ee)) +- Clean up modal submissions (#7994) ([643dab3](https://github.com/discordjs/discord.js/commit/643dab3b1b5305d002fcefed62755bbe11fc3267)) +- **ThreadChannel:** Remove `MAX` helper from threads (#7846) ([dfd9eb2](https://github.com/discordjs/discord.js/commit/dfd9eb20b2d3e0e7db26744b1f15134ac6eda139)) +- **Activity:** Remove undocumented properties (#7844) ([5ba7740](https://github.com/discordjs/discord.js/commit/5ba7740fcfefda1eeba81ace4e6351eac02522a4)) +- **MessageAttachment:** Use `Attachment` instead (#7691) ([ab4c608](https://github.com/discordjs/discord.js/commit/ab4c608b97ff319935e1a7f23564622bfd7ddd57)) +- **Util:** Remove splitting (#7780) ([54e5629](https://github.com/discordjs/discord.js/commit/54e56299865a6746744544ba25d5540a1166d27c)) +- Tidy up builders and components (#7711) ([96a0d83](https://github.com/discordjs/discord.js/commit/96a0d83a1366703ecae40b5e0d5171be9123d079)) +- Remove nickname parsing (#7736) ([78a3afc](https://github.com/discordjs/discord.js/commit/78a3afcd7fdac358e06764cc0d675e1215c785f3)) +- Remove store channels (#7634) ([aedddb8](https://github.com/discordjs/discord.js/commit/aedddb875e740e1f1bd77f06ce1b361fd3b7bc36)) +- **IntegrationApplication:** Remove `summary` (#7729) ([eb6b472](https://github.com/discordjs/discord.js/commit/eb6b472f72488cad7e96befccc00270cf6dc01b8)) +- **GuildAuditLogs:** Remove build (#7704) ([cedd053](https://github.com/discordjs/discord.js/commit/cedd0536baa1301984daf89dfda4e63a7be595a2)) +- **InteractionCollector:** Simplify constructor logic (#7667) ([07b23a9](https://github.com/discordjs/discord.js/commit/07b23a99c7088a7c740f23051f3f755f091519b0)) +- Remove undocumented checks (#7637) ([9a6e691](https://github.com/discordjs/discord.js/commit/9a6e691eaa6c3d133098b2734414590cb838de2e)) +- Allow builders to accept emoji strings (#7616) ([fb9a9c2](https://github.com/discordjs/discord.js/commit/fb9a9c221121ee1c7986f9c775b77b9691a0ae15)) +- Use `static` fields (#7701) ([e805777](https://github.com/discordjs/discord.js/commit/e805777a7a81d1dc7a2edd9741ecb04e685a3886)) +- **EmbedBuilder:** Allow hex strings in setColor (#7673) ([f472975](https://github.com/discordjs/discord.js/commit/f4729759f600372455f062c75859f084e23a5d78)) +- Don't return builders from API data (#7584) ([549716e](https://github.com/discordjs/discord.js/commit/549716e4fcec89ca81216a6d22aa8e623175e37a)) +- **embed:** Allow hex strings in `setColor()` (#7593) ([79d6c04](https://github.com/discordjs/discord.js/commit/79d6c0489c3d563fdd05de63c4fcf93a6deefce1)) +- **InteractionResponses:** Use ClientOptions.jsonTransformer (#7599) ([fac55bc](https://github.com/discordjs/discord.js/commit/fac55bcfd1e8b76aae1273415f74fa6de7aca66d)) +- Deprecate invite stage instance (#7437) ([d2bc9d4](https://github.com/discordjs/discord.js/commit/d2bc9d444f42a70a3c4cc4c68eb107bcaebec509)) +- **guild:** Move `premiumSubscriptionCount` to `AnonymousGuild` (#7451) ([6d3da22](https://github.com/discordjs/discord.js/commit/6d3da226d3c003d137639e719394a807330e4844)) +- **actions:** Use optional chaining (#7460) ([d1bb362](https://github.com/discordjs/discord.js/commit/d1bb36256f2f86022884e6ee9e05b0536cb6384d)) +- **guildbanmanager:** Rename days option to deleteMessageDays (#7447) ([0dfdb2c](https://github.com/discordjs/discord.js/commit/0dfdb2cf11e236e67dd34277108973b5b79790a8)) +- Make public builder props getters (#7422) ([e8252ed](https://github.com/discordjs/discord.js/commit/e8252ed3b981a4b7e4013f12efadd2f5d9318d3e)) +- Remove redundant API defaults (#7449) ([532846b](https://github.com/discordjs/discord.js/commit/532846b1f8260d85022a022d093553310052afc9)) +- Allow discord.js builders to accept camelCase (#7424) ([94bf727](https://github.com/discordjs/discord.js/commit/94bf727cc3a2f11c88e95cdb151b235f775cd1ca)) +- Replace `WSCodes`, `WSEvents`, and `InviteScopes` with `discord-api-types` equivalent (#7409) ([cc25455](https://github.com/discordjs/discord.js/commit/cc25455d2c75177e3eddc880b7fd53cb122387c4)) +- Make constants enums top level and `PascalCase` (#7379) ([d8184f9](https://github.com/discordjs/discord.js/commit/d8184f94dd08daab37195f52828e06af5ed1c1e0)) +- **`Bitfield`:** Use discord-api-types enums instead (#7313) ([fbb1d03](https://github.com/discordjs/discord.js/commit/fbb1d0328bcd517027ad2eedb8753d17489ed851)) +- Use `@discordjs/rest` (#7298) ([ec0fba1](https://github.com/discordjs/discord.js/commit/ec0fba1ed0d3c5b1bb18171ece6fe5ee42d48497)) +- Switch to /builders `Embed` (#7067) ([d2d3a80](https://github.com/discordjs/discord.js/commit/d2d3a80c556a104099a1ddb1b24f1b921c553257)) +- Remove transformPermissions (#7303) ([b4ed8fd](https://github.com/discordjs/discord.js/commit/b4ed8fd3ed953085cd908b2845d4384c8555d3a2)) +- Remove VoiceChannel#editable (#7291) ([164589c](https://github.com/discordjs/discord.js/commit/164589c5516a847457444d11098981d557b6778b)) +- Remove boolean option for `Webhook#fetchMessage` (#7293) ([347ff80](https://github.com/discordjs/discord.js/commit/347ff80bbc9bc5243b7f68ba5d745782eadeba21)) +- **subcommandgroup:** Required default to false (#7217) ([6112767](https://github.com/discordjs/discord.js/commit/6112767128a664f32205425f52ba52220d57834f)) +- **invite:** Make `channel` and `inviter` getters (#7278) ([18b0ed4](https://github.com/discordjs/discord.js/commit/18b0ed4cbe8285637a971c7c99ee49d18060a403)) +- Remove required from getMember (#7188) ([c90e47f](https://github.com/discordjs/discord.js/commit/c90e47f90403e5b1b3499b213dcdf2704fd96b66)) +- Remove djs components and use /builders components instead (#7252) ([101d7c5](https://github.com/discordjs/discord.js/commit/101d7c5ffa03edcf8cb8a0647b77d5c9a38e4bdd)) +- Default *URL methods to animated hash (#7149) ([7c07976](https://github.com/discordjs/discord.js/commit/7c07976018728154be0ce0314d3e8dfe8eb9ed5b)) +- Use setPosition inside edit (#7263) ([0b23b7f](https://github.com/discordjs/discord.js/commit/0b23b7f0394a20596c8d85b82870c3f35ea6b0e0)) +- Don't disable import order lint (#7262) ([0a5d5f3](https://github.com/discordjs/discord.js/commit/0a5d5f38c0b1a249fa2efe16f3b601c90622a4d5)) +- Remove discord.js enums and use discord-api-types enums instead (#7077) ([aa6d1c7](https://github.com/discordjs/discord.js/commit/aa6d1c74de01dd9a8f020c43fb2c193c4729df8d)) +- **application:** Remove fetchAssets (#7250) ([1479e40](https://github.com/discordjs/discord.js/commit/1479e40bcecc4c28ecb9f05fa4fbbdfe3bd387e1)) +- PresenceUpdate and demuxProbe (#7248) ([1745973](https://github.com/discordjs/discord.js/commit/174597302408f13c5bb685e2fb02ae2137cb481d)) +- **embeds:** Don't create new embed instances when unnecessary (#7227) ([822dc67](https://github.com/discordjs/discord.js/commit/822dc678da626de7b4fb22a747cd3cd2e8376732)) +- **GuildMember:** Throw better errors on #kickable and #bannable (#7137) ([4fd127e](https://github.com/discordjs/discord.js/commit/4fd127e79edfa1851f8a10242838f9d7aa68c8c3)) +- **SnowflakeUtil:** Switch to `@sapphire/snowflake` (#7079) ([e082dfb](https://github.com/discordjs/discord.js/commit/e082dfb1584926e4c05face5966d16e4a2921bc5)) +- **InteractionCreate:** Remove interaction event (#6326) ([ae876d9](https://github.com/discordjs/discord.js/commit/ae876d962453ccf843f8e6f70666a98a3173bb75)) +- **MessageCreate:** Remove message event (#6324) ([171e917](https://github.com/discordjs/discord.js/commit/171e917fb96b6bf39a6ad70e83be646f72fe451e)) +- **integration:** Turn undefined into null and consistency (#7209) ([13eb782](https://github.com/discordjs/discord.js/commit/13eb78256da901e6c3c405f546f36617ef5e8239)) +- Remove `deleted` field (#7092) ([cee7fd1](https://github.com/discordjs/discord.js/commit/cee7fd181c464e44eabf20b511d12589f2453722)) +- **Dates:** Save timestamps everywhere and use Date.parse (#7108) ([55e21f5](https://github.com/discordjs/discord.js/commit/55e21f53663a91863c63b6d9f3a8c35564664061)) +- **RoleManager:** Remove `comparePositions()` (#7201) ([fbbac27](https://github.com/discordjs/discord.js/commit/fbbac279789427b2c36869dc47b65fb08431e14d)) +- Better Command Terminology (#7197) ([b7856e7](https://github.com/discordjs/discord.js/commit/b7856e7809ff6fa21fe00286f885808535624f7c)) +- **Actions:** Remove deleted maps (#7076) ([5022b14](https://github.com/discordjs/discord.js/commit/5022b14da09e9b421f947e9bc385a0574cbf07d1)) +- **Client:** Remove applicationCommand events (#6492) ([6085b4f](https://github.com/discordjs/discord.js/commit/6085b4f72723d4ff82f7fea504241d14c94af21e)) +- Remove `Util.removeMentions()` (#6530) ([0c24cc8](https://github.com/discordjs/discord.js/commit/0c24cc8ec0d818315cc8f8bcf74fce060847ac79)) +- **Constants:** Change APPLICATION_COMMAND -> CHAT_INPUT_COMMAND (#7018) ([75616a3](https://github.com/discordjs/discord.js/commit/75616a305f9af33013486b13a872a39212101ce7)) +- **Guild:** Remove deprecated setXPositions methods (#6897) ([43e5e3c](https://github.com/discordjs/discord.js/commit/43e5e3c339a96fa895267d4538eee1d5e5843d05)) +- **UserFlags:** Update flag names (#6938) ([b246fc4](https://github.com/discordjs/discord.js/commit/b246fc4101b8e4957ffd1af8e2e4986a020ca211)) + +## Styling + +- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629)) + +## Typings + +- **GuildFeature:** Allow feature strings to be passed (#8264) ([b7d4e55](https://github.com/discordjs/discord.js/commit/b7d4e55419207d4e25f5c40cab221c7c04a617bf)) +- **CategoryChannelChildManager:** Fix Holds type (#8288) ([33a7a5c](https://github.com/discordjs/discord.js/commit/33a7a5cbdc00d2a5034dc1ec91fec5da7042f9d0)) +- Remove `MemberMention` (#8292) ([bf65b37](https://github.com/discordjs/discord.js/commit/bf65b37d1a9ea8417e26ad4afacea1eb45a0ff5a)) +- **GuildMemberManager:** Fix placement for `fetchMe()` (#8258) ([7525615](https://github.com/discordjs/discord.js/commit/75256153a9923d94ca709a37aaccc48dfb43c153)) +- Convert `Events` to an enum (#8246) ([feb3bdd](https://github.com/discordjs/discord.js/commit/feb3bdda0a3c3da80378c8cbcafca2968551eef9)) +- **GuildMemberManager:** Non-void return of `edit()` (#8186) ([c7a205f](https://github.com/discordjs/discord.js/commit/c7a205f7b992eea43af13a4638e2a03db7bc0d8a)) +- Add missing shard types (#8180) ([27d8deb](https://github.com/discordjs/discord.js/commit/27d8deb4716a87704370a95103b16fa1b763de18)) +- Implement `GuildChannelEditOptions` (#8184) ([b83e0c0](https://github.com/discordjs/discord.js/commit/b83e0c0caffc2b767aa1ba4412580970a6901899)) +- **Status:** Add missing members (#8179) ([8421f92](https://github.com/discordjs/discord.js/commit/8421f9203bd2d85ef8e64c3fb9a991c74223a75d)) +- **GuildScheduledEvent#scheduledStartAt:** Should be nullish (#8111) ([65dc8d6](https://github.com/discordjs/discord.js/commit/65dc8d677ee81469c0eeb4ecdd83fe2f68cc8982)) +- Fix modal builder constructor data type (#8143) ([7279f9c](https://github.com/discordjs/discord.js/commit/7279f9c31b14bc1e78c63b7298e80e37ca5dfe0c)) +- Use `ThreadAutoArchiveDuration` from discord-api-types (#8145) ([a3799f9](https://github.com/discordjs/discord.js/commit/a3799f9ebb027904830457119708d550e2009200)) +- **Shard#reconnecting:** Fix event name (#8118) ([95e6d6e](https://github.com/discordjs/discord.js/commit/95e6d6ede03c4fb92a8d8027a085e84b043fd895)) +- **ApplicationCommand:** Fix typo in setDMPermission (#8097) ([4df491c](https://github.com/discordjs/discord.js/commit/4df491ce8578a1b01ee8412a4df8137a302e7202)) +- Fix `setType()` parameter and `ChannelData.type` (#8089) ([b4e28a8](https://github.com/discordjs/discord.js/commit/b4e28a8ff6bf165c54a8726d3bc3a3cc0c1e469b)) +- Fix `ApplicationCommandPermissionsUpdate` event typings (#8071) ([9964454](https://github.com/discordjs/discord.js/commit/9964454c2944a0523399481a5f609144486e549b)) +- **AutocompleteOption:** Fix and improve types (#8069) ([476b7d5](https://github.com/discordjs/discord.js/commit/476b7d519c719152ea04e207f6dd09bb23e733db)) +- **ThreadMemberManager:** Fix return type of fetching members with no arguments (#8060) ([2392a6f](https://github.com/discordjs/discord.js/commit/2392a6f5de2efcf6b326173d26295c928b94adb6)) +- Remove isAutocomplete typeguard from typings (#8063) ([c0f079d](https://github.com/discordjs/discord.js/commit/c0f079d2325a636c83ac676c525bfa89ce308b3c)) +- **AttachmentBuilder:** Fix data type (#8016) ([7fa698d](https://github.com/discordjs/discord.js/commit/7fa698d23e548987762c4c66c96c510d9ea56eb4)) +- **modal:** Fix `showModal()` typings (#8014) ([0ccc243](https://github.com/discordjs/discord.js/commit/0ccc243c8ffbf852660c899cc2ad47bd5ebb65cb)) +- Fix some attachment related typings (#8013) ([6aa6232](https://github.com/discordjs/discord.js/commit/6aa623240ee94b117c7e69c1d09b50923a8f7a4c)) +- **AttachmentBuilder:** Remove name parameter from constructor (#8008) ([6266b0c](https://github.com/discordjs/discord.js/commit/6266b0c1e323f9522010f90f34ce6f17fcb6e769)) +- Add types to `EventEmitter` static methods (#7986) ([d60c464](https://github.com/discordjs/discord.js/commit/d60c464e618e4159d2656e7832798909832f33cd)) +- Nullify `guildScheduledEventUpdate`'s old parameter (#7955) ([fdeac9d](https://github.com/discordjs/discord.js/commit/fdeac9d9fba06c532eca296ddd8479047bc732bf)) +- Make `CacheType` generic more accurate for return values (#7868) ([e07b910](https://github.com/discordjs/discord.js/commit/e07b910e684bc3cf71fb93417951ad42351bace4)) +- **guildScheduledEvent:** Mark `entityMetadata` as nullable (#7908) ([64bdf53](https://github.com/discordjs/discord.js/commit/64bdf53116945ffb51764bb8ec539d530aefcfb1)) +- **discord.js:** Export missing enums (#7864) ([5eeef3f](https://github.com/discordjs/discord.js/commit/5eeef3f708eb900ec994d837fb4cd414a4f4b437)) +- Fix return type of `toString()` on channels (#7836) ([ece6289](https://github.com/discordjs/discord.js/commit/ece628986c7eb1a66f46076d8f8518c9ff00aaf3)) +- **Message#activity:** Make `partyId` optional and use enum for `type` (#7845) ([bfeaf85](https://github.com/discordjs/discord.js/commit/bfeaf856f76eb7cb756ac55aac13636ccdb345b6)) +- Cleanup *Data type definitions (#7716) ([585169f](https://github.com/discordjs/discord.js/commit/585169f2f097ffb1940d17f549e4290aa55acde2)) +- Fix BooleanCache never resolving to true (#7809) ([440ac24](https://github.com/discordjs/discord.js/commit/440ac243ca1d6f8cd04603e63e3f2f6ea1722ee8)) +- **CommandInteraction:** Add awaitModalSubmit (#7811) ([a6d9ce5](https://github.com/discordjs/discord.js/commit/a6d9ce57c6cae90d0afc60010cad44fdc2c2d06c)) +- **ThreadChannel:** Fix autoArchiveDuration types (#7816) ([0857476](https://github.com/discordjs/discord.js/commit/08574763eb665b5a43ccfb826929f1e3f0d1c3a7)) +- Add missing typing (#7781) ([f094e33](https://github.com/discordjs/discord.js/commit/f094e338617a1a3c9f48a325e4b8e9b5a405aa91)) +- **VoiceChannel:** Nullify property (#7793) ([446eb39](https://github.com/discordjs/discord.js/commit/446eb390ce58b7e7f60e297b25f53773a55f7fb9)) +- **ModalSubmitInteraction:** Message (#7705) ([b577bcc](https://github.com/discordjs/discord.js/commit/b577bcc1df5c6424fef9984e19a5f11c77371cf3)) +- **Embed:** Add missing getters and add video to EmbedData (#7728) ([fd1dc72](https://github.com/discordjs/discord.js/commit/fd1dc72c0a77dbe18753d8db22972dfa5fe4ab36)) +- **ModalSubmitInteraction:** Fix `components` type (#7732) ([6f4e97b](https://github.com/discordjs/discord.js/commit/6f4e97bfafe4a058f6ec85d321676401d701ee55)) +- **interactionCollector:** Filter should have a collected argument (#7753) ([e4f2705](https://github.com/discordjs/discord.js/commit/e4f27051ca921d299c302b600a8c2917e9356ef6)) +- Fix regressions (#7649) ([5748dbe](https://github.com/discordjs/discord.js/commit/5748dbe08783beb80c526de38ccd105eb0e82664)) +- **Constants:** Add `NonSystemMessageTypes` (#7678) ([9afc030](https://github.com/discordjs/discord.js/commit/9afc03054e4c8973702d6c18e618643f76382dd9)) +- Fix auto archive duration type (#7688) ([8e3b2d7](https://github.com/discordjs/discord.js/commit/8e3b2d7abd38136534969cf77c6a748ee3a20355)) +- **InteractionResponseFields:** Add webhook (#7597) ([daf2829](https://github.com/discordjs/discord.js/commit/daf2829cb58d1a44cb1f1ece21e428d1a23e99c9)) +- **Embed:** Add forgotten `footer` type (#7665) ([8fb9816](https://github.com/discordjs/discord.js/commit/8fb98165a9d098ab316475d6baacb015783eb638)) +- **ColorResolvable:** Simplify string types (#7643) ([2297c2b](https://github.com/discordjs/discord.js/commit/2297c2b9479ace16f5f7155479605a4ac2718e3d)) +- Allow component classes in action row data (#7614) ([230c0c4](https://github.com/discordjs/discord.js/commit/230c0c4cb137882ff7bab783a4aeaa83ae941de5)) +- **ActionRow:** Allow components to be passed to constructors (#7531) ([e71c76c](https://github.com/discordjs/discord.js/commit/e71c76c7f795837dbcc3576e507bd286640b4296)) +- **showModal:** Align types with the documentation (#7600) ([0d7e4ed](https://github.com/discordjs/discord.js/commit/0d7e4edd969513692c061c107be4bbe7e4b54321)) +- Modals type and doc fixes (#7608) ([93854a8](https://github.com/discordjs/discord.js/commit/93854a8013d07234cb849bfcbfa99f74a4c3cdb4)) +- **InteractionResponseFields:** Add boolean properties (#7565) ([53defb8](https://github.com/discordjs/discord.js/commit/53defb82e36108468e35077b887ee28b811891ab)) +- Allow raw components for reply and message options (#7573) ([2d4971b](https://github.com/discordjs/discord.js/commit/2d4971b032a01c05b55c93d6475e61b0d25d69d3)) +- Fix component *Data types (#7536) ([a8321d8](https://github.com/discordjs/discord.js/commit/a8321d8026df2e6a09d867939986bf77f894f3a8)) +- Use discord-api-types `Locale` (#7541) ([8346003](https://github.com/discordjs/discord.js/commit/83460037be840ba623f3b02a3e6f218943f9d2b7)) +- **anychannel:** Add PartialGroupDMChannel (#7472) ([cf66930](https://github.com/discordjs/discord.js/commit/cf669301c7be8eaecf91d7f764eccc67d7a5b4c6)) +- Remove `ApplicationCommandInteractionOptionResolver` (#7491) ([71f4fa8](https://github.com/discordjs/discord.js/commit/71f4fa82ed6206d6843345a5394119f2a728aa35)) +- **embed:** Fix timestamp allowed types (#7470) ([7959a68](https://github.com/discordjs/discord.js/commit/7959a68d8ec600af248f5506f39871cae7eeeb04)) +- Remove duplicate rate limit for thread creation (#7465) ([2d2de1d](https://github.com/discordjs/discord.js/commit/2d2de1d3fd15a098d69e09710e9a7a3352234fef)) +- Correct types for InteractionCollector guild and channel (#7452) ([6ce906a](https://github.com/discordjs/discord.js/commit/6ce906a02fcb051cb6df3e9f453ba9f53db03bd0)) +- Fix `GuildAuditLogsTypes` keys & typos (#7423) ([3d8c776](https://github.com/discordjs/discord.js/commit/3d8c77600be51a86a99b526078bb1b1fcb9a0811)) +- Remove duplicate `GuildChannelOverwriteOptions` interface (#7428) ([83458ff](https://github.com/discordjs/discord.js/commit/83458ff7c782b8efdaaac931d2dee1764dad25bf)) +- Use `GuildFeature` enum from `discord-api-types` (#7397) ([a7b80b9](https://github.com/discordjs/discord.js/commit/a7b80b9d9bf4902bd85b592986771eadf7a765dc)) +- Fix *BitField.Flags properties (#7363) ([e6a26d2](https://github.com/discordjs/discord.js/commit/e6a26d25b3cf8dfcc8aa8997b021f1774f3b754b)) +- Fix MessageMentions channel types (#7316) ([c05b388](https://github.com/discordjs/discord.js/commit/c05b38873bb3c37c6e4ebcb6b6373a8858cc03de)) +- Fix channel create overloads (#7294) ([1c6c944](https://github.com/discordjs/discord.js/commit/1c6c9449ad68601c6c98748d73be8114401d38ef)) +- Fix regressions and inconsistencies (#7260) ([26a9dc3](https://github.com/discordjs/discord.js/commit/26a9dc32062cd071917bbe7264050315b4d6dd3c)) +- **interaction:** Remove renamed typeguards (#7220) ([68b9564](https://github.com/discordjs/discord.js/commit/68b9564f1821726377a1e929a3ca1fc65b4ad598)) +- AssertType -> expectType ([3f36746](https://github.com/discordjs/discord.js/commit/3f36746561a40cd61a7cd2e054b7ef80d58fc707)) +- Fix cache types resolving to `never` (#7164) ([c978dbb](https://github.com/discordjs/discord.js/commit/c978dbb6233bcd85408caf0bca7619c9c5d508f0)) + +# [14.12.1](https://github.com/discordjs/discord.js/compare/14.12.0...14.12.1) - (2023-08-01) + +## Bug Fixes + +- **BaseClient:** Fix destroy method (#9742) ([1af7e5a](https://github.com/discordjs/discord.js/commit/1af7e5a0bb4eca35221cb342c1c53dc18263c789)) + +# [14.12.0](https://github.com/discordjs/discord.js/compare/14.11.0...14.12.0) - (2023-07-31) + +## Bug Fixes + +- **ChannelUpdate:** Check against unknown channels (#9697) ([7fb91c5](https://github.com/discordjs/discord.js/commit/7fb91c57f72b74395d67f2207246033c703f1f19)) +- **Action:** Use existing recipients if available (#9653) ([719e54a](https://github.com/discordjs/discord.js/commit/719e54a921f74890519f066a9f56e52fdcfacf07)) +- Everyone role members (#9685) ([0803eb5](https://github.com/discordjs/discord.js/commit/0803eb562bdc7644fa611a0a87dea3e8b0d4c7af)) +- `awaitMessageComponent` with `MessageComponentInteraction`s (#8598) ([b61e4fb](https://github.com/discordjs/discord.js/commit/b61e4fb0dcb9e5d43a7626c5a4760f5801e06fae)) +- **ThreadManager:** Fix internal crash upon conditionally resolving thread members (#9648) ([a6dbe16](https://github.com/discordjs/discord.js/commit/a6dbe163dd3df12ad98465b1dfc040b8eff8805e)) +- **User:** Check global name in equals (#9631) ([8f3bd38](https://github.com/discordjs/discord.js/commit/8f3bd3807233fca2a057948406bdc8aef008b6cb)) +- **WebSocketManager:** Await WebSocket destroy (#9519) ([75308f2](https://github.com/discordjs/discord.js/commit/75308f266933454301b10ee8e1d940d782fdb637)) +- **Client:** Safe call for possibly null WebSocket (#9600) ([24a6149](https://github.com/discordjs/discord.js/commit/24a61495b9bf07887dd535a05ffbec2895faa888)) +- **ThreadManager:** Ensure `fetchActive()` only returns active threads in a channel (#9568) ([53aa24d](https://github.com/discordjs/discord.js/commit/53aa24d41809382c1af57bd1871107c8359e4a15)) +- **LimitedCollection:** Allow items to be stored if keepOverLimit is true when maxSize is 0 (#9534) ([9345d1b](https://github.com/discordjs/discord.js/commit/9345d1b1ac4f7b1f66b919602dff995782151407)) +- **AutocompleteInteraction:** Prevent snake casing of locales (#9565) ([7196fe3](https://github.com/discordjs/discord.js/commit/7196fe36e8089dde7bcaf0db4dd09cf524125e0c)) + +## Documentation + +- Change `Channel` to `BaseChannel` (#9718) ([e5effb6](https://github.com/discordjs/discord.js/commit/e5effb6f6a3e547006eb9bc054cc168844a157f2)) +- **BaseChannel:** Remove `APIChannel` (#9717) ([125405f](https://github.com/discordjs/discord.js/commit/125405f1cf11433c69ff1ae9d6b8f7e713fc37c0)) +- **BuildersSelectMenuOption:** Update link (#9690) ([ede9f4e](https://github.com/discordjs/discord.js/commit/ede9f4e5e203bcfb8820ae7ec3418482735ff9c1)) +- **ClientOptions:** Change default value of sweepers in docs (#9591) ([911e6ef](https://github.com/discordjs/discord.js/commit/911e6eff75f5d05e837d5dfaacf557d6594df16a)) +- **Client:** Correct invite gateway permission checks (#9597) ([e1b6eee](https://github.com/discordjs/discord.js/commit/e1b6eeed0e2e18f9900bc945c9f82d2d05f28a78)) +- Fix broken links to new documentation (#9563) ([d01e8aa](https://github.com/discordjs/discord.js/commit/d01e8aa8af00f5caacffe98caef3ead02e80a9bf)) + +## Features + +- Add ws option support for "buildIdentifyThrottler" (#9728) ([6307f81](https://github.com/discordjs/discord.js/commit/6307f813854ed9dc76d2c4351bd69dd0490d0928)) +- **Client:** Add `guildAvailable` event (#9692) ([3c85fb2](https://github.com/discordjs/discord.js/commit/3c85fb21e62b30e75a7200b704e242c3a0adeda1)) +- User avatar decorations (#8914) ([8d97017](https://github.com/discordjs/discord.js/commit/8d9701745840e23854e8f0b057d21cb10e7d1d54)) +- Add silent option to ShardingManager (#9506) ([df40dcd](https://github.com/discordjs/discord.js/commit/df40dcdb850c398642ebc5cd6e4c48034280f464)) +- **EmbedBuilder:** Add `.length` (#8682) ([53c17e0](https://github.com/discordjs/discord.js/commit/53c17e00c0668c3d1497142dde7384c058c46c64)) +- Guild onboarding (#9120) ([dc73c93](https://github.com/discordjs/discord.js/commit/dc73c938ff9d04a0d7d57630faeb8e81ea343006)) +- Add resume event in shard (#9650) ([a73d54e](https://github.com/discordjs/discord.js/commit/a73d54e43a01719f683e8fd21714e85ffe737add)) +- **presence:** Re-introduce image resolving for other platforms (#9637) ([73c2f8a](https://github.com/discordjs/discord.js/commit/73c2f8aa17aac51b05382444148cb1f60081ee03)) +- Add message to send resume event to shard (#9626) ([a873ec1](https://github.com/discordjs/discord.js/commit/a873ec1e8511829ba95e85bbc9a4074e40c76086)) +- Support new username system (#9512) ([1ab60f9](https://github.com/discordjs/discord.js/commit/1ab60f9da4d6b7ea144fa05b97b029a4bfaeede2)) +- **GuildAuditLogsEntry#extra:** Add missing `channel` property (#9518) ([2272321](https://github.com/discordjs/discord.js/commit/227232112d1cd9f211e177996b7cdee2940f471e)) + +## Performance + +- **Channel:** Linear speed position getter (#9497) ([09b0382](https://github.com/discordjs/discord.js/commit/09b0382c458ed0f3df5b8fa778c504b3e658ac49)) +- **Role:** Improve `members` getter (#9529) ([37181ab](https://github.com/discordjs/discord.js/commit/37181ab2322e48e17ff0d1040bcc510dc7c34e93)) + +## Refactor + +- **User:** Remove deprecation warning from tag (#9660) ([cf8012c](https://github.com/discordjs/discord.js/commit/cf8012c20022aff184d7bce0ad436c136e428d9c)) +- **GuildMember:** Make `_roles` property non-enumerable (#9387) ([46167a7](https://github.com/discordjs/discord.js/commit/46167a79d7d0cac5599459a31c33b2bbcf6e06da)) +- **rest:** Switch api to fetch-like and provide strategies (#9416) ([cdaa0a3](https://github.com/discordjs/discord.js/commit/cdaa0a36f586459f1e5ede868c4250c7da90455c)) + - **BREAKING CHANGE:** NodeJS v18+ is required when using node due to the use of global `fetch` + - **BREAKING CHANGE:** The raw method of REST now returns a web compatible `Respone` object. + - **BREAKING CHANGE:** The `parseResponse` utility method has been updated to operate on a web compatible `Response` object. + - **BREAKING CHANGE:** Many underlying internals have changed, some of which were exported. + - **BREAKING CHANGE:** `DefaultRestOptions` used to contain a default `agent`, which is now set to `null` instead. + +## Typings + +- **MessageManager:** Allow comparison of messages again (#9612) ([a48d0ef](https://github.com/discordjs/discord.js/commit/a48d0efb09613eac6bf3c1bd996f58f5fff7667c)) +- **AutoModerationActionExecution:** Add forum channels as a possible type in `channel()` (#9623) ([d64330a](https://github.com/discordjs/discord.js/commit/d64330a1570b3a2047ef959a6bce268372c70e99)) +- **ModalSubmitFields:** Components is an array (#9406) ([1cab79f](https://github.com/discordjs/discord.js/commit/1cab79f6fde6f367141c9f7ed91bcb70ed2e5c17)) +- Use `readonly` arrays and `const` type parameters in places (#9641) ([cd69868](https://github.com/discordjs/discord.js/commit/cd6986854f4c2d143d2cd9b81d096738480dfa63)) +- **BaseInteraction:** `appPermissions` not `null` in guilds (#9601) ([6c2242f](https://github.com/discordjs/discord.js/commit/6c2242f4f970b1c75c243f74ae64f30ecbf8ba0d)) + +# [14.11.0](https://github.com/discordjs/discord.js/compare/14.10.2...14.11.0) - (2023-05-06) + +## Bug Fixes + +- **WebSocketManager:** Properly emit shard error events (#9521) ([e627468](https://github.com/discordjs/discord.js/commit/e6274681fd10b0d75e1d3b448c94b50ec6810367)) +- **WebSocketManager:** Emit raw ws events again (#9502) ([c429763](https://github.com/discordjs/discord.js/commit/c429763be8e94f0f0cbc630e8bb1d415d46f1465)) + +## Documentation + +- **Client:** Update Sapphire's snowflake utility links (#9501) ([1b7981e](https://github.com/discordjs/discord.js/commit/1b7981e4696b8ae74ceffa876fc0a9be7d0b9f93)) + +## Features + +- **Guild:** Safety alerts channel and mention raid protection (#8959) ([6b2c3fb](https://github.com/discordjs/discord.js/commit/6b2c3fb9d0571de808e990cf064f73240ab93451)) + +## Performance + +- **Role:** Linear speed position getter (#9493) ([8e9a2b4](https://github.com/discordjs/discord.js/commit/8e9a2b4630f78bb9e45345ec2a16812bfac70a20)) + +## Refactor + +- **GuildChannel:** Simplify constructor (#9499) ([f2ad076](https://github.com/discordjs/discord.js/commit/f2ad0762c521422ab64e5b10344a6fd67961031b)) + +## Typings + +- **StringSelectMenuComponentData:** `options` is required (#9515) ([d7b18f0](https://github.com/discordjs/discord.js/commit/d7b18f0681d4147ff192c98108c035d6d0f96cce)) + +# [14.10.2](https://github.com/discordjs/discord.js/compare/14.10.1...14.10.2) - (2023-05-01) + +## Bug Fixes + +- Correct `isJSONEncodable()` import (#9495) ([201b002](https://github.com/discordjs/discord.js/commit/201b002ad405b845ace5f708077c1f157bb4126d)) +- **Client:** `generateInvite()` scope validation (#9492) ([b327f49](https://github.com/discordjs/discord.js/commit/b327f4925ff557e0aa8273d7f017aa616226ca06)) + +# [14.10.1](https://github.com/discordjs/discord.js/compare/14.10.0...14.10.1) - (2023-05-01) + +## Bug Fixes + +- **Client:** Spelling of InvalidScopesWithPermissions ([ac9bf3a](https://github.com/discordjs/discord.js/commit/ac9bf3ac06ec78dbaca2ce4a82cceb0d82484211)) + +## Refactor + +- **ShardClientUtil:** Logic de-duplication (#9491) ([a9f2bff](https://github.com/discordjs/discord.js/commit/a9f2bff82a18c6a3afdee99e5830e1d7b4da65dc)) + +# [14.10.0](https://github.com/discordjs/discord.js/compare/14.9.0...14.10.0) - (2023-05-01) + +## Bug Fixes + +- **ShardClientUtil:** Fix client event names (#9474) ([ad217cc](https://github.com/discordjs/discord.js/commit/ad217cc7604dda6a33df73db82799fd5bb4e85a9)) +- **BaseClient:** Prevent user agent mutation (#9425) ([217e5d8](https://github.com/discordjs/discord.js/commit/217e5d81005a2506c96335f7fb96fa21d7dbb04c)) +- **BitField:** Use only enum names in iterating (#9357) ([40d07fb](https://github.com/discordjs/discord.js/commit/40d07fbbbd51d62793d9ea541f41f157b5dad224)) +- Use new permission name (#9274) ([d2d27ce](https://github.com/discordjs/discord.js/commit/d2d27ce7346bc37b34938c84bd3b106a4fa51f53)) +- **Message#editable:** Fix permissions check in locked threads (#9319) ([d4c1fec](https://github.com/discordjs/discord.js/commit/d4c1fecbe264bc52a70aaf0ec303d35e2f15bbcd)) +- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2)) + +## Documentation + +- **AutoModerationRule:** Update docs (#9464) ([1b15d31](https://github.com/discordjs/discord.js/commit/1b15d31b5ae1b1739716fab00b18083c1d7d389a)) +- **APITypes:** Document role & user select menu components (#9435) ([c6ca5a8](https://github.com/discordjs/discord.js/commit/c6ca5a83e7b72613f95c2145606a1330f64ae894)) +- **BaseMessageOptions:** Fix embeds and components (#9437) ([5c52bb9](https://github.com/discordjs/discord.js/commit/5c52bb95906250518a8813820d543f43dd7abdf9)) +- **InteractionResponses:** ShowModal docs change (#9434) ([7d34100](https://github.com/discordjs/discord.js/commit/7d341000d44b762a2fe0434a6b518f7d63539d34)) +- Use ESM code in examples (#9427) ([ce287f2](https://github.com/discordjs/discord.js/commit/ce287f21d1540da7f17cac8a57dc33a67f391ef3)) +- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9)) +- **Options:** Fix links and invalid syntax (#9322) ([86e5f5a](https://github.com/discordjs/discord.js/commit/86e5f5a119c6d2588b988a33236d358ded357847)) +- Cleanup MessageCreateOptions and MessageReplyOptions (#9283) ([300059c](https://github.com/discordjs/discord.js/commit/300059cb266e6cca42c30ee7f997c48ab2cc565e)) +- **Events:** Document auto moderation events (#9342) ([79bcdfa](https://github.com/discordjs/discord.js/commit/79bcdfa767e7e842164e1174b6f4834ed731d329)) +- Add `SnowflakeUtil` (#9371) ([8ffcf77](https://github.com/discordjs/discord.js/commit/8ffcf77840b62590fcb4731380d28b22d0b98741)) +- Use stable tag (#9343) ([c0f2dd7](https://github.com/discordjs/discord.js/commit/c0f2dd713151a29c98e1eebad66721a208be1fc0)) +- Remove `JSONEncondable` (#9344) ([b2eec5f](https://github.com/discordjs/discord.js/commit/b2eec5f9fcf37ebb3b7f87a67a6ee3160c182183)) + +## Features + +- **Attachment:** Voice messages (#9392) ([3e01f91](https://github.com/discordjs/discord.js/commit/3e01f91bbba2cbacacc6c921ed664752f679960b)) +- **BaseInteraction:** Support new channel payload (#9337) ([29389e3](https://github.com/discordjs/discord.js/commit/29389e39f479b832e54c7cb3ddd363aebe99674f)) +- **RoleTagData:** Add guildConnections (#9366) ([2dddbe1](https://github.com/discordjs/discord.js/commit/2dddbe1f321f2e2722dba4a28f7d18384cf50353)) + +## Performance + +- **RoleManager:** Dont call Role#position getter twice per role (#9352) ([bfee6c8](https://github.com/discordjs/discord.js/commit/bfee6c8d889502ea39ad919dd9b1e6253a2af571)) + +## Refactor + +- **WebSocketManager:** Use /ws package internally (#9099) ([a9e0de4](https://github.com/discordjs/discord.js/commit/a9e0de4288ea39a6a089b8379dcd44ac0053dac7)) +- Remove `fromInteraction` in internal channel creation (#9335) ([794abe8](https://github.com/discordjs/discord.js/commit/794abe8450bae000cd0544922cdf53e7b3e4c59c)) + +## Typings + +- **AutoModerationActionMetadataOptions:** Make channel property optional (#9460) ([d26df5f](https://github.com/discordjs/discord.js/commit/d26df5fabaf227fb9d10ba5cc1ab326de55aadbc)) +- **CategoryChannel:** Ensure `parent` and `parentId` are `null` (#9327) ([8218ffc](https://github.com/discordjs/discord.js/commit/8218ffc78d23234b32c05a97fde2f4bea64d7aa6)) +- **GuildTextBasedChannel:** Remove unnecessary exclusion of forum channels (#9326) ([7ff3d52](https://github.com/discordjs/discord.js/commit/7ff3d528d942a0daa990194915ff8328dec99149)) + +# [14.9.0](https://github.com/discordjs/discord.js/compare/14.8.0...14.9.0) - (2023-04-01) + +## Bug Fixes + +- Add support for new guild feature `GUILD_WEB_PAGE_VANITY_URL` (#9219) ([de1aac6](https://github.com/discordjs/discord.js/commit/de1aac674acb3830124646fcd52cdd98cdb71ba5)) +- Resolving string bitfield (#9262) ([7987565](https://github.com/discordjs/discord.js/commit/79875658cf4a8daa25210c2c620c73a710ca22de)) +- **AutocompleteInteraction:** Send `name_localizations` correctly (#9238) ([1864d37](https://github.com/discordjs/discord.js/commit/1864d37d36e53d127e74b6969a5f542193bfc3c7)) +- Keep symbols in actions manager (#9293) ([984bd55](https://github.com/discordjs/discord.js/commit/984bd55b437507e7ebfdf09ac944c8eba0340d27)) +- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b)) +- **ClientUser:** No mutation on edit (#9259) ([abd6ae9](https://github.com/discordjs/discord.js/commit/abd6ae9fc8ea03722e8b36e29c3fdc1c2cfc93e8)) +- **Message#editable:** Update editable check in threads locked (#9216) ([22e880a](https://github.com/discordjs/discord.js/commit/22e880aaa0d8c644fc8d16a524d17f4f53a056f6)) +- **ThreadManager:** Add `members` and conditionally include `hasMore` (#9164) ([e9a8eb3](https://github.com/discordjs/discord.js/commit/e9a8eb323f3a554dc8f9dab361cd1bac7b88e1cc)) +- **ThreadManager:** Respect `cache` and `force` in fetching (#9239) ([cc57563](https://github.com/discordjs/discord.js/commit/cc57563e73d78a0d71d1444d1ee8215a26a81fa8)) +- **TextBasedChannelTypes:** Add `GuildStageVoice` (#9232) ([51edba7](https://github.com/discordjs/discord.js/commit/51edba78bc4d4cb44b4dd2b79e4bbc515dc46f5b)) + +## Documentation + +- Describe private properties (#8879) ([2792e48](https://github.com/discordjs/discord.js/commit/2792e48119f1cf5fa7d5e6b63369457b0719d4e4)) +- Differ `User#send` (#9251) ([384b4d1](https://github.com/discordjs/discord.js/commit/384b4d10e8642f0f280ea1651f33cd378c341333)) +- Fix compare position example (#9272) ([d16114c](https://github.com/discordjs/discord.js/commit/d16114c52646ca92c53f9b44a0dd10af98dbddcd)) +- **Role:** Fix example for `comparePositionTo()` (#9270) ([bc641fa](https://github.com/discordjs/discord.js/commit/bc641fa9360b851642bc51839cef6bd5600d71f7)) +- Add more examples (#9252) ([bf507ab](https://github.com/discordjs/discord.js/commit/bf507ab2659d95e2991e83293b3834f21283ff33)) +- **FetchArchivedThreadOptions:** `before` respects `archive_timestamp`, not creation timestamp (#9240) ([178c8dc](https://github.com/discordjs/discord.js/commit/178c8dcfeea1c4a6a32835baea389f25feefbac7)) +- Update `APISelectMenuComponent` (#9235) ([56cf138](https://github.com/discordjs/discord.js/commit/56cf138e029e7884a4e7efb606055687ca67b4ac)) + +## Features + +- **Guild:** Add `max_stage_video_channel_users` (#8422) ([34bc36a](https://github.com/discordjs/discord.js/commit/34bc36ac4b04ad033d0dcc3d2701fcf2e682743c)) +- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b)) +- Add GuildBasedTextChannelTypes (#9234) ([5f93dcc](https://github.com/discordjs/discord.js/commit/5f93dcce466286f0fdead8faf4131e98d1c9db55)) + +## Refactor + +- Call `GuildBanManager#create()` directly (#9263) ([f340f3b](https://github.com/discordjs/discord.js/commit/f340f3b1fd719e8f7cf6fa28a41835bc16039fc7)) +- **FetchThreadsOptions:** Remove `active` (#9241) ([519e163](https://github.com/discordjs/discord.js/commit/519e163f8aa3b55420f86d2d60c2584b3a2eb327)) + +# [14.8.0](https://github.com/discordjs/discord.js/compare/14.7.1...14.8.0) - (2023-03-12) + +## Bug Fixes + +- **snowflake:** Snowflakes length (#9144) ([955e8fe](https://github.com/discordjs/discord.js/commit/955e8fe312c42ad4937cc1994d1d81e517c413c8)) +- **Actions:** Inject built data by using a symbol (#9203) ([a63ac88](https://github.com/discordjs/discord.js/commit/a63ac88fcca5b61209892a6e560e35d58f5adc3b)) +- **Message#deletable:** Add check for deletable message types (#9168) ([e78b8ad](https://github.com/discordjs/discord.js/commit/e78b8ad3fb6692cba2c565b508254c723f185f0c)) +- **Message:** `bulkDeletable` permissions should be retrieved later for DMs (#9146) ([a9495bd](https://github.com/discordjs/discord.js/commit/a9495bd8f014c8021a214b83ffc531a2af5defef)) +- **AutoModerationActionExecution:** Transform `action` (#9111) ([9156a28](https://github.com/discordjs/discord.js/commit/9156a2889cd0946dfd0b30a5f8365abfbc377b3d)) +- **MessageReaction:** `toJSON()` infinite recursion (#9070) ([f268e1d](https://github.com/discordjs/discord.js/commit/f268e1d9798744e169ae87089ea2e1f214364d95)) +- **ThreadChannel:** Insert starter message from threads created in forum channels (#9100) ([0b76ab4](https://github.com/discordjs/discord.js/commit/0b76ab4c403dd646c71482856ab993b263b7c474)) +- **ApplicationRoleConnectionMetadata:** Export the class correctly (#9076) ([071516c](https://github.com/discordjs/discord.js/commit/071516c35239bd4e1cae572c855d86b335c8536d)) +- Don't auth for interaction `showModal()` (#9046) ([b803a9a](https://github.com/discordjs/discord.js/commit/b803a9a899aaa75a3ea2bc6623c6afb28f495e8c)) +- **WebSocketShard:** Zombie connection fix (#8989) ([876b181](https://github.com/discordjs/discord.js/commit/876b1813128ec702d3ef1e7b0074a4613e88c332)) +- Keep other properties in triggerMetadata (#8977) ([d8dd197](https://github.com/discordjs/discord.js/commit/d8dd197a936dfffc05f9e5bc3184ec9022c56b51)) +- **escapeX:** Emojis with underlines (#8945) ([07b597d](https://github.com/discordjs/discord.js/commit/07b597df16b9412c23ec2387d54564e4d1bcf7ed)) +- **WebSocketShard:** Either start close timeout or emit destroyed but never both (#8956) ([43ce2a5](https://github.com/discordjs/discord.js/commit/43ce2a572eb8977b6994680171ac0c5f9bda1703)) +- **DMChannel:** `recipientId` edge case (#8950) ([7ce9909](https://github.com/discordjs/discord.js/commit/7ce990954e2f73d7a996df0afa42ab287cb12514)) +- Return only boolean for `disabled` (#8965) ([6614603](https://github.com/discordjs/discord.js/commit/66146033268a4db1279b2eaee4bd418f326c0d4b)) +- Export missing `escapeX()` functions (#8944) ([25c27ea](https://github.com/discordjs/discord.js/commit/25c27eac1417e75c9b601b17cf177b1f47b699a9)) +- **WebSocketShard:** Only cleanup the connection if a connection still exists (#8946) ([5eab5fc](https://github.com/discordjs/discord.js/commit/5eab5fc06ca6be36ecf1557f2ad29a670d4d5ae7)) +- Add `@discordjs/formatters` to dependency list (#8939) ([18b3a19](https://github.com/discordjs/discord.js/commit/18b3a19810a6436fa8bb4b490ec5137eaecbd465)) +- **resolveColor:** Invalid colors (#8933) ([c76e170](https://github.com/discordjs/discord.js/commit/c76e17078602914c3e1d227a3acc98eaa99c18d4)) +- **WebSocketShard:** Clear listeners on reconnect (#8927) ([aa8c57d](https://github.com/discordjs/discord.js/commit/aa8c57dab60104549e28451abf35c0387595d67e)) +- Re-export formatters (#8909) ([b14604a](https://github.com/discordjs/discord.js/commit/b14604abdecca575b1fca693c1593e3585bcca8c)) + +## Documentation + +- **MessageManager:** Add clarification to fetch messages (#9222) ([f5ec1ca](https://github.com/discordjs/discord.js/commit/f5ec1cada5ebf0ca4093bdfc81aaf56900c794ef)) +- Make interactionResponse as optional (#9179) ([664cccb](https://github.com/discordjs/discord.js/commit/664cccb2706db33635aa2556954de57f93b3d3db)) +- Fix typos (#9127) ([1ba1f23](https://github.com/discordjs/discord.js/commit/1ba1f238f04221ec890fc921678909b5b7d92c26)) +- **chatInputApplicationCommandMention:** Parameters are not nullable (#9091) ([6f78e82](https://github.com/discordjs/discord.js/commit/6f78e8285b3ce762de010e68d49b377a47dc5a63)) +- No `@type` description and reveal info block (#9097) ([405f940](https://github.com/discordjs/discord.js/commit/405f9400e8e3ffea9f3847ab5abb431a34538a96)) +- **ThreadEditOptions:** Move info tag back to `invitable` (#9020) ([f3fe3ce](https://github.com/discordjs/discord.js/commit/f3fe3ced622676b406a62b43f085aedde7a621aa)) +- Fix a typo in the MentionableSelectMenuInteraction link (#9000) ([6d7a143](https://github.com/discordjs/discord.js/commit/6d7a143667f33ef2ea45d8016ac4738237707881)) +- **ApplicationRoleConnectionMetadata:** Add documentation (#8976) ([2e22b31](https://github.com/discordjs/discord.js/commit/2e22b31892d9b858fcb24fa580b486b4154e823f)) +- Fix malformed overridden documentation (#8954) ([0b8b114](https://github.com/discordjs/discord.js/commit/0b8b114761f961a2bf8e5aae342ed711b154a89e)) +- **GuildForumThreadManager:** Fix `sticker` type (#8940) ([dd62be0](https://github.com/discordjs/discord.js/commit/dd62be077d3e4fbd73a0c10ca344d93d3d19fa38)) +- Fix deprecated links (#8907) ([976b234](https://github.com/discordjs/discord.js/commit/976b234e9dc9999e5dee47b58c85afbc1cd494c2)) +- **UserFlagsBitField:** Make `.Flags` static (#8902) ([c48ff5e](https://github.com/discordjs/discord.js/commit/c48ff5e4205899e3b6cd35812ca857236bef6864)) + +## Features + +- **Collector:** Add lastCollectedTimestamp (#9044) ([4458a13](https://github.com/discordjs/discord.js/commit/4458a13925164762b519ded1037ae8775d879f71)) +- **StageChannel:** Add messages (#9134) ([ffdb197](https://github.com/discordjs/discord.js/commit/ffdb197f988657100e2a9ff0ca17b759339a1dda)) +- **AutoModerationActionExecution:** Add `channel`, `user` and `member` getters (#9142) ([095bd77](https://github.com/discordjs/discord.js/commit/095bd77515aa31bb0e95a350b4355980fea9268d)) +- **AutoModeration:** Support `custom_message` (#9171) ([c1000b8](https://github.com/discordjs/discord.js/commit/c1000b86ed6d5413afcd6ee7e80505e5a845430b)) +- **ThreadMemberManager:** Support pagination fetching (#9035) ([765d5a3](https://github.com/discordjs/discord.js/commit/765d5a3b2d5529c3a2a4b29512f6932264443ed1)) +- **InteractionResponse:** Add new methods (#9132) ([dc9924f](https://github.com/discordjs/discord.js/commit/dc9924fb5f24c8dac963d6b86ba279a89545e73b)) +- **GuildMember:** Add `flags` (#9087) ([76b2116](https://github.com/discordjs/discord.js/commit/76b21162aca7cd4897826437da3063524e1e7553)) +- **Client:** `guildAuditLogEntryCreate` event (#9058) ([9439107](https://github.com/discordjs/discord.js/commit/9439107a1d6a9b77b5f991973d96bc6100da4753)) +- Add role subscription data (#9025) ([1ba22f4](https://github.com/discordjs/discord.js/commit/1ba22f4c9e4173f8866339d3eadb2939d4b32034)) +- **Sticker:** Add support for gif stickers (#9038) ([6a9875d](https://github.com/discordjs/discord.js/commit/6a9875da054a875a4711394547d47439bbe66fb6)) +- **GuildAuditLogs:** Support `after` (#9011) ([0076589](https://github.com/discordjs/discord.js/commit/0076589ccc93e09d77a448874d1ceff5d0e91aa2)) +- Add role subscriptions (#8915) ([3407e1e](https://github.com/discordjs/discord.js/commit/3407e1eea3c8d5629465553f342ac30ceae27a47)) +- Add `not_found` to guild member chunk data (#8975) ([be294ea](https://github.com/discordjs/discord.js/commit/be294eaf9901ea139ce485deeec9178959ffa91f)) +- **ClientApplication:** Add role connections (#8855) ([22e2bbb](https://github.com/discordjs/discord.js/commit/22e2bbb0d24e3f30516f262308d5786f2f666713)) +- **CommandInteractionOptionResolver:** Add `channelTypes` option to `getChannel` (#8934) ([429dbcc](https://github.com/discordjs/discord.js/commit/429dbccc85cabd9986b2e8bf443bf384e4ddc61a)) +- **ForumChannel:** Add `defaultForumLayout` (#8895) ([cbafd47](https://github.com/discordjs/discord.js/commit/cbafd479b331633ed97f7b1a22ef03c6a2f4cf31)) +- Add support for nsfw commands (#7976) ([7a51344](https://github.com/discordjs/discord.js/commit/7a5134459c5f06864bf74631d83b96d9c21b72d8)) +- **InteractionResponse:** CreatedTimestamp (#8917) ([627511d](https://github.com/discordjs/discord.js/commit/627511d6522f772b84c25e6a3f6da06b06bb912e)) +- **Guild:** Add disableInvites method (#8801) ([45faa19](https://github.com/discordjs/discord.js/commit/45faa199820e7c4ccdb2997c7e3b353f566d2312)) + +## Refactor + +- Compare with `undefined` directly (#9191) ([869153c](https://github.com/discordjs/discord.js/commit/869153c3fdf155783e7c0ecebd3627b087c3a026)) +- **GuildMemberManager:** Tidy up fetching guild members (#8972) ([4e0e125](https://github.com/discordjs/discord.js/commit/4e0e1250399aa12c340ac92a86ec2c05704fe2bb)) +- **BitField:** Reverse iterator/toArray responsibilities (#9118) ([f70df91](https://github.com/discordjs/discord.js/commit/f70df910ed12e397066d0bdb27343af21ead4d92)) +- Moved the escapeX functions from discord.js to @discord.js/formatters (#8957) ([13ce78a](https://github.com/discordjs/discord.js/commit/13ce78af6e3aedc793f53a099a6a615df44311f7)) +- Use `deprecate()` directly (#9026) ([1c871b5](https://github.com/discordjs/discord.js/commit/1c871b5b576dddef12c5afacecf416dbd6243dea)) +- **Guild:** Destructure object in guild editing (#8971) ([d3e9f2a](https://github.com/discordjs/discord.js/commit/d3e9f2a355a1f5272d62a507eb6ecd8808904fff)) +- **GuildManager:** Better handling of creation code (#8974) ([d7a09f6](https://github.com/discordjs/discord.js/commit/d7a09f6fcee30c31b4418166bf7bf9e894841f87)) +- **sharding:** Use switch statement (#8928) ([6540914](https://github.com/discordjs/discord.js/commit/6540914b4a7f244f5e40fe2a3b7e73986763d81b)) +- Use consistent naming for options (#8901) ([a7b55c1](https://github.com/discordjs/discord.js/commit/a7b55c1460cf63fb482f7d05657120eec96bee82)) +- **CommandInteractionOptionResolver:** Loosen mentionable checks (#8910) ([1b151db](https://github.com/discordjs/discord.js/commit/1b151db59c4340417f8a28a88064f45336ac8c78)) + +## Styling + +- Run prettier (#9041) ([2798ba1](https://github.com/discordjs/discord.js/commit/2798ba1eb3d734f0cf2eeccd2e16cfba6804873b)) + +## Typings + +- Allow sending messages with `SuppressNotifications` flag (#9177) ([71a427f](https://github.com/discordjs/discord.js/commit/71a427f6322be76fe2d1cb265de09f171b1b354a)) +- Remove `EscapeMarkdownOptions` (#9153) ([fd0246c](https://github.com/discordjs/discord.js/commit/fd0246ca4c75e60d8e117d9ac5af7067c7a63277)) +- **Attachment:** Make `attachment` private (#8982) ([da23cd5](https://github.com/discordjs/discord.js/commit/da23cd5d69de4856d075f00738f75c68c555ae5b)) +- Fix type of Attachment#name (#9101) ([4e0a89f](https://github.com/discordjs/discord.js/commit/4e0a89f58f43f362bfde80d8319dce767c62850f)) +- Allow builders to set channel types in discord.js (#8990) ([7dec892](https://github.com/discordjs/discord.js/commit/7dec892218f7b470a5f8e78732a524a53da24d26)) +- Swap message reaction and emoji identifier types (#8969) ([ad49845](https://github.com/discordjs/discord.js/commit/ad4984526020f2baeefaeeebbded66c6848c4b85)) +- **widget:** Add missing `name` (#8978) ([898b5ac](https://github.com/discordjs/discord.js/commit/898b5ac416cbbb415b125bb27221d0901fdd180e)) +- Use StringSelectMenuOptionBuilder (#8949) ([bec51de](https://github.com/discordjs/discord.js/commit/bec51de1038c35c6edaaa13934781758fe1951de)) +- Fix actions type in automod (#8962) ([5915f39](https://github.com/discordjs/discord.js/commit/5915f39810b712c05a46fa21ab4e12b4cfa3c25a)) +- Subcommand group `options` is required (#8966) ([5dc5e90](https://github.com/discordjs/discord.js/commit/5dc5e902688fc563087cd5061dcb59dd68fd4eda)) +- Add generic to `ActionRowBuilder.from()` (#8414) ([153352a](https://github.com/discordjs/discord.js/commit/153352ad7a1ccb4a9461523cf2597d81df93b69c)) + +# [14.7.1](https://github.com/discordjs/discord.js/compare/14.7.0...14.7.1) - (2022-12-01) + +## Bug Fixes + +- Prevent crash on no select menu option (#8881) ([11d195d](https://github.com/discordjs/discord.js/commit/11d195d04ff57d51adb0f0d3a0a7342f9e34aba0)) + +# [14.7.0](https://github.com/discordjs/discord.js/compare/14.6.0...14.7.0) - (2022-11-28) + +## Bug Fixes + +- **MessageMentions:** Add `InGuild` generic (#8828) ([f982803](https://github.com/discordjs/discord.js/commit/f9828034cd21e6f702762a46923e0f42115596f6)) +- **Activity:** Fix equals() not checking for differing emoji (#8841) ([7e06f68](https://github.com/discordjs/discord.js/commit/7e06f68185423ba7cb310220b213f445b6571e29)) +- Fixed react/astro/guide/discord.js build, updated dependencies, fix crawlvatar (#8861) ([d0c8256](https://github.com/discordjs/discord.js/commit/d0c82561b8a1765a1daa362ca903f3ffb3fa33ee)) +- **escapeMarkdown:** Fix double escaping (#8798) ([d6873b7](https://github.com/discordjs/discord.js/commit/d6873b7159352479475b3a0daa215bddbdd3a79b)) +- **Transfomers:** Call `.toJSON` in `toSnakeCase` (#8790) ([017f9b1](https://github.com/discordjs/discord.js/commit/017f9b1ed4014dc1db0b78c1a77e463b4403de5d)) +- Censor token in debug output (#8764) ([53d8e87](https://github.com/discordjs/discord.js/commit/53d8e87d7f3a329608250656950bd0a200adb1c7)) +- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4)) + +## Documentation + +- Describe InteractionEditReplyOptions (#8840) ([cb77fd0](https://github.com/discordjs/discord.js/commit/cb77fd02d083438de2aff6f0769baf7d1797bc65)) +- **AutoModerationRuleManager:** Describe cache (#8848) ([d275480](https://github.com/discordjs/discord.js/commit/d2754802cc3479e6288cdbfcd48c76bf57e09a07)) +- Fix message action row components (#8819) ([65bc0ad](https://github.com/discordjs/discord.js/commit/65bc0adbf4d7870d33b92585ca18f964f24bc84e)) +- Specify `ActionRowBuilder` for `components` (#8834) ([8ed5c1b](https://github.com/discordjs/discord.js/commit/8ed5c1beb622f71ce0bd89e4cbeff50e464da8fe)) +- Add `@extends` for select menu classes (#8824) ([09f65b7](https://github.com/discordjs/discord.js/commit/09f65b724b0d2f36bbe89b83570c0d18093b5126)) +- Make WebSocketShard.lastPingTimestamp public (#8768) ([68c9cb3](https://github.com/discordjs/discord.js/commit/68c9cb37bc3df6326b720291827ea477e421faf2)) +- **MessageReplyOptions:** Remove duplicate stickers field (#8766) ([6e348ff](https://github.com/discordjs/discord.js/commit/6e348ffd1d8db8d8ad2da7823460814695e01a43)) + +## Features + +- **Webhook:** Add `channel` property (#8812) ([decbce4](https://github.com/discordjs/discord.js/commit/decbce401062af75f633e6acacc88207b115a719)) +- Auto Moderation (#7938) ([fd4ba5e](https://github.com/discordjs/discord.js/commit/fd4ba5eaba66898699127fc0d5f0ab52c18e3db0)) +- **SelectMenuInteractions:** Add `values` property (#8805) ([b2fabd1](https://github.com/discordjs/discord.js/commit/b2fabd130a76ea54cfbfa1b871ef8659513c2c7a)) +- **ThreadChannel:** Add a helper for pin and unpin (#8786) ([e74aa7f](https://github.com/discordjs/discord.js/commit/e74aa7f6b0fe04e3473fc4a62a73a7db87307685)) +- Add `Message#bulkDeletable` (#8760) ([ff85481](https://github.com/discordjs/discord.js/commit/ff85481d3e7cd6f7c5e38edbe43b27b104e82fba)) +- New select menus (#8793) ([5152abf](https://github.com/discordjs/discord.js/commit/5152abf7285581abf7689e9050fdc56c4abb1e2b)) +- **InteractionResponses:** Add message parameter (#8773) ([8b400ca](https://github.com/discordjs/discord.js/commit/8b400ca975c6bad00060b9c67068f42bd53524ba)) +- Support resume urls (#8784) ([88cd9d9](https://github.com/discordjs/discord.js/commit/88cd9d906074eb79e85df0ef49287f11133d2e0d)) +- Allow deletion of ephemeral messages (#8774) ([fc10774](https://github.com/discordjs/discord.js/commit/fc107744618857bf28c2167f204253baf690ede8)) +- **GuildChannelManager:** Add `.addFollower()` method (#8567) ([caeb1cb](https://github.com/discordjs/discord.js/commit/caeb1cbfdb2f2f007252c4d7e9f47a575c24bcb5)) + +## Refactor + +- **Embed:** Use `embedLength` function from builders (#8735) ([cb3826c](https://github.com/discordjs/discord.js/commit/cb3826ce6dbcd3cf7ab639af6cdfcea80336aa1d)) + +# [14.6.0](https://github.com/discordjs/discord.js/compare/14.5.0...14.6.0) - (2022-10-10) + +## Bug Fixes + +- **ClientOptions:** Make `ClientOptions#intents` returns an IntentsBitField (#8617) ([4c2955a](https://github.com/discordjs/discord.js/commit/4c2955a5de6779c29c09e63ba9ad2b235904f842)) +- Correctly construct a builder (#8727) ([e548e6a](https://github.com/discordjs/discord.js/commit/e548e6a10b7e1720f5e8f3c859b0b64d5134a012)) +- **Components:** Error with unknown components (#8724) ([6fd331d](https://github.com/discordjs/discord.js/commit/6fd331dd528e78fd023c908bd58af3faa9ed6c65)) +- **Client:** Don't auth for webhook fetches with token (#8709) ([01d75c8](https://github.com/discordjs/discord.js/commit/01d75c8b8b14f33c95a4da83a8494db848beeb8c)) +- Re-export util (#8699) ([a306219](https://github.com/discordjs/discord.js/commit/a306219673335584accd2ff77ab34d2812ef6c5d)) +- Throw discord.js errors correctly (#8697) ([ace974f](https://github.com/discordjs/discord.js/commit/ace974fc1fdbc5bcaa0d7f6f6d17de185c9f9cbf)) + +## Documentation + +- **Utils:** Remove `private` from `parseEmoji` (#8718) ([a31e605](https://github.com/discordjs/discord.js/commit/a31e605e09064a300e31a3c91466b613654ba98e)) +- Update UserContextMenuCommandInteraction documentation (#8717) ([7556db2](https://github.com/discordjs/discord.js/commit/7556db243d9480949835668fcb5724fdd5d70e08)) +- Fix `AwaitMessageComponentOptions` typedef (#8696) ([9effd82](https://github.com/discordjs/discord.js/commit/9effd82abe82ba71ae627673da21ba07e1ede23e)) + +## Features + +- **Util:** Escape more markdown characters (#8701) ([7b8966b](https://github.com/discordjs/discord.js/commit/7b8966bca156db79933403289741893a6e10ccd5)) +- **GuildChannelManager:** Allow creating channels with a default auto archive duration (#8693) ([628759b](https://github.com/discordjs/discord.js/commit/628759bcff8b0d4c77926cee2b8c18d8fdb4c260)) +- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3)) +- **ForumChannel:** Add `defaultSortOrder` (#8633) ([883f6e9](https://github.com/discordjs/discord.js/commit/883f6e9202a559c986f4b15fccb422b5aea7bea8)) + +## Refactor + +- Rename Error to DiscordjsError internally (#8706) ([aec44a0](https://github.com/discordjs/discord.js/commit/aec44a0c93f620b22242f35e626d817e831fc8cb)) + +## Typings + +- Fix events augmentation (#8681) ([ac83ada](https://github.com/discordjs/discord.js/commit/ac83ada306ec153c13260d2bd53e4d704884b68a)) +- **Message:** Remove `& this` from `#inGuild` typeguard (#8704) ([c0f7a1a](https://github.com/discordjs/discord.js/commit/c0f7a1a89a4cf62edc7065bd200b2ce4018e0a27)) +- **ModalBuilder:** Fix constructor typings (#8690) ([2ea2a85](https://github.com/discordjs/discord.js/commit/2ea2a85e6335d57f44689f9b6e284129104de8fc)) + +# [14.5.0](https://github.com/discordjs/discord.js/compare/14.4.0...14.5.0) - (2022-09-25) + +## Bug Fixes + +- **ThreadChannel:** Add forum channel to parent (#8664) ([0126d9b](https://github.com/discordjs/discord.js/commit/0126d9b810a156c4bf1b8b93f2121f3319855bac)) +- **GuildChannelManager:** Allow creating webhooks on forums (#8661) ([16fcdc3](https://github.com/discordjs/discord.js/commit/16fcdc36877d1a65ce9995c9fe3502aa268c9388)) +- **ForumChannel:** Implement missing properties and methods (#8662) ([8622939](https://github.com/discordjs/discord.js/commit/862293922924f453f69b0b0f8efe87ddebbd387d)) +- RepliableInteraction respect cached generic (#8667) ([578bc95](https://github.com/discordjs/discord.js/commit/578bc951bdcdc21ec5aee86e7a47a17e8c867dfc)) +- **ThreadChannel:** Allow editing flags (#8671) ([1244854](https://github.com/discordjs/discord.js/commit/1244854e1365d7e4a8d01703a7ec13610ed100c7)) +- **GuildChannelManager:** Typo in `flags` property name when editing (#8669) ([fc8ed81](https://github.com/discordjs/discord.js/commit/fc8ed816e643754a938211a17b41a2cec95df265)) + +## Documentation + +- Fix duplicate typedefs (#8677) ([d79aa2d](https://github.com/discordjs/discord.js/commit/d79aa2d0d0b186bd28cbfc82f3d6ecf3deb41c50)) +- **ForumChannel:** Add `@implements` (#8678) ([8ca407e](https://github.com/discordjs/discord.js/commit/8ca407e089c3050b61a51a52b9100e4613ad1666)) + +## Features + +- **GuildChannelManager:** Allow editing `flags` (#8637) ([abb7226](https://github.com/discordjs/discord.js/commit/abb7226af3445f5b724815bb2f7a121a52a563b5)) + +## Refactor + +- **GuildBanManager:** Add deprecation warning for `deleteMessageDays` (#8659) ([e993122](https://github.com/discordjs/discord.js/commit/e9931229ae62a120ae0761ee2a2c10ea0cb1a6fb)) + +## Typings + +- **GuildChannelManager:** Handle forum channel overload (#8660) ([1486bc9](https://github.com/discordjs/discord.js/commit/1486bc9336369d229972df5e28b9428365b92bff)) +- **Caches:** Allow `GuildForumThreadManager` and `GuildTextThreadManager` (#8665) ([2487e3b](https://github.com/discordjs/discord.js/commit/2487e3bf76260a4a2fbf375e0b01a43f347922a3)) + +# [14.4.0](https://github.com/discordjs/discord.js/compare/14.3.0...14.4.0) - (2022-09-21) + +## Bug Fixes + +- Correct applied tags type (#8641) ([f6f15d8](https://github.com/discordjs/discord.js/commit/f6f15d8e877d4ffbe908a093e64809ef9015e0ff)) +- **ThreadChannel:** Make `fetchStarterMessage()` work in forum posts (#8638) ([a7f816e](https://github.com/discordjs/discord.js/commit/a7f816eeb7fa1e193cf0901efbdcaf629f72465f)) +- Update `messageCount`/`totalMessageSent` on message events (#8635) ([145eb2f](https://github.com/discordjs/discord.js/commit/145eb2fc5db5ca739aa9782d5ec5210f81a6aeeb)) +- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9)) + +## Documentation + +- Correctly overwrite `setRTCRegion` method (#8642) ([f049734](https://github.com/discordjs/discord.js/commit/f0497343f1193635b260b9e2085cac7b43991f74)) +- **GuildTextThreadManager:** Document correct `@extend` (#8639) ([802b239](https://github.com/discordjs/discord.js/commit/802b2394b08151faab6810695fd5c8f27ce84d58)) +- Fix regexps incorrectly being called global (#8624) ([fc9653f](https://github.com/discordjs/discord.js/commit/fc9653f5aea4013da15fb8de0a4452400eaa7739)) +- Update misleading `Client#guildMemberAvailable` event description (#8626) ([22ac6b4](https://github.com/discordjs/discord.js/commit/22ac6b4660db6b02f62b9851e9e3bcfe5fb506b5)) +- **Options:** Update DefaultMakeCacheSettings (#8585) ([3252332](https://github.com/discordjs/discord.js/commit/32523325c6610e95fe3ffcc31d005b3418c6bc68)) +- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0)) + +## Features + +- **Widget:** Allow forum channels (#8645) ([b106956](https://github.com/discordjs/discord.js/commit/b1069563086fc616fe21abb789f28f69e57c8851)) +- **WelcomeChannel:** Add forum channel as a type (#8643) ([6f1f465](https://github.com/discordjs/discord.js/commit/6f1f465a77e362e20ec50067be0e634d35946ba5)) +- Allow forum channels in webhook update event (#8646) ([5048a3d](https://github.com/discordjs/discord.js/commit/5048a3d17ace22336e74451d30b513b3db42a26f)) +- Add support for guild forums (#7791) ([8a8d519](https://github.com/discordjs/discord.js/commit/8a8d519c9c4c082370fc6935b56dafb525b873df)) +- **GuildBanManager#create:** Add `deleteMessageSeconds` (#8326) ([03fb5b0](https://github.com/discordjs/discord.js/commit/03fb5b0a2f45275dec7885175ad691a1d9c449c4)) +- Add typeguard to BaseInteraction#isRepliable (#8565) ([55c3ee2](https://github.com/discordjs/discord.js/commit/55c3ee20ae700e78d18a3c4c04b6a7426cffc060)) +- **Integration:** Add `scopes` (#8483) ([8b3d006](https://github.com/discordjs/discord.js/commit/8b3d0061180cfd5d9ba8beae3e8d623b5ce43ea4)) +- Add `chatInputApplicationCommandMention` formatter (#8546) ([d08a57c](https://github.com/discordjs/discord.js/commit/d08a57cadd9d69a734077cc1902d931ab10336db)) + +## Refactor + +- Replace usage of deprecated `ChannelType`s (#8625) ([669c3cd](https://github.com/discordjs/discord.js/commit/669c3cd2566eac68ef38ab522dd6378ba761e8b3)) +- Split message send/edit types/documentation (#8590) ([8e1afae](https://github.com/discordjs/discord.js/commit/8e1afaebdb686033555ca58e53f34bb97f7369c8)) +- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67)) + +## Typings + +- Narrow channel type in thread managers (#8640) ([14bbc91](https://github.com/discordjs/discord.js/commit/14bbc9150a748e7ac1660c2375c7f065fcc55a6c)) +- **interactions:** Pass `Cached` type to return type of methods (#8619) ([053da5b](https://github.com/discordjs/discord.js/commit/053da5bc91d5cfa8d842b13b0b05083d2f7f086d)) +- Ensure events possess `Client<true>` (#8612) ([a9f003a](https://github.com/discordjs/discord.js/commit/a9f003ac9b56d31166cbf353d02140dad0b2517e)) +- **GuildChannelManager:** Correct `fetch` return type (#8549) ([1d4cdee](https://github.com/discordjs/discord.js/commit/1d4cdee321ab25bb0f109d55a000582825dd79f9)) +- **ThreadChannel:** `fetchStarterMessage` must return a `Message<true>` (#8560) ([b9c62ac](https://github.com/discordjs/discord.js/commit/b9c62ac0f0f534c33f9913135095f8b3d98ec05e)) +- **webhook:** Avatar can be null (#8541) ([f77612a](https://github.com/discordjs/discord.js/commit/f77612a55e9c593a21bc27e58c9fbd03d85787e3)) + +# [14.3.0](https://github.com/discordjs/discord.js/compare/14.2.0...14.3.0) - (2022-08-22) + +## Bug Fixes + +- **GuildMemberManager:** `add()` method throws an error (#8539) ([3bef901](https://github.com/discordjs/discord.js/commit/3bef9018c0be3c5dc51d03b796d08b925dc4e1b9)) +- **Guild:** Widget channel types and fixes (#8530) ([23a0b6c](https://github.com/discordjs/discord.js/commit/23a0b6ccf27410963bd4f5c53d9ee2ce019e90a8)) +- **Embed:** Reference video in video (#8473) ([c97977a](https://github.com/discordjs/discord.js/commit/c97977a3e806bd5d8682bc7fb22ebec1a8ceecdc)) + +## Documentation + +- **GuildAuditLogsEntry:** Correct `action` wording (#8499) ([7d25072](https://github.com/discordjs/discord.js/commit/7d2507279cc9d1397c7d61e7c7b856ff4bc17c86)) + +## Features + +- **GuildMemberManager:** AddRole and removeRole (#8510) ([cda3f00](https://github.com/discordjs/discord.js/commit/cda3f005b1546fdb8410e9550526956f840857fc)) +- Deprecate `ActionRow.from()` (#8504) ([f9c25dd](https://github.com/discordjs/discord.js/commit/f9c25ddcfe68f089e13f1090c3df4bd7cd74d2b7)) +- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166)) + +## Refactor + +- **GuildAuditLogsEntry:** Remove `guild` from application command permission update extra (#8520) ([2b8074d](https://github.com/discordjs/discord.js/commit/2b8074dd12f2f1e957caffb57e5fd4d7be88dc25)) + +## Typings + +- Inference of guild in `MessageManager` (#8538) ([6bb1474](https://github.com/discordjs/discord.js/commit/6bb1474d2001b76773954c959b2c2687e1df0136)) +- Allow choice's value type to be strictly inferred (#8529) ([b3f7c32](https://github.com/discordjs/discord.js/commit/b3f7c32f7f91f12766178f5e17585856e81d9a87)) +- **GuildAuditLogs:** Allow fetching to return all possible values (#8522) ([0dba8ad](https://github.com/discordjs/discord.js/commit/0dba8adbd2e6efd634bd3eb31df09467ba8a8a0d)) +- Correct `EventEmitter.on (static)` return type (#8524) ([16bbc8a](https://github.com/discordjs/discord.js/commit/16bbc8aa208a8a16c22be24696f57d5f7a5faf2b)) +- **GuildAuditLogs:** Remove static `Entry` (#8521) ([7a3d18d](https://github.com/discordjs/discord.js/commit/7a3d18dd6d1fe27393d00019b9ecd35c98b95ee7)) +- Disallow some channel types from webhook creation (#8531) ([4882b17](https://github.com/discordjs/discord.js/commit/4882b17a77484f801faa19fb971f2e6abd88e59f)) +- Implement max/min values for autocomplete (#8498) ([812f7f1](https://github.com/discordjs/discord.js/commit/812f7f1ea86fc953aa796875cbc7ccc434203d77)) +- **ModalMessageModalSubmitInteraction:** ChannelId is not nullable (#8496) ([c31a5cf](https://github.com/discordjs/discord.js/commit/c31a5cfcc82706667768eac77b5f99ba69cf3c91)) +- Change type of ApplicationCommandSubCommand.options (#8476) ([ebaf158](https://github.com/discordjs/discord.js/commit/ebaf158006d3c7db3b8c695e7c027b8af11999ba)) + +# [14.2.0](https://github.com/discordjs/discord.js/compare/14.1.2...14.2.0) - (2022-08-10) + +## Bug Fixes + +- **ThreadChannel:** Handle possibly `null` parent (#8466) ([afa27b1](https://github.com/discordjs/discord.js/commit/afa27b15c5b92bc8d55b8285834d8e03f6692d06)) +- Remove DM channels from `Client#messageDeleteBulk`'s types (#8460) ([6c6fe74](https://github.com/discordjs/discord.js/commit/6c6fe74dd84859c5319efa999404e8168f189710)) +- **Transformers:** Do not transform `Date` objects (#8463) ([0e2a095](https://github.com/discordjs/discord.js/commit/0e2a09571c8e5ee61153b04e45334a226a1b4534)) +- **ModalSubmitInteraction:** Allow deferUpdate (#8455) ([0fab869](https://github.com/discordjs/discord.js/commit/0fab869e5179dca7ddec75b5519615278e51ad82)) +- **Guild:** Unable to fetch templates (#8420) ([aac8acc](https://github.com/discordjs/discord.js/commit/aac8acc22be7d7af99933ef099eca7deda43cb40)) +- **MessageMentions:** Infinite loop in `parsedUsers` getter (#8430) ([b8a3136](https://github.com/discordjs/discord.js/commit/b8a31360a220e3d796f5381bd215d30a379ecb7c)) +- **DataResolver:** Make `Buffer` from string (#8416) ([e72b986](https://github.com/discordjs/discord.js/commit/e72b986939e2958547c0e54d6d27472c8d111609)) + +## Documentation + +- Change registration example to use global commands (#8454) ([64a4041](https://github.com/discordjs/discord.js/commit/64a4041a05e9514334a9f9e1f38a1ea18bb676d5)) +- **Colors:** Provide enum descriptions (#8437) ([6ef4754](https://github.com/discordjs/discord.js/commit/6ef4754d40c5ec65715fc1e00e643c52fe0a6209)) +- **AttachmentBuilder:** Fix #8407 (#8421) ([5b053cf](https://github.com/discordjs/discord.js/commit/5b053cf82ec2f2b717a490485af052dc956fe3c9)) + +## Features + +- **Guild:** Add `max_video_channel_users` (#8423) ([3a96ce7](https://github.com/discordjs/discord.js/commit/3a96ce7970947f6268c21a1323d986aac8cb736d)) + +## Typings + +- **Message:** Correct `bulkDelete` return type (#8465) ([c5b96a1](https://github.com/discordjs/discord.js/commit/c5b96a185cb8ba836b7cd10526c14059866f218f)) +- Fix missing types for mentionable options (#8443) ([452e94f](https://github.com/discordjs/discord.js/commit/452e94fd3ecc12de9e3408982c5c7fd931bae634)) +- **ApplicationCommandOption:** Add `ApplicationCommandBooleanOption` (#8434) ([38275fc](https://github.com/discordjs/discord.js/commit/38275fc53d633ce77ed2b142aff788dcbd4fad8c)) + +# [14.1.2](https://github.com/discordjs/discord.js/compare/14.1.1...14.1.2) - (2022-07-30) + +## Bug Fixes + +- **errors:** Error codes (#8398) ([480c85c](https://github.com/discordjs/discord.js/commit/480c85c9c3d129204b3399ed726a4e570e0b2852)) + +## Documentation + +- **Embed:** Ensure height and width are numbers (#8396) ([fca3dad](https://github.com/discordjs/discord.js/commit/fca3dada2a565eecfc7e5275cc9317df1d261871)) + +# [14.1.0](https://github.com/discordjs/discord.js/compare/14.0.3...14.1.0) - (2022-07-29) + +## Bug Fixes + +- **MessageMentions:** `ignoreRepliedUser` option in `has()` (#8202) ([b4e2c0c](https://github.com/discordjs/discord.js/commit/b4e2c0c4d5538b945f9d597c6410a6f84b315084)) +- **GuildChannelManager:** Allow unsetting rtcRegion (#8359) ([a7d49e5](https://github.com/discordjs/discord.js/commit/a7d49e56fc7c34d2e4548d9e5bf0aec45273506e)) +- **ThreadChannel:** Omit webhook fetching (#8351) ([3839958](https://github.com/discordjs/discord.js/commit/3839958e3f682c715f1017da05436d2fe34900fd)) +- **GuildAuditLogsEntry:** Replace OverwriteType with AuditLogOptionsType (#8345) ([58c1b51](https://github.com/discordjs/discord.js/commit/58c1b51c5ceab137ad9851919b338419eeeab69e)) +- **ShardClientUtil#_respond:** Construct global error (#8348) ([8e520f9](https://github.com/discordjs/discord.js/commit/8e520f946a5b9f93a939290facf4ccca2c05ff21)) +- **Presence:** Do not return NaN for activity timestamp (#8340) ([df42fdf](https://github.com/discordjs/discord.js/commit/df42fdfc421f1190f0a2267a66efd3c921ec2348)) +- **Client:** Omit private properties from toJSON (#8337) ([830c670](https://github.com/discordjs/discord.js/commit/830c670c61dcb17d8ab2a894a3203c68917d27e0)) +- **ApplicationCommandManager:** Allow passing 0n to defaultMemberPermissions (#8311) ([1fb7b30](https://github.com/discordjs/discord.js/commit/1fb7b30963cfe7ea4c05b1f3b42171c879c46a1d)) + +## Documentation + +- **InteractionResponses:** Add `showModal()` return type (#8376) ([0b61dbf](https://github.com/discordjs/discord.js/commit/0b61dbf720e844322b066e30080c3537ab3d8174)) +- **WebhookClient:** Document working options (#8375) ([ba6797e](https://github.com/discordjs/discord.js/commit/ba6797e74209161b64c412de1b6f307cb28736b8)) +- **Message:** Document gateway intent for content (#8364) ([2130aae](https://github.com/discordjs/discord.js/commit/2130aae3210a8eaf91c5ccae5463940d49052c7d)) +- Use info blocks for requirements (#8361) ([80b9738](https://github.com/discordjs/discord.js/commit/80b9738957ebf5b6eb7c9858cec0fb1c897d0a1f)) +- **WebhookClient:** Make constructor a union (#8370) ([e9920a9](https://github.com/discordjs/discord.js/commit/e9920a9c98ffb78bd7d0ae00d486476367296646)) +- Update docs and examples to PascalCase links (#8305) ([34ba9d1](https://github.com/discordjs/discord.js/commit/34ba9d1c4c80eff7e6ac199a40232d07491432cc)) + +## Features + +- Add channel & message URL formatters (#8371) ([a7deb8f](https://github.com/discordjs/discord.js/commit/a7deb8f89830ead6185c5fb46a49688b6d209ed1)) +- Restore missing typeguards (#8328) ([77ed407](https://github.com/discordjs/discord.js/commit/77ed407f6aadb68e729470c5269e9b526cb1b3f0)) +- **GuildMember:** Add dmChannel getter (#8281) ([4fc2c60](https://github.com/discordjs/discord.js/commit/4fc2c60a3bb43671b4b0202ae75eab42aba163ff)) + +## Refactor + +- Deprecate `Formatter` class (#8373) ([7fd9ed8](https://github.com/discordjs/discord.js/commit/7fd9ed8f13d17ce7e98e34f7454d9047054d8467)) +- **PermissionOverwriteManager:** Use `OverwriteType` (#8374) ([6d24805](https://github.com/discordjs/discord.js/commit/6d248051cfd431e9cb1c65cb98f56aa0a6556407)) + +## Typings + +- **GuildAuditLogsEntryExtraField:** Use `AuditLogOptionsType` (#8349) ([200ab91](https://github.com/discordjs/discord.js/commit/200ab91f527d8a5706d277b89a975096f75d141a)) + +# [14.0.3](https://github.com/discordjs/discord.js/compare/14.0.2...14.0.3) - (2022-07-19) + +## Bug Fixes + +- **Components:** Support emoji id strings (#8310) ([660e212](https://github.com/discordjs/discord.js/commit/660e212e83df026c684ee2cda7fb4e98870f342e)) + +# [14.0.2](https://github.com/discordjs/discord.js/compare/14.0.1...14.0.2) - (2022-07-18) + +## Bug Fixes + +- **DataResolver#resolveImage:** Adjust to updated resolveFile (#8308) ([3a7e93d](https://github.com/discordjs/discord.js/commit/3a7e93df576172c797f1d8bd6483234bb6af2d00)) + +# [14.0.0](https://github.com/discordjs/discord.js/compare/9.3.1...14.0.0) - (2022-07-17) + +## Bug Fixes + +- **GuildMemberManager:** Allow setting own nickname (#8066) ([52a9e21](https://github.com/discordjs/discord.js/commit/52a9e213c2dc13ee52ee0234593fdce392f43890)) +- **PermissionOverwriteManager:** Mutates user (#8283) ([3bf30b1](https://github.com/discordjs/discord.js/commit/3bf30b1e6d2d6f583f7069a1e24e7842d59fab2f)) +- **GuildChannelManager:** Access `resolveId` correctly (#8296) ([3648f6d](https://github.com/discordjs/discord.js/commit/3648f6d567cd834c301de913ce19f786a265240d)) +- **GuildChannelManager:** Edit lockPermissions (#8269) ([7876548](https://github.com/discordjs/discord.js/commit/787654816d2b6a5168d199d32cdaeb4ef6d270b9)) +- **`SelectMenuBuilder`:** Properly accept `SelectMenuOptionBuilder`s (#8174) ([31d5930](https://github.com/discordjs/discord.js/commit/31d593046466438c55f5784b0f2098e233c5edc4)) +- Remove global flag on regular expressions (#8177) ([cdd9214](https://github.com/discordjs/discord.js/commit/cdd9214212892e30b3eaa161837c37516c5bcaa0)) +- **MessagePayload:** Guard against `repliedUser` property (#8211) ([fa010b5](https://github.com/discordjs/discord.js/commit/fa010b516254c4ab2762278817f31bf289f0ab6a)) +- **ApplicationCommandManager:** Explicitly allow passing builders to methods (#8209) ([50d55bd](https://github.com/discordjs/discord.js/commit/50d55bd6b819307c86701f4808c087f359c6ccff)) +- **GuildMemberRemove:** Remove member's presence (#8181) ([11b1739](https://github.com/discordjs/discord.js/commit/11b173931968c548f8504649ae7090865892e62d)) +- Edit() data can be partial and `defaultMemberPermissions` can be `null` (#8163) ([0ffbef5](https://github.com/discordjs/discord.js/commit/0ffbef506a97a0bf22cb134fc007c2aec29cbffc)) +- **WebSocketShard:** Keep an error handler on connections (#8150) ([c34c02a](https://github.com/discordjs/discord.js/commit/c34c02ab8d119bf16d8d14d125a9b650b4bb18f4)) +- **DJSError:** Error code validation (#8149) ([31f6582](https://github.com/discordjs/discord.js/commit/31f658247fe0e1047897edab629643d140e77e07)) +- **vcs:** Nsfw property (#8132) ([2eeaad6](https://github.com/discordjs/discord.js/commit/2eeaad6f27fdf8868364fa95ed20755ee09bda87)) +- **WebSocketManager:** Correct error name (#8138) ([db2b033](https://github.com/discordjs/discord.js/commit/db2b0333d912fe83381db2ffe16829d7d03d6c2e)) +- **WebSocketShard:** Disconnected casing (#8117) ([23e183a](https://github.com/discordjs/discord.js/commit/23e183a9ac7aaa3bca2bc4eb8634d1738ec34a26)) +- **webhooks:** Revert webhook caching (and returning Message) (#8038) ([d54bf5d](https://github.com/discordjs/discord.js/commit/d54bf5d286f4057db130901591b192fd4d1668c1)) +- **ApplicationCommand:** Remove `autocomplete` check at the top level and correctly check for `dmPermission` (#8100) ([0a44b05](https://github.com/discordjs/discord.js/commit/0a44b05db83948857afbe18471e7a867da47177a)) +- **ApplicationCommand:** Fix default member permissions assignment (#8067) ([96053ba](https://github.com/discordjs/discord.js/commit/96053babe1bd65ebe1fc6a261f5eb052906afdb9)) +- **scripts:** Read directory and rerun (#8065) ([f527dea](https://github.com/discordjs/discord.js/commit/f527dea36ead194aaae1bf5da1e953df59d692fd)) +- Select menu options to accept both rest and array (#8032) ([fbe67e1](https://github.com/discordjs/discord.js/commit/fbe67e102502b4b49690cbf8ff891ead2232ecf3)) +- **CommandInteractionOptionResolver:** Handle autocompletion interactions (#8058) ([d8077c6](https://github.com/discordjs/discord.js/commit/d8077c6839dc8ceb57d3c3a86bf9746be2a91ada)) +- **scripts:** Add quotes around blob arguments (#8054) ([598f61b](https://github.com/discordjs/discord.js/commit/598f61b992fab1b3fdcab8ff960366f7af0b37ea)) +- **Message:** Force fetching (#8047) ([f2b267c](https://github.com/discordjs/discord.js/commit/f2b267c079dd8aa7277910471f3db2f88af6efb2)) +- **Attachment:** Do not destructure `data` (#8041) ([1afae90](https://github.com/discordjs/discord.js/commit/1afae909d72e648cf48d63d7de2708737a78c126)) +- **DirectoryChannel:** Type `name` and handle `url` (#8023) ([86d8fbc](https://github.com/discordjs/discord.js/commit/86d8fbc023e3925e8f86799d6ebf2d423f7bf2ec)) +- Readd `isThread` type guard (#8019) ([f8ed71b](https://github.com/discordjs/discord.js/commit/f8ed71bfca6e47e3d44ad063e23804354bd23604)) +- Add static method `from` in builders (#7990) ([ad36c0b](https://github.com/discordjs/discord.js/commit/ad36c0be7744ea4214ccf345fe80a5a1a9e89101)) +- Typings (#7965) ([7a1095b](https://github.com/discordjs/discord.js/commit/7a1095b66be3c5d81185e026281e2908c10c1695)) +- **GuildAuditLogs:** Cache guild scheduled events (#7951) ([2f03f9a](https://github.com/discordjs/discord.js/commit/2f03f9ad3f63abee5b5c46d02f1afa8885e8977c)) +- Make sure action row builders create djs builders (#7945) ([adf461b](https://github.com/discordjs/discord.js/commit/adf461baf49be754c7a10c61faf1ef3df333413a)) +- **TextBasedChannel#bulkDelete:** Return deleted message (#7943) ([191510b](https://github.com/discordjs/discord.js/commit/191510b7f87903e4bd93b891649cb290fd50c47e)) +- Remove trailing invites on channel deletion (#7932) ([5e9b757](https://github.com/discordjs/discord.js/commit/5e9b757a3733e6526770eb60a15072612294eb21)) +- **DataResolver:** Fix check for readable streams (#7928) ([28172ca](https://github.com/discordjs/discord.js/commit/28172ca7b57357436d3252ec01ec17dad865d87f)) +- **AuditLog:** Default changes to empty array (#7880) ([19eaed6](https://github.com/discordjs/discord.js/commit/19eaed63905367ef4604366b8839023384524d1f)) +- **Util:** Flatten ignoring certain fields (#7773) ([df64d3e](https://github.com/discordjs/discord.js/commit/df64d3ea382c07e66bc7cc8877ee430206c31d63)) +- Possibly missing (#7829) ([6239d83](https://github.com/discordjs/discord.js/commit/6239d83c4d5f0a396678410d7fef35e39ed29009)) +- `endReason` not being properly set in base Collector (#7833) ([0c18dab](https://github.com/discordjs/discord.js/commit/0c18dab1280205b8855d17d075b7421860d59c14)) +- **SelectMenuBuilder:** Options array (#7826) ([3617093](https://github.com/discordjs/discord.js/commit/361709332bdc871822c2b9919f14fd090d68666a)) +- **Activity:** Platform type (#7805) ([4ac91c6](https://github.com/discordjs/discord.js/commit/4ac91c61d08111ae4d49d1e64caf94e6e49832c8)) +- **ApplicationCommand:** Equal nameLocalizations and descriptionLocalizations (#7802) ([4972bd8](https://github.com/discordjs/discord.js/commit/4972bd87c17cbc6a94c9608ba2ab39c475f9921f)) +- **InteractionResponses:** Use optional chaining on nullable property (#7812) ([c5fb548](https://github.com/discordjs/discord.js/commit/c5fb54852906898ffb19282dd60168dfc6fb2eba)) +- **MessageManager:** Allow caching option of an unspecified limit (#7763) ([1b2d8de](https://github.com/discordjs/discord.js/commit/1b2d8decb638faeae8184119c5cedfcdaf9485e3)) +- **builders:** Add constructor default param (#7788) ([c286650](https://github.com/discordjs/discord.js/commit/c2866504a3824005fe756556fec4b349898b7d22)) +- **MessagePayload:** ResolveBody check body instead of data (#7738) ([3db20ab](https://github.com/discordjs/discord.js/commit/3db20abdd2d502a1ed457842181b164dc6390ba1)) +- **ActionRow:** ToJSON should include components (#7739) ([ebb4dfa](https://github.com/discordjs/discord.js/commit/ebb4dfa262adb2086c83db487002bb2e1ed5ab88)) +- Prevent `NaN` for nullable timestamps (#7750) ([8625d81](https://github.com/discordjs/discord.js/commit/8625d817145eb642aeb0da05184352f438586986)) +- **InteractionCreateAction:** Ensure text-based channel for caching messages (#7755) ([25fdb38](https://github.com/discordjs/discord.js/commit/25fdb3894d33dc395a376a3d962a063eb5735253)) +- Pass `force` correctly (#7721) ([402514f](https://github.com/discordjs/discord.js/commit/402514ff323ccf1f8c95d295f044cf0bb5547c2e)) +- Support reason in setRTCRegion helpers (#7723) ([905a6a1](https://github.com/discordjs/discord.js/commit/905a6a11663f9469ada67f8310a969453ffc5b2a)) +- **GuildMemberManager:** Return type can be null (#7680) ([74bf7d5](https://github.com/discordjs/discord.js/commit/74bf7d57ab959eb820ab1c213ac86ab1ea660398)) +- **gateway:** Use version 10 (#7689) ([8880de0](https://github.com/discordjs/discord.js/commit/8880de0cecdf273fd6df23988e4cb77774a75390)) +- Audit log static reference (#7703) ([85e531f](https://github.com/discordjs/discord.js/commit/85e531f22d7a8f8ad043647ce445726ae0df26c0)) +- Handle possibly missing property (#7641) ([0c32332](https://github.com/discordjs/discord.js/commit/0c32332a5aacbbb6c415da75c166d09cfdb34bbd)) +- **util:** Allow `escapeInlineCode` to escape double backtics (#7638) ([d5369a5](https://github.com/discordjs/discord.js/commit/d5369a56e3fcf50513f3bc582552c2838b04d199)) +- **GuildEditData:** Some fields can be null (#7632) ([4d2b559](https://github.com/discordjs/discord.js/commit/4d2b55955d1a3ff05c3047599232becdc3f2c445)) +- TOKEN_INVALID error not thrown at login with invalid token (#7630) ([cd79bef](https://github.com/discordjs/discord.js/commit/cd79bef2547594f4d0c744faa8fa67fb9fd61526)) +- **GuildScheduledEvent:** Handle missing `image` (#7625) ([c684ac5](https://github.com/discordjs/discord.js/commit/c684ac55e1d225740e67ab7bd5643de1b35f4594)) +- **guild:** Throw if ownerId falsey (#7575) ([98177aa](https://github.com/discordjs/discord.js/commit/98177aa38d3d6516d4c5354d6c7edea925dc881d)) +- Remove Modal export (#7654) ([87a6b84](https://github.com/discordjs/discord.js/commit/87a6b8445bfbf3981cd39813fe961dfa1c7f2bce)) +- **Embed:** Fix incorrect destructuring import (#7615) ([cbdb408](https://github.com/discordjs/discord.js/commit/cbdb408dffd1c7f2193c15989528a3de5fd9f13a)) +- **ThreadMembersUpdate:** Only emit added & removed thread members (#7539) ([c12d61a](https://github.com/discordjs/discord.js/commit/c12d61a3421afcdc41f77c0fddde4efbb257fa69)) +- **Util:** EscapeInlineCode properly (#7587) ([851f380](https://github.com/discordjs/discord.js/commit/851f380eb10d23ffd08e8b845aed4039abbcd03b)) +- **GuildStickerManager:** Correctly access guild ID (#7605) ([4b08d9b](https://github.com/discordjs/discord.js/commit/4b08d9b376bda7a7f4bb3fb8c555d25cca648de4)) +- **MessageManager:** Pin route (#7610) ([cb566c8](https://github.com/discordjs/discord.js/commit/cb566c8b6abff489a944db7952e5c5a48e0c98b0)) +- Handle partial data for `Typing#user` (#7542) ([c6cb5e9](https://github.com/discordjs/discord.js/commit/c6cb5e9ebbf46d81404119a6aa11bb8ebb17d5a4)) +- **guild:** Fix typo accessing user instead of users (#7537) ([8203c5d](https://github.com/discordjs/discord.js/commit/8203c5d843f2431c0f49023282f1bf73d85881d1)) +- **test:** `MessageActionRow` to `ActionRow` (#7523) ([d1d1b07](https://github.com/discordjs/discord.js/commit/d1d1b076bebf7cb706b2436a40d87c6efaed1e1d)) +- **MessagePayload:** Don't set reply flags to target flags (#7514) ([4f30652](https://github.com/discordjs/discord.js/commit/4f306521d829fef21ebd70557b37f8199b82572b)) +- **invite:** Add back channelId property (#7501) ([78aa36f](https://github.com/discordjs/discord.js/commit/78aa36f9f5913b86c82376ecdf20653b15340bbe)) +- Properly serialize `undefined` values (#7497) ([8dbd345](https://github.com/discordjs/discord.js/commit/8dbd34544cbeb499282f01dda9d35ed9bca93591)) +- Allow unsafe embeds to be serialized (#7494) ([942ea1a](https://github.com/discordjs/discord.js/commit/942ea1acbfb49289ccb3a1882b5a2da0a7d0bccf)) +- Attachment types (#7478) ([395a68f](https://github.com/discordjs/discord.js/commit/395a68ff49c622d5136d6b775beaf8e88a2d8610)) +- Use case converter for json component serialization (#7464) ([2d45544](https://github.com/discordjs/discord.js/commit/2d4554440ed9329a5876a9c674c3eb2de0f2f917)) +- **GuildAuditLogs:** Typings and consistency (#7445) ([c1b27f8](https://github.com/discordjs/discord.js/commit/c1b27f8eed8ea04a48bc106453892bddcdc6b73e)) +- **dataresolver:** Ensure fetched file is convert to a buffer (#7457) ([9311fa7](https://github.com/discordjs/discord.js/commit/9311fa7b42b2b5a74e411aa263daa4fbfc270645)) +- **messagepayload:** ResolveFile property names (#7458) ([a8106f7](https://github.com/discordjs/discord.js/commit/a8106f7c586f0ecac76e7f72c53b0da215a6fbf1)) +- **ci:** Ci error (#7454) ([0af9bc8](https://github.com/discordjs/discord.js/commit/0af9bc841ffe1a297d308500d696bad4b85abda9)) +- **threads:** Require being sendable to be unarchivable (#7406) ([861f0e2](https://github.com/discordjs/discord.js/commit/861f0e2134662ab64a11d313130aff58b413d495)) +- **guildmember:** Check if member has administrator permission (#7384) ([81d8b54](https://github.com/discordjs/discord.js/commit/81d8b54ff6b98b0e7ee2c57eaee6bc0b707e135a)) +- **guild:** Remove `maximumPresences` default value (#7440) ([55b388a](https://github.com/discordjs/discord.js/commit/55b388a763dc7223e88b62ae928fe85fe8b8fe58)) +- **guildchannelmanager:** Edit always sets parent to null (#7446) ([b97aedd](https://github.com/discordjs/discord.js/commit/b97aedd8e15f9358960cb59403f3a8ea24b87141)) +- **guildmember:** Make `pending` nullable (#7401) ([fe11ff5](https://github.com/discordjs/discord.js/commit/fe11ff5f6e85571a981e90eba5b9f3bda7a2cd04)) +- **clientpresence:** Fix used opcodes (#7415) ([a921ec7](https://github.com/discordjs/discord.js/commit/a921ec7dc525c58d40b4678e66270f9238abed31)) +- Correctly export UnsafeSelectMenuComponent from builders (#7421) ([aadfbda](https://github.com/discordjs/discord.js/commit/aadfbda586d57a7b775ad26c201f0dc34618180b)) +- MessageReaction.me being false when it shouldn't (#7378) ([04502ce](https://github.com/discordjs/discord.js/commit/04502ce702da53c4b00bf391d0fd936746851381)) +- Fix some typos (#7393) ([92a04f4](https://github.com/discordjs/discord.js/commit/92a04f4d98f6c6760214034cc8f5a1eaa78893c7)) +- **messagementions:** Fix `has` method (#7292) ([3a5ab2c](https://github.com/discordjs/discord.js/commit/3a5ab2c4e54de4e67ab6e323d7eac86482da7382)) +- **guildmembermanager:** Use rest in edit (#7356) ([00ce1c5](https://github.com/discordjs/discord.js/commit/00ce1c56ac224691a8691a3525cb14ae002319c6)) +- **typings:** Mark `RESTOptions` as Partial in `ClientOptions` (#7349) ([e1ecc1a](https://github.com/discordjs/discord.js/commit/e1ecc1a80a9358cdbafbe8542c40b9de8cad467e)) +- **Webhook:** Use correct method name (#7348) ([11e5e5a](https://github.com/discordjs/discord.js/commit/11e5e5ac5b70138f56332eb3e61a42443670b0de)) +- **thread:** Don't assign directly to getters (#7346) ([2db0cdd](https://github.com/discordjs/discord.js/commit/2db0cdd357c3a02decb4fd4168db87888efba283)) +- Missed enums and typings from #7290 (#7331) ([47633f0](https://github.com/discordjs/discord.js/commit/47633f0fd2435d6d8c694d8d37b26039a7b3797a)) +- **guildchannelmanager:** Remove reverse enum lookup (#7304) ([857bba4](https://github.com/discordjs/discord.js/commit/857bba448029f3f070c67fb40b59a3a2a2e5c6f4)) +- Import `clear{Timeout,Interval}` from `node:timers` (#7269) ([8ddd44e](https://github.com/discordjs/discord.js/commit/8ddd44ed85b32c86243efe0ec35b283eaaa8212c)) +- **ApplicationCommand:** Use new ApplicationCommandOptionType enums (#7257) ([06f5210](https://github.com/discordjs/discord.js/commit/06f5210f58bbba6102173033a9f1e6fb004fdf5d)) +- Use enums from discord-api-types (#7258) ([f284a46](https://github.com/discordjs/discord.js/commit/f284a4641fd68de9190bda97ec1eab0981149630)) +- **exports:** Export ApplicationCommandType properly (#7256) ([f753882](https://github.com/discordjs/discord.js/commit/f75388259262bf6b4a64375b97800bd72378f3bc)) +- **Shard:** EventEmitter listener warning (#7240) ([ff3a8b8](https://github.com/discordjs/discord.js/commit/ff3a8b83234d3826fc49c5a8c3cb52ef9f281ffd)) +- **timestamps:** Account for timestamps of 0 when creating Dates (#7226) ([a8509c9](https://github.com/discordjs/discord.js/commit/a8509c91ca0147393b407221405b6b917677961a)) +- **MessageEmbed:** CreatedAt field can be zero (#7218) ([37cad54](https://github.com/discordjs/discord.js/commit/37cad54dbdade39607397b8ad697eca94f1b7197)) +- **BaseClient:** Do not append default options if provided is not an object (#6453) ([b92a7d7](https://github.com/discordjs/discord.js/commit/b92a7d72332c35b607db54aa6aca24b8e10e00ad)) +- Snowflakeutil import (#7219) ([962f4bf](https://github.com/discordjs/discord.js/commit/962f4bf88211dbfb5ad0295a9467dede1e2688ee)) +- **Role:** Remove unused process (#7215) ([63034b4](https://github.com/discordjs/discord.js/commit/63034b44c9849087e391684d9b6c0c6ae9a21113)) +- **WebhookClient:** Updated webhook url regex (#6804) ([1c615d1](https://github.com/discordjs/discord.js/commit/1c615d1bb2606d5f19e55076d4ecab95c619518e)) +- **Sweepers:** Add sweepStickers function (#7213) ([95f8375](https://github.com/discordjs/discord.js/commit/95f8375d425f58f501f32ead03f7927e6596f8e6)) +- **InteractionCreate:** Use ChatInputCommandInteraction instead (#7210) ([49dada3](https://github.com/discordjs/discord.js/commit/49dada35f92470d3e4426362510847b93dd42d1a)) +- **Structues:** Rename old module's name (#7207) ([fbef454](https://github.com/discordjs/discord.js/commit/fbef45489457a2198357dc4dd303740d79036784)) +- **WebSocket:** Remove application command handler (#7202) ([033151c](https://github.com/discordjs/discord.js/commit/033151cf92fe43536b8a4c0f4d7d9ed75a2095c5)) +- **User:** `bannerURL()` should not throw when not present (#6789) ([3872acf](https://github.com/discordjs/discord.js/commit/3872acfeb8390f6f7202d69cf1f7f8616a7b0b34)) +- **VoiceState:** Ensure `suppress` & `streaming` have proper fallback values (#6377) ([a0d5f13](https://github.com/discordjs/discord.js/commit/a0d5f13dd9b27c44f5183a2a9af4c4fdecb312c0)) +- **sweepers:** Provide default for object param (#7182) ([ae2f013](https://github.com/discordjs/discord.js/commit/ae2f013653c8a9f9ffb12ae8fcdb1bb604b39236)) + +## Deprecation + +- **Caching:** Clean up deprecated cache sweeping (#7118) ([12ffa06](https://github.com/discordjs/discord.js/commit/12ffa069aa8b247e945fef16a543f41c2c391bf1)) + +## Documentation + +- Align webhook method return types with implementation (#8253) ([5aeed99](https://github.com/discordjs/discord.js/commit/5aeed9935058241648507d7f651679226a89dbb3)) +- Remove `@private` constructor documentation (#8255) ([452dec5](https://github.com/discordjs/discord.js/commit/452dec57ca422f5e7424a0f0e78c3e152717f413)) +- **ApplicationCommand:** Add `min_length` and `max_length` to ApplicationCommandOptionData (#8239) ([43f62bb](https://github.com/discordjs/discord.js/commit/43f62bb6678ec332795c8cfbe0c01854b95aa61e)) +- **MessageInteraction#commandName:** Updated description (#8212) ([ab238a9](https://github.com/discordjs/discord.js/commit/ab238a9046e0201dbd4755fa41fa69c44b186912)) +- Add missing `@extends` (#8205) ([e0c8282](https://github.com/discordjs/discord.js/commit/e0c82824905dcebf62c2d1afcc5e5590a5594838)) +- **Constants:** Fix SweeperKeys type (#8157) ([af04992](https://github.com/discordjs/discord.js/commit/af04992ed3c2617fda686c2bc7338dcada283dc6)) +- **Channels:** Internally document channel creation (#8154) ([5e5853a](https://github.com/discordjs/discord.js/commit/5e5853a4e885c47e3dde519761dd59a5ec0e06fc)) +- Update threads to use `ThreadAutoArchiveDuration` (#8153) ([ee36d60](https://github.com/discordjs/discord.js/commit/ee36d60dc6714c83569a20716fa8ca8e1bd7de4f)) +- **APITypes:** Remove duplicate type definition (#8144) ([a061233](https://github.com/discordjs/discord.js/commit/a0612335101c7ce2a07d95da4b79f0d4a2b1a6a0)) +- Document missing type definitions (#8130) ([203bc4a](https://github.com/discordjs/discord.js/commit/203bc4a2cf0c2d90a003093318aa0741605610f5)) +- **InteractionResponse:** Fix return (#8141) ([f1ac17c](https://github.com/discordjs/discord.js/commit/f1ac17c961cf95d99e205133605d10d8be5bd737)) +- **PermissionsBitField:** Fix `@name` of bitfield (#8115) ([3a77ce0](https://github.com/discordjs/discord.js/commit/3a77ce0b18c60a0b21ba088590ff89f2ace94087)) +- `TextBasedChannel` -> `TextBasedChannels` typos (#8110) ([db663a5](https://github.com/discordjs/discord.js/commit/db663a55c2ed2faf61e217009158da50dfcf274f)) +- Remove `number`s from enums (#8098) ([0a138da](https://github.com/discordjs/discord.js/commit/0a138dab95a86512f08ac3be356f77f38f2ea880)) +- **GuildAuditLogs:** Fix and reimplement type definitions (#8108) ([4155136](https://github.com/discordjs/discord.js/commit/415513696c7b7e139d1b958e480bf0c7e4d14111)) +- **WebSocketOptions:** Add `version` to docs and typings (#8050) ([386c41f](https://github.com/discordjs/discord.js/commit/386c41f24fb3c9d06967d9c1881a57645c3a71f2)) +- **BaseGuildTextChannel:** Update `setType()`'s parameter type (#8088) ([9c0f190](https://github.com/discordjs/discord.js/commit/9c0f190de1f743d9bd597ffd656503c672db71c1)) +- Update outdated examples (#8081) ([51eadf3](https://github.com/discordjs/discord.js/commit/51eadf37371a6138847efdb4b5b81ee132001cf0)) +- **ThreadMemberManager:** Require `member` in `FetchThreadMemberOptions` (#8079) ([552ec72](https://github.com/discordjs/discord.js/commit/552ec72542ec3b2b3ebf35c9fd84ab502dd746cf)) +- **AutocompleteInteraction:** Change useless log in responds example (#8077) ([ac7bf69](https://github.com/discordjs/discord.js/commit/ac7bf692bfce8204e278205dde811515a51f154b)) +- Description and missing `@typedef` fixes (#8087) ([a2eebf6](https://github.com/discordjs/discord.js/commit/a2eebf6c66f3e4c96ece9d2ae2a1133c84257f42)) +- Ignore docs of unexported functions (#8051) ([94bdcac](https://github.com/discordjs/discord.js/commit/94bdcaca62414a77d4ee0b8b79752a2be937320b)) +- **ClientOptions:** Fix closeTimeout default (#8049) ([b2eea1c](https://github.com/discordjs/discord.js/commit/b2eea1c900ba73d4b98b72f5c196f51e27d3ab8f)) +- **DirectoryChannel:** Extend `Channel` (#8022) ([f3f34f0](https://github.com/discordjs/discord.js/commit/f3f34f07b3b396015b130b8e9d938a3eec688fc3)) +- **Attachment:** Remove constructor doc (#8009) ([0a7953e](https://github.com/discordjs/discord.js/commit/0a7953e46310c77483d277539b47f1a7ab051fd9)) +- **VoiceChannel:** Annotate that it is implementing TextBasedChannel (#8007) ([5987dbe](https://github.com/discordjs/discord.js/commit/5987dbe5cff6991ae6905b0387411fa042d3e9b7)) +- Add missing discord-api-types external types (#8001) ([546d486](https://github.com/discordjs/discord.js/commit/546d48655f36ed9a6c6c5ce3c2eabcca1a86a945)) +- **InteractionResponses:** Replace outdated Embed example for reply (#7875) ([d308c66](https://github.com/discordjs/discord.js/commit/d308c66eeca6bdc3471637ae3aaaaa0a2f5c9989)) +- Require parameter (#7838) ([f4ccc67](https://github.com/discordjs/discord.js/commit/f4ccc6772c15e32489ca22fb2c3e803b85d4dbf9)) +- **ApplicationCommand:** Fix and improve localization docs (#7804) ([61a44c5](https://github.com/discordjs/discord.js/commit/61a44c509c40abaf7ffb95b10942889cbbf155ac)) +- **ApplicationCommand:** Fix ApplicationCommandOptionChoice (#7794) ([f1d0084](https://github.com/discordjs/discord.js/commit/f1d0084da26b0111ca029c789ad9e8e6c2882b4d)) +- Add back static properties and methods (#7706) ([520f471](https://github.com/discordjs/discord.js/commit/520f471ac56cbc01402b79197333a8a34c4ac5c9)) +- **InteractionCollector:** Document channel option type (#7551) ([e787cd5](https://github.com/discordjs/discord.js/commit/e787cd5fa5d013319347392ee4f799a677f6f512)) +- Correctly type getters (#7500) ([ffecf08](https://github.com/discordjs/discord.js/commit/ffecf084956f954cf10e1b844e00326e443a86f2)) +- ApplicationCommandData typedef (#7389) ([d32db88](https://github.com/discordjs/discord.js/commit/d32db8833e1058fb36f2e83af79d5353a9f2f693)) +- **channel:** Fix `isDMBased` docs (#7411) ([f2a7a9f](https://github.com/discordjs/discord.js/commit/f2a7a9f1b30af272a6a8d81825d09f84e749cc24)) +- **messageattachment:** Fix `contentType` docs (#7413) ([2800e07](https://github.com/discordjs/discord.js/commit/2800e07e5974e07b9f8ce043722b9b99a5bcc80d)) +- Add supported option types for autocomplete (#7368) ([8bb3751](https://github.com/discordjs/discord.js/commit/8bb37513400d646d784d59875d6b6a6ec10160cd)) +- Add external builder docs links (#7390) ([0b866c9](https://github.com/discordjs/discord.js/commit/0b866c9fb284971113e288e52327d4506db28011)) +- Add EnumResolvers (#7353) ([72767a1](https://github.com/discordjs/discord.js/commit/72767a1059526bdf617e80d5a9e5da1fbd2936d3)) +- **locales:** Update Discord API docs link (#7266) ([b640272](https://github.com/discordjs/discord.js/commit/b6402723c31bed3c49f8b8cde873b65b9f373fd7)) +- **StageInstance:** Deprecate discoverableDisabled (#7179) ([bd33ebb](https://github.com/discordjs/discord.js/commit/bd33ebb507eab36bc2219103dbd1e0217b9f38c0)) +- **shardingmanager:** Fix type of `execArgv` option (#7284) ([e65da44](https://github.com/discordjs/discord.js/commit/e65da44d9c564d1ffcb0f4df2bcdaf0ce0636f35)) +- **interaction:** Add locale list link (#7261) ([37ec0bd](https://github.com/discordjs/discord.js/commit/37ec0bda6df75fb1dc69b7a1eafbb8ea19e68457)) +- Fix a typo and use milliseconds instead of ms (#7251) ([0dd56af](https://github.com/discordjs/discord.js/commit/0dd56afe1cdf16f1e7d9afe1f8c29c31d1833a25)) +- Fix command interaction docs (#7212) ([137ea24](https://github.com/discordjs/discord.js/commit/137ea249df3aa6b8375ecb42aa456a6fdb811f19)) +- **TextBasedChannel:** Fixed syntax error in examples (#7163) ([b454740](https://github.com/discordjs/discord.js/commit/b454740ae87b6c3c13536181965519c7277e5840)) +- **TextBasedChannel:** Fix #createMessageComponentCollector description (#7168) ([d4e6e03](https://github.com/discordjs/discord.js/commit/d4e6e0370857dff00185d59faf8aaac12b343a7a)) +- Fixes the examples for kick and ban (#7170) ([db669b8](https://github.com/discordjs/discord.js/commit/db669b897132ec458d50ca6c1e3afa761e98ffc3)) +- **RoleManager:** Fix incorrect example (#7174) ([f79ea67](https://github.com/discordjs/discord.js/commit/f79ea67d3a9ba134a9acef0a443bd089c4e173a6)) + +## Features + +- **builder:** Add max min length in string option (#8214) ([96c8d21](https://github.com/discordjs/discord.js/commit/96c8d21f95eb366c46ae23505ba9054f44821b25)) +- **applicationCommand:** Add max min length in string option (#8215) ([94ee60d](https://github.com/discordjs/discord.js/commit/94ee60d3d438f6657bdef51471528769af09624c)) +- Add website documentation early mvp (#8183) ([d95197c](https://github.com/discordjs/discord.js/commit/d95197cc78593df4d0a8d1cc492b0e41b4ab58b8)) +- **BaseInteraction:** Add support for `app_permissions` (#8194) ([002d6a5](https://github.com/discordjs/discord.js/commit/002d6a5aede3d1c0e08bd58eeef38a3b9202f525)) +- **util:** ParseWebhookURL (#8166) ([c4653f9](https://github.com/discordjs/discord.js/commit/c4653f97b1529eb0b99fccdba67c37eb4f467ff9)) +- **AutocompleteInteraction:** Add `commandGuildId` (#8086) ([10a6c42](https://github.com/discordjs/discord.js/commit/10a6c4287dd45a30290814e50fa29a086f85da02)) +- **guild:** Add support for setting MFA level (#8024) ([c5176be](https://github.com/discordjs/discord.js/commit/c5176be14b697ff506eb973c4119644eab544304)) +- **vcs:** Add missing property and methods (#8002) ([0415300](https://github.com/discordjs/discord.js/commit/0415300243877ddbcb501c0a26b1ff65618a1da7)) +- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21)) +- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc)) +- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86)) +- Backport handle zombie connection (#7626) ([e1176fa](https://github.com/discordjs/discord.js/commit/e1176faa27898d4f127c293c099201cb294e10ee)) +- **CommandInteraction:** Add 'commandGuildId' (#8018) ([aa59a40](https://github.com/discordjs/discord.js/commit/aa59a409b36c7ef7018d1785d2dba4da17b57864)) +- Allow builders to accept rest params and arrays (#7874) ([ad75be9](https://github.com/discordjs/discord.js/commit/ad75be9a9cf90c8624495df99b75177e6c24022f)) +- **MessageReaction:** Add react method (#7810) ([a328778](https://github.com/discordjs/discord.js/commit/a3287782b57c28b94c390c24e7d5f2d8c303301f)) +- **Collector:** Add `ignore` event (#7644) ([5244fe3](https://github.com/discordjs/discord.js/commit/5244fe3c1cd400985b00e95d8e5ec73823cf4f25)) +- **GuildMemberManager:** Add `GuildMemberManager#fetchMe()` (#7526) ([349766d](https://github.com/discordjs/discord.js/commit/349766dd6925e2d5e5597cc78c73e46f17c56eab)) +- **guildChannelManager:** Add `videoQualityMode` option for `create()` (#7980) ([cdd2ba0](https://github.com/discordjs/discord.js/commit/cdd2ba036ab1559783eb067786c52aff61807557)) +- **EnumResolvers:** Remove Enumresolvers (#7876) ([76694c1](https://github.com/discordjs/discord.js/commit/76694c1497de1b083a792fd1fda20f0eace50c48)) +- Move `me` to `GuildMemberManager` manager (#7669) ([aed687b](https://github.com/discordjs/discord.js/commit/aed687b09f87862eb2f33fb9f95b2cbd0b770585)) +- **rest:** Use undici (#7747) ([d1ec8c3](https://github.com/discordjs/discord.js/commit/d1ec8c37ffb7fe3b63eaa8c382f22ca1fb348c9b)) +- **VoiceChannel:** Add support for text in voice (#6921) ([4ba0f56](https://github.com/discordjs/discord.js/commit/4ba0f56b6af64bac30eea807fb3e9f3c41c3c83c)) +- **SelectMenu:** Allow emojis in options and option constructors (#7797) ([f22245e](https://github.com/discordjs/discord.js/commit/f22245e9d072ac4ef63b0ae0d84d5ba94608ce22)) +- Allow `createMessageComponentCollector` without using `fetchReply` (#7623) ([a58556a](https://github.com/discordjs/discord.js/commit/a58556adc02b2b9239c8f277a4387c743c9d6f04)) +- Add guild directory support (#6788) ([b01f414](https://github.com/discordjs/discord.js/commit/b01f4147d4f3bca021bc269c9f06463f06e3db53)) +- **GuildBanManager:** Support pagination results (#7734) ([fc2a8bb](https://github.com/discordjs/discord.js/commit/fc2a8bb6750919ecd6ee7c872df05f4b677ff5d3)) +- **CommandInteraction:** Add support for localized slash commands (#7684) ([01a423d](https://github.com/discordjs/discord.js/commit/01a423d110cfcddb3d794fcc32579a1547dd472d)) +- Allow emoji strings to be passed through constructors (#7718) ([0faac04](https://github.com/discordjs/discord.js/commit/0faac04b69f1dda3dc860cd584af100e36a40917)) +- **StageInstanceManager:** Add `sendStartNotification` option to create (#7730) ([29f8807](https://github.com/discordjs/discord.js/commit/29f88079559cc02ccfef7a7c16458d481e573fb5)) +- Add `makeURLSearchParams` utility function (#7744) ([8eaec11](https://github.com/discordjs/discord.js/commit/8eaec114a98026024c21545988860c123948c55d)) +- **modal:** Add `awaitModalSubmit` (#7751) ([3037fca](https://github.com/discordjs/discord.js/commit/3037fca196a0f9238d53bb51394daf737bbf3742)) +- **Actions:** Add parent structure to events parameters (#7577) ([3f3e432](https://github.com/discordjs/discord.js/commit/3f3e4327c86da86734c19a96e97115bd505b4532)) +- Export `UnsafeModalBuilder` and `UnsafeTextInputBuilder` (#7628) ([6fec252](https://github.com/discordjs/discord.js/commit/6fec25239dfed46a30826d38dc97f3680f24ec65)) +- **VoiceChannel:** Support `video_quality_mode` (#7722) ([3b3dabf](https://github.com/discordjs/discord.js/commit/3b3dabf3da2e2f24b81967d68b581d7f7452273f)) +- Add API v10 support (#7477) ([72577c4](https://github.com/discordjs/discord.js/commit/72577c4bfd02524a27afb6ff4aebba9301a690d3)) +- **embed:** Remove Embed.setColor (#7662) ([9b0d8cb](https://github.com/discordjs/discord.js/commit/9b0d8cb2d8f7b55753de584eb3a3f347f87596c2)) +- **StageInstance:** Add support for associated guild event (#7576) ([3dff31f](https://github.com/discordjs/discord.js/commit/3dff31f63fe4afdcc818193d737e1917f1ac8105)) +- **VoiceState:** Add edit method (#7569) ([b162f27](https://github.com/discordjs/discord.js/commit/b162f27e46524bfc64515969d753c6e8f30e6c40)) +- **ModalSubmitInteraction:** Add boolean properties (#7596) ([8907390](https://github.com/discordjs/discord.js/commit/89073903a253d9408839573502c72cae93fe70b6)) +- Add Modals and Text Inputs (#7023) ([ed92015](https://github.com/discordjs/discord.js/commit/ed920156344233241a21b0c0b99736a3a855c23c)) +- **discord.js:** Partial transition to undici (#7482) ([5158332](https://github.com/discordjs/discord.js/commit/51583320d3b0f6452cd96bad1021f2a57e4cc6f6)) +- **message:** Add `reason` on pin and unpin (#7520) ([00728f7](https://github.com/discordjs/discord.js/commit/00728f72b36123b607502624b4b02a02ee524d4a)) +- Re-export AuditLogEvent enum (#7528) ([6a2fa70](https://github.com/discordjs/discord.js/commit/6a2fa70b8e79a460be38916eeb605976ad6fe68b)) +- **options:** Add support for custom JSON transformers (#7476) ([dee27db](https://github.com/discordjs/discord.js/commit/dee27db35af379b0835f9fd5cc19563f7bf3dfc0)) +- Add CategoryChannelChildManager (#7320) ([5cf5071](https://github.com/discordjs/discord.js/commit/5cf5071061760c2f9c1e36d7648aef544b03323a)) + - **Co-authored-by:** Antonio Román <kyradiscord@gmail.com> +- Attachment application command option type (#7200) ([0034396](https://github.com/discordjs/discord.js/commit/003439671d359dcfe481446ef12b90bd71c57835)) +- **builders:** Add attachment command option type (#7203) ([ae0f35f](https://github.com/discordjs/discord.js/commit/ae0f35f51d68dfa5a7dc43d161ef9365171debdb)) +- **scheduledevents:** Add image option (#7436) ([fbc71ef](https://github.com/discordjs/discord.js/commit/fbc71ef6b668c4b1e2b065d9b65541d9303db0a0)) +- Add methods to managers (#7300) ([dd751ae](https://github.com/discordjs/discord.js/commit/dd751ae19da196cc2f90ccd35c7d8e99878daaf9)) +- **channel:** Add .url getter (#7402) ([f59d630](https://github.com/discordjs/discord.js/commit/f59d6305cb0cd0d154a909f18be76407c4d452d3)) +- **components:** Add unsafe message component builders (#7387) ([6b6222b](https://github.com/discordjs/discord.js/commit/6b6222bf513d1ee8cd98fba0ad313def560b864f)) +- **thread:** Add `newlyCreated` to `threadCreate` event (#7386) ([51beda5](https://github.com/discordjs/discord.js/commit/51beda56f74e44ed013b5d25044b8d5fd1978b29)) +- **channel:** Add isDMBased typeguard (#7362) ([388f535](https://github.com/discordjs/discord.js/commit/388f53550cca7ded7350a050fda03c36e4c1fdf7)) +- **`Interaction`:** Add `.commandType` property to `CommandInteraction` and `AutocompleteInteraction` (#7357) ([567db60](https://github.com/discordjs/discord.js/commit/567db60475c8704661b2e788c9905ef364d6c00c)) +- **scheduledevent:** Add support for event cover images (#7337) ([355f579](https://github.com/discordjs/discord.js/commit/355f579771771a28a293c327a38574c8918d18f8)) +- **enumResolvers:** Strengthen typings (#7344) ([9a566e8](https://github.com/discordjs/discord.js/commit/9a566e8068f28fce87c07861ef1d2877c6ae105f)) +- Allow setting message flags when sending (#7312) ([706db92](https://github.com/discordjs/discord.js/commit/706db9228a91ef42e49d2ec749eac153b9ef75d0)) +- **minor:** Add application_id to Webhook (#7317) ([5ccdb0a](https://github.com/discordjs/discord.js/commit/5ccdb0ab266e4f74c331386ac2d6dd32bc225c62)) +- **threadchannel:** Add `createdTimestamp` field (#7306) ([9a16234](https://github.com/discordjs/discord.js/commit/9a1623425ae2d69f5c16f0096af4951ff5096e80)) +- **GuildPreview:** Add stickers (#7152) ([cf25de9](https://github.com/discordjs/discord.js/commit/cf25de9373df98b3c1cd0ca0a092d9dc8172929d)) +- Enum resolvers & internal enum string removal (#7290) ([213acd7](https://github.com/discordjs/discord.js/commit/213acd799738b888d550cdf3f08906764f8288e0)) +- **guildemojimanager:** Add `delete` and `edit` methods (#7286) ([9181a31](https://github.com/discordjs/discord.js/commit/9181a31e0ba330502052c94da544bb15c8b66f11)) +- **interaction:** Add `isRepliable` type guard (#7259) ([da05a88](https://github.com/discordjs/discord.js/commit/da05a8856b11cc1bf0df424c88a1cf9573e5b654)) +- **Channel:** Improve typeguards (#6957) ([37a22e0](https://github.com/discordjs/discord.js/commit/37a22e04c27724c2a65b05c701e3000ba3653ba1)) +- Add Locales to Interactions (#7131) ([9052e32](https://github.com/discordjs/discord.js/commit/9052e321d1c9c8841962d4e8dc5d9e060b104438)) +- **Permissions:** Remove deprecated thread-related permissions (#6755) ([ab3ff5a](https://github.com/discordjs/discord.js/commit/ab3ff5a262caf7d6225b8d6b54ab2c6b6613c0d0)) +- **VoiceRegion:** Remove the unsent vip field (#6759) ([caaef53](https://github.com/discordjs/discord.js/commit/caaef53dd97ecac9f714072ddba5ae9a99ab1027)) +- **richpresenceassets:** Add YouTube and custom image support (#7184) ([d06d70c](https://github.com/discordjs/discord.js/commit/d06d70ccf26c04c1122fac8430922588a489f95e)) +- **Collector:** Yield all collected values (#7073) ([2b480cb](https://github.com/discordjs/discord.js/commit/2b480cb14e6f52855efcb372da7fb455c15b13b1)) + +## Refactor + +- **Util:** Rename `fetchRecommendedShards` (#8298) ([cafde77](https://github.com/discordjs/discord.js/commit/cafde77d73452d729ba8e2cb1cac3f14235b889b)) +- **Embed:** Add all the types (#8254) ([64f8140](https://github.com/discordjs/discord.js/commit/64f814066cc4adebaca47eb8d7a2040a8df399ae)) +- **rest:** Add content-type(s) to uploads (#8290) ([103a358](https://github.com/discordjs/discord.js/commit/103a3584c95a7b7f57fa62d47b86520d5ec32303)) +- Make `GuildAuditLogsEntry.action` return an `AuditLogEvent` (#8256) ([f0b68d5](https://github.com/discordjs/discord.js/commit/f0b68d57368d7ac3db97925df68c11a945ccd84c)) +- **builder:** Remove `unsafe*Builder`s (#8074) ([a4d1862](https://github.com/discordjs/discord.js/commit/a4d18629828234f43f03d1bd4851d4b727c6903b)) +- Make `ShardEvents` the events of `Shard` (#8185) ([c5750d5](https://github.com/discordjs/discord.js/commit/c5750d59f529ab48a5bc88a73a1c449ef6ddbffd)) +- **Util:** Make single `replace` call in `cleanContent` (#8210) ([6b20645](https://github.com/discordjs/discord.js/commit/6b206457400ce31d566b02a0c135042afb540853)) +- **ApplicationCommandManager:** Use `makeURLSearchParams` (#8196) ([cb3dca4](https://github.com/discordjs/discord.js/commit/cb3dca4ae029724421f3d04a784ace0ae2de75e2)) +- Use `Base` prefix for channel and interaction base classes (#8099) ([e24970e](https://github.com/discordjs/discord.js/commit/e24970e3c3d24f71ba711e59666cd8a49a33e33b)) +- **Constants:** Remove leftover code (#8156) ([cd17aad](https://github.com/discordjs/discord.js/commit/cd17aad720430d23af51c364caeb8b22bf6cb6b5)) +- Errors (#8068) ([e68effa](https://github.com/discordjs/discord.js/commit/e68effa822f064a324ed5b92e797c9fc3ce5e211)) +- **ClientOptions:** Remove `$` prefix from `ws.properties` keys (#8094) ([90a98fe](https://github.com/discordjs/discord.js/commit/90a98fee16b7d1d06768461f4e85127c0edf8419)) +- Use `GuildFeature` enum (#8101) ([e5ec1c4](https://github.com/discordjs/discord.js/commit/e5ec1c4dbc3fa54b2c43d1fec24932d7363e17cb)) +- **util:** Make utility functions top level (#8052) ([e53d162](https://github.com/discordjs/discord.js/commit/e53d1621986035b0c92a1782f6e013d408480e00)) +- **ApplicationCommand:** Permissions v2 (#7857) ([c7391db](https://github.com/discordjs/discord.js/commit/c7391db11b3efd4b1a6904affb26887ad06d6db4)) +- ***:** Include name/reason/etc fields into options/data params (#8026) ([9c8b310](https://github.com/discordjs/discord.js/commit/9c8b3102ce00d1f2c1255c150fb3030f8b6dd026)) +- **ThreadMemberManager:** Consistent thread member fetching (#8021) ([da9107c](https://github.com/discordjs/discord.js/commit/da9107c007536952107bd92943b6c714538d5aeb)) +- **interactions:** Remove redundant interaction typeguards (#8027) ([f57d676](https://github.com/discordjs/discord.js/commit/f57d6768ad24f6e37dc598f9c93709449d3bc4dd)) +- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a)) +- **channel:** Remove redundant channel type guards (#8012) ([70c733b](https://github.com/discordjs/discord.js/commit/70c733bb9a5bde0f79e6bea0bdc416458bda4c06)) +- Always return `Message` instances in interactions (#7917) ([9720e55](https://github.com/discordjs/discord.js/commit/9720e555340431c3b3ad7bd670ad0ac7eee8865f)) +- **attachment:** Don't return attachment builders from API (#7852) ([dfadcbc](https://github.com/discordjs/discord.js/commit/dfadcbc2fd50be64c8a0c1cae3be10f83678c5ee)) +- Clean up modal submissions (#7994) ([643dab3](https://github.com/discordjs/discord.js/commit/643dab3b1b5305d002fcefed62755bbe11fc3267)) +- **ThreadChannel:** Remove `MAX` helper from threads (#7846) ([dfd9eb2](https://github.com/discordjs/discord.js/commit/dfd9eb20b2d3e0e7db26744b1f15134ac6eda139)) +- **Activity:** Remove undocumented properties (#7844) ([5ba7740](https://github.com/discordjs/discord.js/commit/5ba7740fcfefda1eeba81ace4e6351eac02522a4)) +- **MessageAttachment:** Use `Attachment` instead (#7691) ([ab4c608](https://github.com/discordjs/discord.js/commit/ab4c608b97ff319935e1a7f23564622bfd7ddd57)) +- **Util:** Remove splitting (#7780) ([54e5629](https://github.com/discordjs/discord.js/commit/54e56299865a6746744544ba25d5540a1166d27c)) +- Tidy up builders and components (#7711) ([96a0d83](https://github.com/discordjs/discord.js/commit/96a0d83a1366703ecae40b5e0d5171be9123d079)) +- Remove nickname parsing (#7736) ([78a3afc](https://github.com/discordjs/discord.js/commit/78a3afcd7fdac358e06764cc0d675e1215c785f3)) +- Remove store channels (#7634) ([aedddb8](https://github.com/discordjs/discord.js/commit/aedddb875e740e1f1bd77f06ce1b361fd3b7bc36)) +- **IntegrationApplication:** Remove `summary` (#7729) ([eb6b472](https://github.com/discordjs/discord.js/commit/eb6b472f72488cad7e96befccc00270cf6dc01b8)) +- **GuildAuditLogs:** Remove build (#7704) ([cedd053](https://github.com/discordjs/discord.js/commit/cedd0536baa1301984daf89dfda4e63a7be595a2)) +- **InteractionCollector:** Simplify constructor logic (#7667) ([07b23a9](https://github.com/discordjs/discord.js/commit/07b23a99c7088a7c740f23051f3f755f091519b0)) +- Remove undocumented checks (#7637) ([9a6e691](https://github.com/discordjs/discord.js/commit/9a6e691eaa6c3d133098b2734414590cb838de2e)) +- Allow builders to accept emoji strings (#7616) ([fb9a9c2](https://github.com/discordjs/discord.js/commit/fb9a9c221121ee1c7986f9c775b77b9691a0ae15)) +- Use `static` fields (#7701) ([e805777](https://github.com/discordjs/discord.js/commit/e805777a7a81d1dc7a2edd9741ecb04e685a3886)) +- **EmbedBuilder:** Allow hex strings in setColor (#7673) ([f472975](https://github.com/discordjs/discord.js/commit/f4729759f600372455f062c75859f084e23a5d78)) +- Don't return builders from API data (#7584) ([549716e](https://github.com/discordjs/discord.js/commit/549716e4fcec89ca81216a6d22aa8e623175e37a)) +- **embed:** Allow hex strings in `setColor()` (#7593) ([79d6c04](https://github.com/discordjs/discord.js/commit/79d6c0489c3d563fdd05de63c4fcf93a6deefce1)) +- **InteractionResponses:** Use ClientOptions.jsonTransformer (#7599) ([fac55bc](https://github.com/discordjs/discord.js/commit/fac55bcfd1e8b76aae1273415f74fa6de7aca66d)) +- Deprecate invite stage instance (#7437) ([d2bc9d4](https://github.com/discordjs/discord.js/commit/d2bc9d444f42a70a3c4cc4c68eb107bcaebec509)) +- **guild:** Move `premiumSubscriptionCount` to `AnonymousGuild` (#7451) ([6d3da22](https://github.com/discordjs/discord.js/commit/6d3da226d3c003d137639e719394a807330e4844)) +- **actions:** Use optional chaining (#7460) ([d1bb362](https://github.com/discordjs/discord.js/commit/d1bb36256f2f86022884e6ee9e05b0536cb6384d)) +- **guildbanmanager:** Rename days option to deleteMessageDays (#7447) ([0dfdb2c](https://github.com/discordjs/discord.js/commit/0dfdb2cf11e236e67dd34277108973b5b79790a8)) +- Make public builder props getters (#7422) ([e8252ed](https://github.com/discordjs/discord.js/commit/e8252ed3b981a4b7e4013f12efadd2f5d9318d3e)) +- Remove redundant API defaults (#7449) ([532846b](https://github.com/discordjs/discord.js/commit/532846b1f8260d85022a022d093553310052afc9)) +- Allow discord.js builders to accept camelCase (#7424) ([94bf727](https://github.com/discordjs/discord.js/commit/94bf727cc3a2f11c88e95cdb151b235f775cd1ca)) +- Replace `WSCodes`, `WSEvents`, and `InviteScopes` with `discord-api-types` equivalent (#7409) ([cc25455](https://github.com/discordjs/discord.js/commit/cc25455d2c75177e3eddc880b7fd53cb122387c4)) +- Make constants enums top level and `PascalCase` (#7379) ([d8184f9](https://github.com/discordjs/discord.js/commit/d8184f94dd08daab37195f52828e06af5ed1c1e0)) +- **`Bitfield`:** Use discord-api-types enums instead (#7313) ([fbb1d03](https://github.com/discordjs/discord.js/commit/fbb1d0328bcd517027ad2eedb8753d17489ed851)) +- Use `@discordjs/rest` (#7298) ([ec0fba1](https://github.com/discordjs/discord.js/commit/ec0fba1ed0d3c5b1bb18171ece6fe5ee42d48497)) +- Switch to /builders `Embed` (#7067) ([d2d3a80](https://github.com/discordjs/discord.js/commit/d2d3a80c556a104099a1ddb1b24f1b921c553257)) +- Remove transformPermissions (#7303) ([b4ed8fd](https://github.com/discordjs/discord.js/commit/b4ed8fd3ed953085cd908b2845d4384c8555d3a2)) +- Remove VoiceChannel#editable (#7291) ([164589c](https://github.com/discordjs/discord.js/commit/164589c5516a847457444d11098981d557b6778b)) +- Remove boolean option for `Webhook#fetchMessage` (#7293) ([347ff80](https://github.com/discordjs/discord.js/commit/347ff80bbc9bc5243b7f68ba5d745782eadeba21)) +- **subcommandgroup:** Required default to false (#7217) ([6112767](https://github.com/discordjs/discord.js/commit/6112767128a664f32205425f52ba52220d57834f)) +- **invite:** Make `channel` and `inviter` getters (#7278) ([18b0ed4](https://github.com/discordjs/discord.js/commit/18b0ed4cbe8285637a971c7c99ee49d18060a403)) +- Remove required from getMember (#7188) ([c90e47f](https://github.com/discordjs/discord.js/commit/c90e47f90403e5b1b3499b213dcdf2704fd96b66)) +- Remove djs components and use /builders components instead (#7252) ([101d7c5](https://github.com/discordjs/discord.js/commit/101d7c5ffa03edcf8cb8a0647b77d5c9a38e4bdd)) +- Default *URL methods to animated hash (#7149) ([7c07976](https://github.com/discordjs/discord.js/commit/7c07976018728154be0ce0314d3e8dfe8eb9ed5b)) +- Use setPosition inside edit (#7263) ([0b23b7f](https://github.com/discordjs/discord.js/commit/0b23b7f0394a20596c8d85b82870c3f35ea6b0e0)) +- Don't disable import order lint (#7262) ([0a5d5f3](https://github.com/discordjs/discord.js/commit/0a5d5f38c0b1a249fa2efe16f3b601c90622a4d5)) +- Remove discord.js enums and use discord-api-types enums instead (#7077) ([aa6d1c7](https://github.com/discordjs/discord.js/commit/aa6d1c74de01dd9a8f020c43fb2c193c4729df8d)) +- **application:** Remove fetchAssets (#7250) ([1479e40](https://github.com/discordjs/discord.js/commit/1479e40bcecc4c28ecb9f05fa4fbbdfe3bd387e1)) +- PresenceUpdate and demuxProbe (#7248) ([1745973](https://github.com/discordjs/discord.js/commit/174597302408f13c5bb685e2fb02ae2137cb481d)) +- **embeds:** Don't create new embed instances when unnecessary (#7227) ([822dc67](https://github.com/discordjs/discord.js/commit/822dc678da626de7b4fb22a747cd3cd2e8376732)) +- **GuildMember:** Throw better errors on #kickable and #bannable (#7137) ([4fd127e](https://github.com/discordjs/discord.js/commit/4fd127e79edfa1851f8a10242838f9d7aa68c8c3)) +- **SnowflakeUtil:** Switch to `@sapphire/snowflake` (#7079) ([e082dfb](https://github.com/discordjs/discord.js/commit/e082dfb1584926e4c05face5966d16e4a2921bc5)) +- **InteractionCreate:** Remove interaction event (#6326) ([ae876d9](https://github.com/discordjs/discord.js/commit/ae876d962453ccf843f8e6f70666a98a3173bb75)) +- **MessageCreate:** Remove message event (#6324) ([171e917](https://github.com/discordjs/discord.js/commit/171e917fb96b6bf39a6ad70e83be646f72fe451e)) +- **integration:** Turn undefined into null and consistency (#7209) ([13eb782](https://github.com/discordjs/discord.js/commit/13eb78256da901e6c3c405f546f36617ef5e8239)) +- Remove `deleted` field (#7092) ([cee7fd1](https://github.com/discordjs/discord.js/commit/cee7fd181c464e44eabf20b511d12589f2453722)) +- **Dates:** Save timestamps everywhere and use Date.parse (#7108) ([55e21f5](https://github.com/discordjs/discord.js/commit/55e21f53663a91863c63b6d9f3a8c35564664061)) +- **RoleManager:** Remove `comparePositions()` (#7201) ([fbbac27](https://github.com/discordjs/discord.js/commit/fbbac279789427b2c36869dc47b65fb08431e14d)) +- Better Command Terminology (#7197) ([b7856e7](https://github.com/discordjs/discord.js/commit/b7856e7809ff6fa21fe00286f885808535624f7c)) +- **Actions:** Remove deleted maps (#7076) ([5022b14](https://github.com/discordjs/discord.js/commit/5022b14da09e9b421f947e9bc385a0574cbf07d1)) +- **Client:** Remove applicationCommand events (#6492) ([6085b4f](https://github.com/discordjs/discord.js/commit/6085b4f72723d4ff82f7fea504241d14c94af21e)) +- Remove `Util.removeMentions()` (#6530) ([0c24cc8](https://github.com/discordjs/discord.js/commit/0c24cc8ec0d818315cc8f8bcf74fce060847ac79)) +- **Constants:** Change APPLICATION_COMMAND -> CHAT_INPUT_COMMAND (#7018) ([75616a3](https://github.com/discordjs/discord.js/commit/75616a305f9af33013486b13a872a39212101ce7)) +- **Guild:** Remove deprecated setXPositions methods (#6897) ([43e5e3c](https://github.com/discordjs/discord.js/commit/43e5e3c339a96fa895267d4538eee1d5e5843d05)) +- **UserFlags:** Update flag names (#6938) ([b246fc4](https://github.com/discordjs/discord.js/commit/b246fc4101b8e4957ffd1af8e2e4986a020ca211)) + +## Styling + +- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629)) + +## Typings + +- **GuildFeature:** Allow feature strings to be passed (#8264) ([b7d4e55](https://github.com/discordjs/discord.js/commit/b7d4e55419207d4e25f5c40cab221c7c04a617bf)) +- **CategoryChannelChildManager:** Fix Holds type (#8288) ([33a7a5c](https://github.com/discordjs/discord.js/commit/33a7a5cbdc00d2a5034dc1ec91fec5da7042f9d0)) +- Remove `MemberMention` (#8292) ([bf65b37](https://github.com/discordjs/discord.js/commit/bf65b37d1a9ea8417e26ad4afacea1eb45a0ff5a)) +- **GuildMemberManager:** Fix placement for `fetchMe()` (#8258) ([7525615](https://github.com/discordjs/discord.js/commit/75256153a9923d94ca709a37aaccc48dfb43c153)) +- Convert `Events` to an enum (#8246) ([feb3bdd](https://github.com/discordjs/discord.js/commit/feb3bdda0a3c3da80378c8cbcafca2968551eef9)) +- **GuildMemberManager:** Non-void return of `edit()` (#8186) ([c7a205f](https://github.com/discordjs/discord.js/commit/c7a205f7b992eea43af13a4638e2a03db7bc0d8a)) +- Add missing shard types (#8180) ([27d8deb](https://github.com/discordjs/discord.js/commit/27d8deb4716a87704370a95103b16fa1b763de18)) +- Implement `GuildChannelEditOptions` (#8184) ([b83e0c0](https://github.com/discordjs/discord.js/commit/b83e0c0caffc2b767aa1ba4412580970a6901899)) +- **Status:** Add missing members (#8179) ([8421f92](https://github.com/discordjs/discord.js/commit/8421f9203bd2d85ef8e64c3fb9a991c74223a75d)) +- **GuildScheduledEvent#scheduledStartAt:** Should be nullish (#8111) ([65dc8d6](https://github.com/discordjs/discord.js/commit/65dc8d677ee81469c0eeb4ecdd83fe2f68cc8982)) +- Fix modal builder constructor data type (#8143) ([7279f9c](https://github.com/discordjs/discord.js/commit/7279f9c31b14bc1e78c63b7298e80e37ca5dfe0c)) +- Use `ThreadAutoArchiveDuration` from discord-api-types (#8145) ([a3799f9](https://github.com/discordjs/discord.js/commit/a3799f9ebb027904830457119708d550e2009200)) +- **Shard#reconnecting:** Fix event name (#8118) ([95e6d6e](https://github.com/discordjs/discord.js/commit/95e6d6ede03c4fb92a8d8027a085e84b043fd895)) +- **ApplicationCommand:** Fix typo in setDMPermission (#8097) ([4df491c](https://github.com/discordjs/discord.js/commit/4df491ce8578a1b01ee8412a4df8137a302e7202)) +- Fix `setType()` parameter and `ChannelData.type` (#8089) ([b4e28a8](https://github.com/discordjs/discord.js/commit/b4e28a8ff6bf165c54a8726d3bc3a3cc0c1e469b)) +- Fix `ApplicationCommandPermissionsUpdate` event typings (#8071) ([9964454](https://github.com/discordjs/discord.js/commit/9964454c2944a0523399481a5f609144486e549b)) +- **AutocompleteOption:** Fix and improve types (#8069) ([476b7d5](https://github.com/discordjs/discord.js/commit/476b7d519c719152ea04e207f6dd09bb23e733db)) +- **ThreadMemberManager:** Fix return type of fetching members with no arguments (#8060) ([2392a6f](https://github.com/discordjs/discord.js/commit/2392a6f5de2efcf6b326173d26295c928b94adb6)) +- Remove isAutocomplete typeguard from typings (#8063) ([c0f079d](https://github.com/discordjs/discord.js/commit/c0f079d2325a636c83ac676c525bfa89ce308b3c)) +- **AttachmentBuilder:** Fix data type (#8016) ([7fa698d](https://github.com/discordjs/discord.js/commit/7fa698d23e548987762c4c66c96c510d9ea56eb4)) +- **modal:** Fix `showModal()` typings (#8014) ([0ccc243](https://github.com/discordjs/discord.js/commit/0ccc243c8ffbf852660c899cc2ad47bd5ebb65cb)) +- Fix some attachment related typings (#8013) ([6aa6232](https://github.com/discordjs/discord.js/commit/6aa623240ee94b117c7e69c1d09b50923a8f7a4c)) +- **AttachmentBuilder:** Remove name parameter from constructor (#8008) ([6266b0c](https://github.com/discordjs/discord.js/commit/6266b0c1e323f9522010f90f34ce6f17fcb6e769)) +- Add types to `EventEmitter` static methods (#7986) ([d60c464](https://github.com/discordjs/discord.js/commit/d60c464e618e4159d2656e7832798909832f33cd)) +- Nullify `guildScheduledEventUpdate`'s old parameter (#7955) ([fdeac9d](https://github.com/discordjs/discord.js/commit/fdeac9d9fba06c532eca296ddd8479047bc732bf)) +- Make `CacheType` generic more accurate for return values (#7868) ([e07b910](https://github.com/discordjs/discord.js/commit/e07b910e684bc3cf71fb93417951ad42351bace4)) +- **guildScheduledEvent:** Mark `entityMetadata` as nullable (#7908) ([64bdf53](https://github.com/discordjs/discord.js/commit/64bdf53116945ffb51764bb8ec539d530aefcfb1)) +- **discord.js:** Export missing enums (#7864) ([5eeef3f](https://github.com/discordjs/discord.js/commit/5eeef3f708eb900ec994d837fb4cd414a4f4b437)) +- Fix return type of `toString()` on channels (#7836) ([ece6289](https://github.com/discordjs/discord.js/commit/ece628986c7eb1a66f46076d8f8518c9ff00aaf3)) +- **Message#activity:** Make `partyId` optional and use enum for `type` (#7845) ([bfeaf85](https://github.com/discordjs/discord.js/commit/bfeaf856f76eb7cb756ac55aac13636ccdb345b6)) +- Cleanup *Data type definitions (#7716) ([585169f](https://github.com/discordjs/discord.js/commit/585169f2f097ffb1940d17f549e4290aa55acde2)) +- Fix BooleanCache never resolving to true (#7809) ([440ac24](https://github.com/discordjs/discord.js/commit/440ac243ca1d6f8cd04603e63e3f2f6ea1722ee8)) +- **CommandInteraction:** Add awaitModalSubmit (#7811) ([a6d9ce5](https://github.com/discordjs/discord.js/commit/a6d9ce57c6cae90d0afc60010cad44fdc2c2d06c)) +- **ThreadChannel:** Fix autoArchiveDuration types (#7816) ([0857476](https://github.com/discordjs/discord.js/commit/08574763eb665b5a43ccfb826929f1e3f0d1c3a7)) +- Add missing typing (#7781) ([f094e33](https://github.com/discordjs/discord.js/commit/f094e338617a1a3c9f48a325e4b8e9b5a405aa91)) +- **VoiceChannel:** Nullify property (#7793) ([446eb39](https://github.com/discordjs/discord.js/commit/446eb390ce58b7e7f60e297b25f53773a55f7fb9)) +- **ModalSubmitInteraction:** Message (#7705) ([b577bcc](https://github.com/discordjs/discord.js/commit/b577bcc1df5c6424fef9984e19a5f11c77371cf3)) +- **Embed:** Add missing getters and add video to EmbedData (#7728) ([fd1dc72](https://github.com/discordjs/discord.js/commit/fd1dc72c0a77dbe18753d8db22972dfa5fe4ab36)) +- **ModalSubmitInteraction:** Fix `components` type (#7732) ([6f4e97b](https://github.com/discordjs/discord.js/commit/6f4e97bfafe4a058f6ec85d321676401d701ee55)) +- **interactionCollector:** Filter should have a collected argument (#7753) ([e4f2705](https://github.com/discordjs/discord.js/commit/e4f27051ca921d299c302b600a8c2917e9356ef6)) +- Fix regressions (#7649) ([5748dbe](https://github.com/discordjs/discord.js/commit/5748dbe08783beb80c526de38ccd105eb0e82664)) +- **Constants:** Add `NonSystemMessageTypes` (#7678) ([9afc030](https://github.com/discordjs/discord.js/commit/9afc03054e4c8973702d6c18e618643f76382dd9)) +- Fix auto archive duration type (#7688) ([8e3b2d7](https://github.com/discordjs/discord.js/commit/8e3b2d7abd38136534969cf77c6a748ee3a20355)) +- **InteractionResponseFields:** Add webhook (#7597) ([daf2829](https://github.com/discordjs/discord.js/commit/daf2829cb58d1a44cb1f1ece21e428d1a23e99c9)) +- **Embed:** Add forgotten `footer` type (#7665) ([8fb9816](https://github.com/discordjs/discord.js/commit/8fb98165a9d098ab316475d6baacb015783eb638)) +- **ColorResolvable:** Simplify string types (#7643) ([2297c2b](https://github.com/discordjs/discord.js/commit/2297c2b9479ace16f5f7155479605a4ac2718e3d)) +- Allow component classes in action row data (#7614) ([230c0c4](https://github.com/discordjs/discord.js/commit/230c0c4cb137882ff7bab783a4aeaa83ae941de5)) +- **ActionRow:** Allow components to be passed to constructors (#7531) ([e71c76c](https://github.com/discordjs/discord.js/commit/e71c76c7f795837dbcc3576e507bd286640b4296)) +- **showModal:** Align types with the documentation (#7600) ([0d7e4ed](https://github.com/discordjs/discord.js/commit/0d7e4edd969513692c061c107be4bbe7e4b54321)) +- Modals type and doc fixes (#7608) ([93854a8](https://github.com/discordjs/discord.js/commit/93854a8013d07234cb849bfcbfa99f74a4c3cdb4)) +- **InteractionResponseFields:** Add boolean properties (#7565) ([53defb8](https://github.com/discordjs/discord.js/commit/53defb82e36108468e35077b887ee28b811891ab)) +- Allow raw components for reply and message options (#7573) ([2d4971b](https://github.com/discordjs/discord.js/commit/2d4971b032a01c05b55c93d6475e61b0d25d69d3)) +- Fix component *Data types (#7536) ([a8321d8](https://github.com/discordjs/discord.js/commit/a8321d8026df2e6a09d867939986bf77f894f3a8)) +- Use discord-api-types `Locale` (#7541) ([8346003](https://github.com/discordjs/discord.js/commit/83460037be840ba623f3b02a3e6f218943f9d2b7)) +- **anychannel:** Add PartialGroupDMChannel (#7472) ([cf66930](https://github.com/discordjs/discord.js/commit/cf669301c7be8eaecf91d7f764eccc67d7a5b4c6)) +- Remove `ApplicationCommandInteractionOptionResolver` (#7491) ([71f4fa8](https://github.com/discordjs/discord.js/commit/71f4fa82ed6206d6843345a5394119f2a728aa35)) +- **embed:** Fix timestamp allowed types (#7470) ([7959a68](https://github.com/discordjs/discord.js/commit/7959a68d8ec600af248f5506f39871cae7eeeb04)) +- Remove duplicate rate limit for thread creation (#7465) ([2d2de1d](https://github.com/discordjs/discord.js/commit/2d2de1d3fd15a098d69e09710e9a7a3352234fef)) +- Correct types for InteractionCollector guild and channel (#7452) ([6ce906a](https://github.com/discordjs/discord.js/commit/6ce906a02fcb051cb6df3e9f453ba9f53db03bd0)) +- Fix `GuildAuditLogsTypes` keys & typos (#7423) ([3d8c776](https://github.com/discordjs/discord.js/commit/3d8c77600be51a86a99b526078bb1b1fcb9a0811)) +- Remove duplicate `GuildChannelOverwriteOptions` interface (#7428) ([83458ff](https://github.com/discordjs/discord.js/commit/83458ff7c782b8efdaaac931d2dee1764dad25bf)) +- Use `GuildFeature` enum from `discord-api-types` (#7397) ([a7b80b9](https://github.com/discordjs/discord.js/commit/a7b80b9d9bf4902bd85b592986771eadf7a765dc)) +- Fix *BitField.Flags properties (#7363) ([e6a26d2](https://github.com/discordjs/discord.js/commit/e6a26d25b3cf8dfcc8aa8997b021f1774f3b754b)) +- Fix MessageMentions channel types (#7316) ([c05b388](https://github.com/discordjs/discord.js/commit/c05b38873bb3c37c6e4ebcb6b6373a8858cc03de)) +- Fix channel create overloads (#7294) ([1c6c944](https://github.com/discordjs/discord.js/commit/1c6c9449ad68601c6c98748d73be8114401d38ef)) +- Fix regressions and inconsistencies (#7260) ([26a9dc3](https://github.com/discordjs/discord.js/commit/26a9dc32062cd071917bbe7264050315b4d6dd3c)) +- **interaction:** Remove renamed typeguards (#7220) ([68b9564](https://github.com/discordjs/discord.js/commit/68b9564f1821726377a1e929a3ca1fc65b4ad598)) +- AssertType -> expectType ([3f36746](https://github.com/discordjs/discord.js/commit/3f36746561a40cd61a7cd2e054b7ef80d58fc707)) +- Fix cache types resolving to `never` (#7164) ([c978dbb](https://github.com/discordjs/discord.js/commit/c978dbb6233bcd85408caf0bca7619c9c5d508f0)) + +# [14.12.1](https://github.com/discordjs/discord.js/compare/14.12.0...14.12.1) - (2023-08-01) + +## Bug Fixes + +- **BaseClient:** Fix destroy method (#9742) ([1af7e5a](https://github.com/discordjs/discord.js/commit/1af7e5a0bb4eca35221cb342c1c53dc18263c789)) + +# [14.12.0](https://github.com/discordjs/discord.js/compare/14.11.0...14.12.0) - (2023-07-31) + +## Bug Fixes + +- **ChannelUpdate:** Check against unknown channels (#9697) ([7fb91c5](https://github.com/discordjs/discord.js/commit/7fb91c57f72b74395d67f2207246033c703f1f19)) +- **Action:** Use existing recipients if available (#9653) ([719e54a](https://github.com/discordjs/discord.js/commit/719e54a921f74890519f066a9f56e52fdcfacf07)) +- Everyone role members (#9685) ([0803eb5](https://github.com/discordjs/discord.js/commit/0803eb562bdc7644fa611a0a87dea3e8b0d4c7af)) +- `awaitMessageComponent` with `MessageComponentInteraction`s (#8598) ([b61e4fb](https://github.com/discordjs/discord.js/commit/b61e4fb0dcb9e5d43a7626c5a4760f5801e06fae)) +- **ThreadManager:** Fix internal crash upon conditionally resolving thread members (#9648) ([a6dbe16](https://github.com/discordjs/discord.js/commit/a6dbe163dd3df12ad98465b1dfc040b8eff8805e)) +- **User:** Check global name in equals (#9631) ([8f3bd38](https://github.com/discordjs/discord.js/commit/8f3bd3807233fca2a057948406bdc8aef008b6cb)) +- **WebSocketManager:** Await WebSocket destroy (#9519) ([75308f2](https://github.com/discordjs/discord.js/commit/75308f266933454301b10ee8e1d940d782fdb637)) +- **Client:** Safe call for possibly null WebSocket (#9600) ([24a6149](https://github.com/discordjs/discord.js/commit/24a61495b9bf07887dd535a05ffbec2895faa888)) +- **ThreadManager:** Ensure `fetchActive()` only returns active threads in a channel (#9568) ([53aa24d](https://github.com/discordjs/discord.js/commit/53aa24d41809382c1af57bd1871107c8359e4a15)) +- **LimitedCollection:** Allow items to be stored if keepOverLimit is true when maxSize is 0 (#9534) ([9345d1b](https://github.com/discordjs/discord.js/commit/9345d1b1ac4f7b1f66b919602dff995782151407)) +- **AutocompleteInteraction:** Prevent snake casing of locales (#9565) ([7196fe3](https://github.com/discordjs/discord.js/commit/7196fe36e8089dde7bcaf0db4dd09cf524125e0c)) + +## Documentation + +- Change `Channel` to `BaseChannel` (#9718) ([e5effb6](https://github.com/discordjs/discord.js/commit/e5effb6f6a3e547006eb9bc054cc168844a157f2)) +- **BaseChannel:** Remove `APIChannel` (#9717) ([125405f](https://github.com/discordjs/discord.js/commit/125405f1cf11433c69ff1ae9d6b8f7e713fc37c0)) +- **BuildersSelectMenuOption:** Update link (#9690) ([ede9f4e](https://github.com/discordjs/discord.js/commit/ede9f4e5e203bcfb8820ae7ec3418482735ff9c1)) +- **ClientOptions:** Change default value of sweepers in docs (#9591) ([911e6ef](https://github.com/discordjs/discord.js/commit/911e6eff75f5d05e837d5dfaacf557d6594df16a)) +- **Client:** Correct invite gateway permission checks (#9597) ([e1b6eee](https://github.com/discordjs/discord.js/commit/e1b6eeed0e2e18f9900bc945c9f82d2d05f28a78)) +- Fix broken links to new documentation (#9563) ([d01e8aa](https://github.com/discordjs/discord.js/commit/d01e8aa8af00f5caacffe98caef3ead02e80a9bf)) + +## Features + +- Add ws option support for "buildIdentifyThrottler" (#9728) ([6307f81](https://github.com/discordjs/discord.js/commit/6307f813854ed9dc76d2c4351bd69dd0490d0928)) +- **Client:** Add `guildAvailable` event (#9692) ([3c85fb2](https://github.com/discordjs/discord.js/commit/3c85fb21e62b30e75a7200b704e242c3a0adeda1)) +- User avatar decorations (#8914) ([8d97017](https://github.com/discordjs/discord.js/commit/8d9701745840e23854e8f0b057d21cb10e7d1d54)) +- Add silent option to ShardingManager (#9506) ([df40dcd](https://github.com/discordjs/discord.js/commit/df40dcdb850c398642ebc5cd6e4c48034280f464)) +- **EmbedBuilder:** Add `.length` (#8682) ([53c17e0](https://github.com/discordjs/discord.js/commit/53c17e00c0668c3d1497142dde7384c058c46c64)) +- Guild onboarding (#9120) ([dc73c93](https://github.com/discordjs/discord.js/commit/dc73c938ff9d04a0d7d57630faeb8e81ea343006)) +- Add resume event in shard (#9650) ([a73d54e](https://github.com/discordjs/discord.js/commit/a73d54e43a01719f683e8fd21714e85ffe737add)) +- **presence:** Re-introduce image resolving for other platforms (#9637) ([73c2f8a](https://github.com/discordjs/discord.js/commit/73c2f8aa17aac51b05382444148cb1f60081ee03)) +- Add message to send resume event to shard (#9626) ([a873ec1](https://github.com/discordjs/discord.js/commit/a873ec1e8511829ba95e85bbc9a4074e40c76086)) +- Support new username system (#9512) ([1ab60f9](https://github.com/discordjs/discord.js/commit/1ab60f9da4d6b7ea144fa05b97b029a4bfaeede2)) +- **GuildAuditLogsEntry#extra:** Add missing `channel` property (#9518) ([2272321](https://github.com/discordjs/discord.js/commit/227232112d1cd9f211e177996b7cdee2940f471e)) + +## Performance + +- **Channel:** Linear speed position getter (#9497) ([09b0382](https://github.com/discordjs/discord.js/commit/09b0382c458ed0f3df5b8fa778c504b3e658ac49)) +- **Role:** Improve `members` getter (#9529) ([37181ab](https://github.com/discordjs/discord.js/commit/37181ab2322e48e17ff0d1040bcc510dc7c34e93)) + +## Refactor + +- **User:** Remove deprecation warning from tag (#9660) ([cf8012c](https://github.com/discordjs/discord.js/commit/cf8012c20022aff184d7bce0ad436c136e428d9c)) +- **GuildMember:** Make `_roles` property non-enumerable (#9387) ([46167a7](https://github.com/discordjs/discord.js/commit/46167a79d7d0cac5599459a31c33b2bbcf6e06da)) +- **rest:** Switch api to fetch-like and provide strategies (#9416) ([cdaa0a3](https://github.com/discordjs/discord.js/commit/cdaa0a36f586459f1e5ede868c4250c7da90455c)) + - **BREAKING CHANGE:** NodeJS v18+ is required when using node due to the use of global `fetch` + - **BREAKING CHANGE:** The raw method of REST now returns a web compatible `Respone` object. + - **BREAKING CHANGE:** The `parseResponse` utility method has been updated to operate on a web compatible `Response` object. + - **BREAKING CHANGE:** Many underlying internals have changed, some of which were exported. + - **BREAKING CHANGE:** `DefaultRestOptions` used to contain a default `agent`, which is now set to `null` instead. + +## Typings + +- **MessageManager:** Allow comparison of messages again (#9612) ([a48d0ef](https://github.com/discordjs/discord.js/commit/a48d0efb09613eac6bf3c1bd996f58f5fff7667c)) +- **AutoModerationActionExecution:** Add forum channels as a possible type in `channel()` (#9623) ([d64330a](https://github.com/discordjs/discord.js/commit/d64330a1570b3a2047ef959a6bce268372c70e99)) +- **ModalSubmitFields:** Components is an array (#9406) ([1cab79f](https://github.com/discordjs/discord.js/commit/1cab79f6fde6f367141c9f7ed91bcb70ed2e5c17)) +- Use `readonly` arrays and `const` type parameters in places (#9641) ([cd69868](https://github.com/discordjs/discord.js/commit/cd6986854f4c2d143d2cd9b81d096738480dfa63)) +- **BaseInteraction:** `appPermissions` not `null` in guilds (#9601) ([6c2242f](https://github.com/discordjs/discord.js/commit/6c2242f4f970b1c75c243f74ae64f30ecbf8ba0d)) + +# [14.11.0](https://github.com/discordjs/discord.js/compare/14.10.2...14.11.0) - (2023-05-06) + +## Bug Fixes + +- **WebSocketManager:** Properly emit shard error events (#9521) ([e627468](https://github.com/discordjs/discord.js/commit/e6274681fd10b0d75e1d3b448c94b50ec6810367)) +- **WebSocketManager:** Emit raw ws events again (#9502) ([c429763](https://github.com/discordjs/discord.js/commit/c429763be8e94f0f0cbc630e8bb1d415d46f1465)) + +## Documentation + +- **Client:** Update Sapphire's snowflake utility links (#9501) ([1b7981e](https://github.com/discordjs/discord.js/commit/1b7981e4696b8ae74ceffa876fc0a9be7d0b9f93)) + +## Features + +- **Guild:** Safety alerts channel and mention raid protection (#8959) ([6b2c3fb](https://github.com/discordjs/discord.js/commit/6b2c3fb9d0571de808e990cf064f73240ab93451)) + +## Performance + +- **Role:** Linear speed position getter (#9493) ([8e9a2b4](https://github.com/discordjs/discord.js/commit/8e9a2b4630f78bb9e45345ec2a16812bfac70a20)) + +## Refactor + +- **GuildChannel:** Simplify constructor (#9499) ([f2ad076](https://github.com/discordjs/discord.js/commit/f2ad0762c521422ab64e5b10344a6fd67961031b)) + +## Typings + +- **StringSelectMenuComponentData:** `options` is required (#9515) ([d7b18f0](https://github.com/discordjs/discord.js/commit/d7b18f0681d4147ff192c98108c035d6d0f96cce)) + +# [14.10.2](https://github.com/discordjs/discord.js/compare/14.10.1...14.10.2) - (2023-05-01) + +## Bug Fixes + +- Correct `isJSONEncodable()` import (#9495) ([201b002](https://github.com/discordjs/discord.js/commit/201b002ad405b845ace5f708077c1f157bb4126d)) +- **Client:** `generateInvite()` scope validation (#9492) ([b327f49](https://github.com/discordjs/discord.js/commit/b327f4925ff557e0aa8273d7f017aa616226ca06)) + +# [14.10.1](https://github.com/discordjs/discord.js/compare/14.10.0...14.10.1) - (2023-05-01) + +## Bug Fixes + +- **Client:** Spelling of InvalidScopesWithPermissions ([ac9bf3a](https://github.com/discordjs/discord.js/commit/ac9bf3ac06ec78dbaca2ce4a82cceb0d82484211)) + +## Refactor + +- **ShardClientUtil:** Logic de-duplication (#9491) ([a9f2bff](https://github.com/discordjs/discord.js/commit/a9f2bff82a18c6a3afdee99e5830e1d7b4da65dc)) + +# [14.10.0](https://github.com/discordjs/discord.js/compare/14.9.0...14.10.0) - (2023-05-01) + +## Bug Fixes + +- **ShardClientUtil:** Fix client event names (#9474) ([ad217cc](https://github.com/discordjs/discord.js/commit/ad217cc7604dda6a33df73db82799fd5bb4e85a9)) +- **BaseClient:** Prevent user agent mutation (#9425) ([217e5d8](https://github.com/discordjs/discord.js/commit/217e5d81005a2506c96335f7fb96fa21d7dbb04c)) +- **BitField:** Use only enum names in iterating (#9357) ([40d07fb](https://github.com/discordjs/discord.js/commit/40d07fbbbd51d62793d9ea541f41f157b5dad224)) +- Use new permission name (#9274) ([d2d27ce](https://github.com/discordjs/discord.js/commit/d2d27ce7346bc37b34938c84bd3b106a4fa51f53)) +- **Message#editable:** Fix permissions check in locked threads (#9319) ([d4c1fec](https://github.com/discordjs/discord.js/commit/d4c1fecbe264bc52a70aaf0ec303d35e2f15bbcd)) +- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2)) + +## Documentation + +- **AutoModerationRule:** Update docs (#9464) ([1b15d31](https://github.com/discordjs/discord.js/commit/1b15d31b5ae1b1739716fab00b18083c1d7d389a)) +- **APITypes:** Document role & user select menu components (#9435) ([c6ca5a8](https://github.com/discordjs/discord.js/commit/c6ca5a83e7b72613f95c2145606a1330f64ae894)) +- **BaseMessageOptions:** Fix embeds and components (#9437) ([5c52bb9](https://github.com/discordjs/discord.js/commit/5c52bb95906250518a8813820d543f43dd7abdf9)) +- **InteractionResponses:** ShowModal docs change (#9434) ([7d34100](https://github.com/discordjs/discord.js/commit/7d341000d44b762a2fe0434a6b518f7d63539d34)) +- Use ESM code in examples (#9427) ([ce287f2](https://github.com/discordjs/discord.js/commit/ce287f21d1540da7f17cac8a57dc33a67f391ef3)) +- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9)) +- **Options:** Fix links and invalid syntax (#9322) ([86e5f5a](https://github.com/discordjs/discord.js/commit/86e5f5a119c6d2588b988a33236d358ded357847)) +- Cleanup MessageCreateOptions and MessageReplyOptions (#9283) ([300059c](https://github.com/discordjs/discord.js/commit/300059cb266e6cca42c30ee7f997c48ab2cc565e)) +- **Events:** Document auto moderation events (#9342) ([79bcdfa](https://github.com/discordjs/discord.js/commit/79bcdfa767e7e842164e1174b6f4834ed731d329)) +- Add `SnowflakeUtil` (#9371) ([8ffcf77](https://github.com/discordjs/discord.js/commit/8ffcf77840b62590fcb4731380d28b22d0b98741)) +- Use stable tag (#9343) ([c0f2dd7](https://github.com/discordjs/discord.js/commit/c0f2dd713151a29c98e1eebad66721a208be1fc0)) +- Remove `JSONEncondable` (#9344) ([b2eec5f](https://github.com/discordjs/discord.js/commit/b2eec5f9fcf37ebb3b7f87a67a6ee3160c182183)) + +## Features + +- **Attachment:** Voice messages (#9392) ([3e01f91](https://github.com/discordjs/discord.js/commit/3e01f91bbba2cbacacc6c921ed664752f679960b)) +- **BaseInteraction:** Support new channel payload (#9337) ([29389e3](https://github.com/discordjs/discord.js/commit/29389e39f479b832e54c7cb3ddd363aebe99674f)) +- **RoleTagData:** Add guildConnections (#9366) ([2dddbe1](https://github.com/discordjs/discord.js/commit/2dddbe1f321f2e2722dba4a28f7d18384cf50353)) + +## Performance + +- **RoleManager:** Dont call Role#position getter twice per role (#9352) ([bfee6c8](https://github.com/discordjs/discord.js/commit/bfee6c8d889502ea39ad919dd9b1e6253a2af571)) + +## Refactor + +- **WebSocketManager:** Use /ws package internally (#9099) ([a9e0de4](https://github.com/discordjs/discord.js/commit/a9e0de4288ea39a6a089b8379dcd44ac0053dac7)) +- Remove `fromInteraction` in internal channel creation (#9335) ([794abe8](https://github.com/discordjs/discord.js/commit/794abe8450bae000cd0544922cdf53e7b3e4c59c)) + +## Typings + +- **AutoModerationActionMetadataOptions:** Make channel property optional (#9460) ([d26df5f](https://github.com/discordjs/discord.js/commit/d26df5fabaf227fb9d10ba5cc1ab326de55aadbc)) +- **CategoryChannel:** Ensure `parent` and `parentId` are `null` (#9327) ([8218ffc](https://github.com/discordjs/discord.js/commit/8218ffc78d23234b32c05a97fde2f4bea64d7aa6)) +- **GuildTextBasedChannel:** Remove unnecessary exclusion of forum channels (#9326) ([7ff3d52](https://github.com/discordjs/discord.js/commit/7ff3d528d942a0daa990194915ff8328dec99149)) + +# [14.9.0](https://github.com/discordjs/discord.js/compare/14.8.0...14.9.0) - (2023-04-01) + +## Bug Fixes + +- Add support for new guild feature `GUILD_WEB_PAGE_VANITY_URL` (#9219) ([de1aac6](https://github.com/discordjs/discord.js/commit/de1aac674acb3830124646fcd52cdd98cdb71ba5)) +- Resolving string bitfield (#9262) ([7987565](https://github.com/discordjs/discord.js/commit/79875658cf4a8daa25210c2c620c73a710ca22de)) +- **AutocompleteInteraction:** Send `name_localizations` correctly (#9238) ([1864d37](https://github.com/discordjs/discord.js/commit/1864d37d36e53d127e74b6969a5f542193bfc3c7)) +- Keep symbols in actions manager (#9293) ([984bd55](https://github.com/discordjs/discord.js/commit/984bd55b437507e7ebfdf09ac944c8eba0340d27)) +- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b)) +- **ClientUser:** No mutation on edit (#9259) ([abd6ae9](https://github.com/discordjs/discord.js/commit/abd6ae9fc8ea03722e8b36e29c3fdc1c2cfc93e8)) +- **Message#editable:** Update editable check in threads locked (#9216) ([22e880a](https://github.com/discordjs/discord.js/commit/22e880aaa0d8c644fc8d16a524d17f4f53a056f6)) +- **ThreadManager:** Add `members` and conditionally include `hasMore` (#9164) ([e9a8eb3](https://github.com/discordjs/discord.js/commit/e9a8eb323f3a554dc8f9dab361cd1bac7b88e1cc)) +- **ThreadManager:** Respect `cache` and `force` in fetching (#9239) ([cc57563](https://github.com/discordjs/discord.js/commit/cc57563e73d78a0d71d1444d1ee8215a26a81fa8)) +- **TextBasedChannelTypes:** Add `GuildStageVoice` (#9232) ([51edba7](https://github.com/discordjs/discord.js/commit/51edba78bc4d4cb44b4dd2b79e4bbc515dc46f5b)) + +## Documentation + +- Describe private properties (#8879) ([2792e48](https://github.com/discordjs/discord.js/commit/2792e48119f1cf5fa7d5e6b63369457b0719d4e4)) +- Differ `User#send` (#9251) ([384b4d1](https://github.com/discordjs/discord.js/commit/384b4d10e8642f0f280ea1651f33cd378c341333)) +- Fix compare position example (#9272) ([d16114c](https://github.com/discordjs/discord.js/commit/d16114c52646ca92c53f9b44a0dd10af98dbddcd)) +- **Role:** Fix example for `comparePositionTo()` (#9270) ([bc641fa](https://github.com/discordjs/discord.js/commit/bc641fa9360b851642bc51839cef6bd5600d71f7)) +- Add more examples (#9252) ([bf507ab](https://github.com/discordjs/discord.js/commit/bf507ab2659d95e2991e83293b3834f21283ff33)) +- **FetchArchivedThreadOptions:** `before` respects `archive_timestamp`, not creation timestamp (#9240) ([178c8dc](https://github.com/discordjs/discord.js/commit/178c8dcfeea1c4a6a32835baea389f25feefbac7)) +- Update `APISelectMenuComponent` (#9235) ([56cf138](https://github.com/discordjs/discord.js/commit/56cf138e029e7884a4e7efb606055687ca67b4ac)) + +## Features + +- **Guild:** Add `max_stage_video_channel_users` (#8422) ([34bc36a](https://github.com/discordjs/discord.js/commit/34bc36ac4b04ad033d0dcc3d2701fcf2e682743c)) +- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b)) +- Add GuildBasedTextChannelTypes (#9234) ([5f93dcc](https://github.com/discordjs/discord.js/commit/5f93dcce466286f0fdead8faf4131e98d1c9db55)) + +## Refactor + +- Call `GuildBanManager#create()` directly (#9263) ([f340f3b](https://github.com/discordjs/discord.js/commit/f340f3b1fd719e8f7cf6fa28a41835bc16039fc7)) +- **FetchThreadsOptions:** Remove `active` (#9241) ([519e163](https://github.com/discordjs/discord.js/commit/519e163f8aa3b55420f86d2d60c2584b3a2eb327)) + +# [14.8.0](https://github.com/discordjs/discord.js/compare/14.7.1...14.8.0) - (2023-03-12) + +## Bug Fixes + +- **snowflake:** Snowflakes length (#9144) ([955e8fe](https://github.com/discordjs/discord.js/commit/955e8fe312c42ad4937cc1994d1d81e517c413c8)) +- **Actions:** Inject built data by using a symbol (#9203) ([a63ac88](https://github.com/discordjs/discord.js/commit/a63ac88fcca5b61209892a6e560e35d58f5adc3b)) +- **Message#deletable:** Add check for deletable message types (#9168) ([e78b8ad](https://github.com/discordjs/discord.js/commit/e78b8ad3fb6692cba2c565b508254c723f185f0c)) +- **Message:** `bulkDeletable` permissions should be retrieved later for DMs (#9146) ([a9495bd](https://github.com/discordjs/discord.js/commit/a9495bd8f014c8021a214b83ffc531a2af5defef)) +- **AutoModerationActionExecution:** Transform `action` (#9111) ([9156a28](https://github.com/discordjs/discord.js/commit/9156a2889cd0946dfd0b30a5f8365abfbc377b3d)) +- **MessageReaction:** `toJSON()` infinite recursion (#9070) ([f268e1d](https://github.com/discordjs/discord.js/commit/f268e1d9798744e169ae87089ea2e1f214364d95)) +- **ThreadChannel:** Insert starter message from threads created in forum channels (#9100) ([0b76ab4](https://github.com/discordjs/discord.js/commit/0b76ab4c403dd646c71482856ab993b263b7c474)) +- **ApplicationRoleConnectionMetadata:** Export the class correctly (#9076) ([071516c](https://github.com/discordjs/discord.js/commit/071516c35239bd4e1cae572c855d86b335c8536d)) +- Don't auth for interaction `showModal()` (#9046) ([b803a9a](https://github.com/discordjs/discord.js/commit/b803a9a899aaa75a3ea2bc6623c6afb28f495e8c)) +- **WebSocketShard:** Zombie connection fix (#8989) ([876b181](https://github.com/discordjs/discord.js/commit/876b1813128ec702d3ef1e7b0074a4613e88c332)) +- Keep other properties in triggerMetadata (#8977) ([d8dd197](https://github.com/discordjs/discord.js/commit/d8dd197a936dfffc05f9e5bc3184ec9022c56b51)) +- **escapeX:** Emojis with underlines (#8945) ([07b597d](https://github.com/discordjs/discord.js/commit/07b597df16b9412c23ec2387d54564e4d1bcf7ed)) +- **WebSocketShard:** Either start close timeout or emit destroyed but never both (#8956) ([43ce2a5](https://github.com/discordjs/discord.js/commit/43ce2a572eb8977b6994680171ac0c5f9bda1703)) +- **DMChannel:** `recipientId` edge case (#8950) ([7ce9909](https://github.com/discordjs/discord.js/commit/7ce990954e2f73d7a996df0afa42ab287cb12514)) +- Return only boolean for `disabled` (#8965) ([6614603](https://github.com/discordjs/discord.js/commit/66146033268a4db1279b2eaee4bd418f326c0d4b)) +- Export missing `escapeX()` functions (#8944) ([25c27ea](https://github.com/discordjs/discord.js/commit/25c27eac1417e75c9b601b17cf177b1f47b699a9)) +- **WebSocketShard:** Only cleanup the connection if a connection still exists (#8946) ([5eab5fc](https://github.com/discordjs/discord.js/commit/5eab5fc06ca6be36ecf1557f2ad29a670d4d5ae7)) +- Add `@discordjs/formatters` to dependency list (#8939) ([18b3a19](https://github.com/discordjs/discord.js/commit/18b3a19810a6436fa8bb4b490ec5137eaecbd465)) +- **resolveColor:** Invalid colors (#8933) ([c76e170](https://github.com/discordjs/discord.js/commit/c76e17078602914c3e1d227a3acc98eaa99c18d4)) +- **WebSocketShard:** Clear listeners on reconnect (#8927) ([aa8c57d](https://github.com/discordjs/discord.js/commit/aa8c57dab60104549e28451abf35c0387595d67e)) +- Re-export formatters (#8909) ([b14604a](https://github.com/discordjs/discord.js/commit/b14604abdecca575b1fca693c1593e3585bcca8c)) + +## Documentation + +- **MessageManager:** Add clarification to fetch messages (#9222) ([f5ec1ca](https://github.com/discordjs/discord.js/commit/f5ec1cada5ebf0ca4093bdfc81aaf56900c794ef)) +- Make interactionResponse as optional (#9179) ([664cccb](https://github.com/discordjs/discord.js/commit/664cccb2706db33635aa2556954de57f93b3d3db)) +- Fix typos (#9127) ([1ba1f23](https://github.com/discordjs/discord.js/commit/1ba1f238f04221ec890fc921678909b5b7d92c26)) +- **chatInputApplicationCommandMention:** Parameters are not nullable (#9091) ([6f78e82](https://github.com/discordjs/discord.js/commit/6f78e8285b3ce762de010e68d49b377a47dc5a63)) +- No `@type` description and reveal info block (#9097) ([405f940](https://github.com/discordjs/discord.js/commit/405f9400e8e3ffea9f3847ab5abb431a34538a96)) +- **ThreadEditOptions:** Move info tag back to `invitable` (#9020) ([f3fe3ce](https://github.com/discordjs/discord.js/commit/f3fe3ced622676b406a62b43f085aedde7a621aa)) +- Fix a typo in the MentionableSelectMenuInteraction link (#9000) ([6d7a143](https://github.com/discordjs/discord.js/commit/6d7a143667f33ef2ea45d8016ac4738237707881)) +- **ApplicationRoleConnectionMetadata:** Add documentation (#8976) ([2e22b31](https://github.com/discordjs/discord.js/commit/2e22b31892d9b858fcb24fa580b486b4154e823f)) +- Fix malformed overridden documentation (#8954) ([0b8b114](https://github.com/discordjs/discord.js/commit/0b8b114761f961a2bf8e5aae342ed711b154a89e)) +- **GuildForumThreadManager:** Fix `sticker` type (#8940) ([dd62be0](https://github.com/discordjs/discord.js/commit/dd62be077d3e4fbd73a0c10ca344d93d3d19fa38)) +- Fix deprecated links (#8907) ([976b234](https://github.com/discordjs/discord.js/commit/976b234e9dc9999e5dee47b58c85afbc1cd494c2)) +- **UserFlagsBitField:** Make `.Flags` static (#8902) ([c48ff5e](https://github.com/discordjs/discord.js/commit/c48ff5e4205899e3b6cd35812ca857236bef6864)) + +## Features + +- **Collector:** Add lastCollectedTimestamp (#9044) ([4458a13](https://github.com/discordjs/discord.js/commit/4458a13925164762b519ded1037ae8775d879f71)) +- **StageChannel:** Add messages (#9134) ([ffdb197](https://github.com/discordjs/discord.js/commit/ffdb197f988657100e2a9ff0ca17b759339a1dda)) +- **AutoModerationActionExecution:** Add `channel`, `user` and `member` getters (#9142) ([095bd77](https://github.com/discordjs/discord.js/commit/095bd77515aa31bb0e95a350b4355980fea9268d)) +- **AutoModeration:** Support `custom_message` (#9171) ([c1000b8](https://github.com/discordjs/discord.js/commit/c1000b86ed6d5413afcd6ee7e80505e5a845430b)) +- **ThreadMemberManager:** Support pagination fetching (#9035) ([765d5a3](https://github.com/discordjs/discord.js/commit/765d5a3b2d5529c3a2a4b29512f6932264443ed1)) +- **InteractionResponse:** Add new methods (#9132) ([dc9924f](https://github.com/discordjs/discord.js/commit/dc9924fb5f24c8dac963d6b86ba279a89545e73b)) +- **GuildMember:** Add `flags` (#9087) ([76b2116](https://github.com/discordjs/discord.js/commit/76b21162aca7cd4897826437da3063524e1e7553)) +- **Client:** `guildAuditLogEntryCreate` event (#9058) ([9439107](https://github.com/discordjs/discord.js/commit/9439107a1d6a9b77b5f991973d96bc6100da4753)) +- Add role subscription data (#9025) ([1ba22f4](https://github.com/discordjs/discord.js/commit/1ba22f4c9e4173f8866339d3eadb2939d4b32034)) +- **Sticker:** Add support for gif stickers (#9038) ([6a9875d](https://github.com/discordjs/discord.js/commit/6a9875da054a875a4711394547d47439bbe66fb6)) +- **GuildAuditLogs:** Support `after` (#9011) ([0076589](https://github.com/discordjs/discord.js/commit/0076589ccc93e09d77a448874d1ceff5d0e91aa2)) +- Add role subscriptions (#8915) ([3407e1e](https://github.com/discordjs/discord.js/commit/3407e1eea3c8d5629465553f342ac30ceae27a47)) +- Add `not_found` to guild member chunk data (#8975) ([be294ea](https://github.com/discordjs/discord.js/commit/be294eaf9901ea139ce485deeec9178959ffa91f)) +- **ClientApplication:** Add role connections (#8855) ([22e2bbb](https://github.com/discordjs/discord.js/commit/22e2bbb0d24e3f30516f262308d5786f2f666713)) +- **CommandInteractionOptionResolver:** Add `channelTypes` option to `getChannel` (#8934) ([429dbcc](https://github.com/discordjs/discord.js/commit/429dbccc85cabd9986b2e8bf443bf384e4ddc61a)) +- **ForumChannel:** Add `defaultForumLayout` (#8895) ([cbafd47](https://github.com/discordjs/discord.js/commit/cbafd479b331633ed97f7b1a22ef03c6a2f4cf31)) +- Add support for nsfw commands (#7976) ([7a51344](https://github.com/discordjs/discord.js/commit/7a5134459c5f06864bf74631d83b96d9c21b72d8)) +- **InteractionResponse:** CreatedTimestamp (#8917) ([627511d](https://github.com/discordjs/discord.js/commit/627511d6522f772b84c25e6a3f6da06b06bb912e)) +- **Guild:** Add disableInvites method (#8801) ([45faa19](https://github.com/discordjs/discord.js/commit/45faa199820e7c4ccdb2997c7e3b353f566d2312)) + +## Refactor + +- Compare with `undefined` directly (#9191) ([869153c](https://github.com/discordjs/discord.js/commit/869153c3fdf155783e7c0ecebd3627b087c3a026)) +- **GuildMemberManager:** Tidy up fetching guild members (#8972) ([4e0e125](https://github.com/discordjs/discord.js/commit/4e0e1250399aa12c340ac92a86ec2c05704fe2bb)) +- **BitField:** Reverse iterator/toArray responsibilities (#9118) ([f70df91](https://github.com/discordjs/discord.js/commit/f70df910ed12e397066d0bdb27343af21ead4d92)) +- Moved the escapeX functions from discord.js to @discord.js/formatters (#8957) ([13ce78a](https://github.com/discordjs/discord.js/commit/13ce78af6e3aedc793f53a099a6a615df44311f7)) +- Use `deprecate()` directly (#9026) ([1c871b5](https://github.com/discordjs/discord.js/commit/1c871b5b576dddef12c5afacecf416dbd6243dea)) +- **Guild:** Destructure object in guild editing (#8971) ([d3e9f2a](https://github.com/discordjs/discord.js/commit/d3e9f2a355a1f5272d62a507eb6ecd8808904fff)) +- **GuildManager:** Better handling of creation code (#8974) ([d7a09f6](https://github.com/discordjs/discord.js/commit/d7a09f6fcee30c31b4418166bf7bf9e894841f87)) +- **sharding:** Use switch statement (#8928) ([6540914](https://github.com/discordjs/discord.js/commit/6540914b4a7f244f5e40fe2a3b7e73986763d81b)) +- Use consistent naming for options (#8901) ([a7b55c1](https://github.com/discordjs/discord.js/commit/a7b55c1460cf63fb482f7d05657120eec96bee82)) +- **CommandInteractionOptionResolver:** Loosen mentionable checks (#8910) ([1b151db](https://github.com/discordjs/discord.js/commit/1b151db59c4340417f8a28a88064f45336ac8c78)) + +## Styling + +- Run prettier (#9041) ([2798ba1](https://github.com/discordjs/discord.js/commit/2798ba1eb3d734f0cf2eeccd2e16cfba6804873b)) + +## Typings + +- Allow sending messages with `SuppressNotifications` flag (#9177) ([71a427f](https://github.com/discordjs/discord.js/commit/71a427f6322be76fe2d1cb265de09f171b1b354a)) +- Remove `EscapeMarkdownOptions` (#9153) ([fd0246c](https://github.com/discordjs/discord.js/commit/fd0246ca4c75e60d8e117d9ac5af7067c7a63277)) +- **Attachment:** Make `attachment` private (#8982) ([da23cd5](https://github.com/discordjs/discord.js/commit/da23cd5d69de4856d075f00738f75c68c555ae5b)) +- Fix type of Attachment#name (#9101) ([4e0a89f](https://github.com/discordjs/discord.js/commit/4e0a89f58f43f362bfde80d8319dce767c62850f)) +- Allow builders to set channel types in discord.js (#8990) ([7dec892](https://github.com/discordjs/discord.js/commit/7dec892218f7b470a5f8e78732a524a53da24d26)) +- Swap message reaction and emoji identifier types (#8969) ([ad49845](https://github.com/discordjs/discord.js/commit/ad4984526020f2baeefaeeebbded66c6848c4b85)) +- **widget:** Add missing `name` (#8978) ([898b5ac](https://github.com/discordjs/discord.js/commit/898b5ac416cbbb415b125bb27221d0901fdd180e)) +- Use StringSelectMenuOptionBuilder (#8949) ([bec51de](https://github.com/discordjs/discord.js/commit/bec51de1038c35c6edaaa13934781758fe1951de)) +- Fix actions type in automod (#8962) ([5915f39](https://github.com/discordjs/discord.js/commit/5915f39810b712c05a46fa21ab4e12b4cfa3c25a)) +- Subcommand group `options` is required (#8966) ([5dc5e90](https://github.com/discordjs/discord.js/commit/5dc5e902688fc563087cd5061dcb59dd68fd4eda)) +- Add generic to `ActionRowBuilder.from()` (#8414) ([153352a](https://github.com/discordjs/discord.js/commit/153352ad7a1ccb4a9461523cf2597d81df93b69c)) + +# [14.7.1](https://github.com/discordjs/discord.js/compare/14.7.0...14.7.1) - (2022-12-01) + +## Bug Fixes + +- Prevent crash on no select menu option (#8881) ([11d195d](https://github.com/discordjs/discord.js/commit/11d195d04ff57d51adb0f0d3a0a7342f9e34aba0)) + +# [14.7.0](https://github.com/discordjs/discord.js/compare/14.6.0...14.7.0) - (2022-11-28) + +## Bug Fixes + +- **MessageMentions:** Add `InGuild` generic (#8828) ([f982803](https://github.com/discordjs/discord.js/commit/f9828034cd21e6f702762a46923e0f42115596f6)) +- **Activity:** Fix equals() not checking for differing emoji (#8841) ([7e06f68](https://github.com/discordjs/discord.js/commit/7e06f68185423ba7cb310220b213f445b6571e29)) +- Fixed react/astro/guide/discord.js build, updated dependencies, fix crawlvatar (#8861) ([d0c8256](https://github.com/discordjs/discord.js/commit/d0c82561b8a1765a1daa362ca903f3ffb3fa33ee)) +- **escapeMarkdown:** Fix double escaping (#8798) ([d6873b7](https://github.com/discordjs/discord.js/commit/d6873b7159352479475b3a0daa215bddbdd3a79b)) +- **Transfomers:** Call `.toJSON` in `toSnakeCase` (#8790) ([017f9b1](https://github.com/discordjs/discord.js/commit/017f9b1ed4014dc1db0b78c1a77e463b4403de5d)) +- Censor token in debug output (#8764) ([53d8e87](https://github.com/discordjs/discord.js/commit/53d8e87d7f3a329608250656950bd0a200adb1c7)) +- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4)) + +## Documentation + +- Describe InteractionEditReplyOptions (#8840) ([cb77fd0](https://github.com/discordjs/discord.js/commit/cb77fd02d083438de2aff6f0769baf7d1797bc65)) +- **AutoModerationRuleManager:** Describe cache (#8848) ([d275480](https://github.com/discordjs/discord.js/commit/d2754802cc3479e6288cdbfcd48c76bf57e09a07)) +- Fix message action row components (#8819) ([65bc0ad](https://github.com/discordjs/discord.js/commit/65bc0adbf4d7870d33b92585ca18f964f24bc84e)) +- Specify `ActionRowBuilder` for `components` (#8834) ([8ed5c1b](https://github.com/discordjs/discord.js/commit/8ed5c1beb622f71ce0bd89e4cbeff50e464da8fe)) +- Add `@extends` for select menu classes (#8824) ([09f65b7](https://github.com/discordjs/discord.js/commit/09f65b724b0d2f36bbe89b83570c0d18093b5126)) +- Make WebSocketShard.lastPingTimestamp public (#8768) ([68c9cb3](https://github.com/discordjs/discord.js/commit/68c9cb37bc3df6326b720291827ea477e421faf2)) +- **MessageReplyOptions:** Remove duplicate stickers field (#8766) ([6e348ff](https://github.com/discordjs/discord.js/commit/6e348ffd1d8db8d8ad2da7823460814695e01a43)) + +## Features + +- **Webhook:** Add `channel` property (#8812) ([decbce4](https://github.com/discordjs/discord.js/commit/decbce401062af75f633e6acacc88207b115a719)) +- Auto Moderation (#7938) ([fd4ba5e](https://github.com/discordjs/discord.js/commit/fd4ba5eaba66898699127fc0d5f0ab52c18e3db0)) +- **SelectMenuInteractions:** Add `values` property (#8805) ([b2fabd1](https://github.com/discordjs/discord.js/commit/b2fabd130a76ea54cfbfa1b871ef8659513c2c7a)) +- **ThreadChannel:** Add a helper for pin and unpin (#8786) ([e74aa7f](https://github.com/discordjs/discord.js/commit/e74aa7f6b0fe04e3473fc4a62a73a7db87307685)) +- Add `Message#bulkDeletable` (#8760) ([ff85481](https://github.com/discordjs/discord.js/commit/ff85481d3e7cd6f7c5e38edbe43b27b104e82fba)) +- New select menus (#8793) ([5152abf](https://github.com/discordjs/discord.js/commit/5152abf7285581abf7689e9050fdc56c4abb1e2b)) +- **InteractionResponses:** Add message parameter (#8773) ([8b400ca](https://github.com/discordjs/discord.js/commit/8b400ca975c6bad00060b9c67068f42bd53524ba)) +- Support resume urls (#8784) ([88cd9d9](https://github.com/discordjs/discord.js/commit/88cd9d906074eb79e85df0ef49287f11133d2e0d)) +- Allow deletion of ephemeral messages (#8774) ([fc10774](https://github.com/discordjs/discord.js/commit/fc107744618857bf28c2167f204253baf690ede8)) +- **GuildChannelManager:** Add `.addFollower()` method (#8567) ([caeb1cb](https://github.com/discordjs/discord.js/commit/caeb1cbfdb2f2f007252c4d7e9f47a575c24bcb5)) + +## Refactor + +- **Embed:** Use `embedLength` function from builders (#8735) ([cb3826c](https://github.com/discordjs/discord.js/commit/cb3826ce6dbcd3cf7ab639af6cdfcea80336aa1d)) + +# [14.6.0](https://github.com/discordjs/discord.js/compare/14.5.0...14.6.0) - (2022-10-10) + +## Bug Fixes + +- **ClientOptions:** Make `ClientOptions#intents` returns an IntentsBitField (#8617) ([4c2955a](https://github.com/discordjs/discord.js/commit/4c2955a5de6779c29c09e63ba9ad2b235904f842)) +- Correctly construct a builder (#8727) ([e548e6a](https://github.com/discordjs/discord.js/commit/e548e6a10b7e1720f5e8f3c859b0b64d5134a012)) +- **Components:** Error with unknown components (#8724) ([6fd331d](https://github.com/discordjs/discord.js/commit/6fd331dd528e78fd023c908bd58af3faa9ed6c65)) +- **Client:** Don't auth for webhook fetches with token (#8709) ([01d75c8](https://github.com/discordjs/discord.js/commit/01d75c8b8b14f33c95a4da83a8494db848beeb8c)) +- Re-export util (#8699) ([a306219](https://github.com/discordjs/discord.js/commit/a306219673335584accd2ff77ab34d2812ef6c5d)) +- Throw discord.js errors correctly (#8697) ([ace974f](https://github.com/discordjs/discord.js/commit/ace974fc1fdbc5bcaa0d7f6f6d17de185c9f9cbf)) + +## Documentation + +- **Utils:** Remove `private` from `parseEmoji` (#8718) ([a31e605](https://github.com/discordjs/discord.js/commit/a31e605e09064a300e31a3c91466b613654ba98e)) +- Update UserContextMenuCommandInteraction documentation (#8717) ([7556db2](https://github.com/discordjs/discord.js/commit/7556db243d9480949835668fcb5724fdd5d70e08)) +- Fix `AwaitMessageComponentOptions` typedef (#8696) ([9effd82](https://github.com/discordjs/discord.js/commit/9effd82abe82ba71ae627673da21ba07e1ede23e)) + +## Features + +- **Util:** Escape more markdown characters (#8701) ([7b8966b](https://github.com/discordjs/discord.js/commit/7b8966bca156db79933403289741893a6e10ccd5)) +- **GuildChannelManager:** Allow creating channels with a default auto archive duration (#8693) ([628759b](https://github.com/discordjs/discord.js/commit/628759bcff8b0d4c77926cee2b8c18d8fdb4c260)) +- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3)) +- **ForumChannel:** Add `defaultSortOrder` (#8633) ([883f6e9](https://github.com/discordjs/discord.js/commit/883f6e9202a559c986f4b15fccb422b5aea7bea8)) + +## Refactor + +- Rename Error to DiscordjsError internally (#8706) ([aec44a0](https://github.com/discordjs/discord.js/commit/aec44a0c93f620b22242f35e626d817e831fc8cb)) + +## Typings + +- Fix events augmentation (#8681) ([ac83ada](https://github.com/discordjs/discord.js/commit/ac83ada306ec153c13260d2bd53e4d704884b68a)) +- **Message:** Remove `& this` from `#inGuild` typeguard (#8704) ([c0f7a1a](https://github.com/discordjs/discord.js/commit/c0f7a1a89a4cf62edc7065bd200b2ce4018e0a27)) +- **ModalBuilder:** Fix constructor typings (#8690) ([2ea2a85](https://github.com/discordjs/discord.js/commit/2ea2a85e6335d57f44689f9b6e284129104de8fc)) + +# [14.5.0](https://github.com/discordjs/discord.js/compare/14.4.0...14.5.0) - (2022-09-25) + +## Bug Fixes + +- **ThreadChannel:** Add forum channel to parent (#8664) ([0126d9b](https://github.com/discordjs/discord.js/commit/0126d9b810a156c4bf1b8b93f2121f3319855bac)) +- **GuildChannelManager:** Allow creating webhooks on forums (#8661) ([16fcdc3](https://github.com/discordjs/discord.js/commit/16fcdc36877d1a65ce9995c9fe3502aa268c9388)) +- **ForumChannel:** Implement missing properties and methods (#8662) ([8622939](https://github.com/discordjs/discord.js/commit/862293922924f453f69b0b0f8efe87ddebbd387d)) +- RepliableInteraction respect cached generic (#8667) ([578bc95](https://github.com/discordjs/discord.js/commit/578bc951bdcdc21ec5aee86e7a47a17e8c867dfc)) +- **ThreadChannel:** Allow editing flags (#8671) ([1244854](https://github.com/discordjs/discord.js/commit/1244854e1365d7e4a8d01703a7ec13610ed100c7)) +- **GuildChannelManager:** Typo in `flags` property name when editing (#8669) ([fc8ed81](https://github.com/discordjs/discord.js/commit/fc8ed816e643754a938211a17b41a2cec95df265)) + +## Documentation + +- Fix duplicate typedefs (#8677) ([d79aa2d](https://github.com/discordjs/discord.js/commit/d79aa2d0d0b186bd28cbfc82f3d6ecf3deb41c50)) +- **ForumChannel:** Add `@implements` (#8678) ([8ca407e](https://github.com/discordjs/discord.js/commit/8ca407e089c3050b61a51a52b9100e4613ad1666)) + +## Features + +- **GuildChannelManager:** Allow editing `flags` (#8637) ([abb7226](https://github.com/discordjs/discord.js/commit/abb7226af3445f5b724815bb2f7a121a52a563b5)) + +## Refactor + +- **GuildBanManager:** Add deprecation warning for `deleteMessageDays` (#8659) ([e993122](https://github.com/discordjs/discord.js/commit/e9931229ae62a120ae0761ee2a2c10ea0cb1a6fb)) + +## Typings + +- **GuildChannelManager:** Handle forum channel overload (#8660) ([1486bc9](https://github.com/discordjs/discord.js/commit/1486bc9336369d229972df5e28b9428365b92bff)) +- **Caches:** Allow `GuildForumThreadManager` and `GuildTextThreadManager` (#8665) ([2487e3b](https://github.com/discordjs/discord.js/commit/2487e3bf76260a4a2fbf375e0b01a43f347922a3)) + +# [14.4.0](https://github.com/discordjs/discord.js/compare/14.3.0...14.4.0) - (2022-09-21) + +## Bug Fixes + +- Correct applied tags type (#8641) ([f6f15d8](https://github.com/discordjs/discord.js/commit/f6f15d8e877d4ffbe908a093e64809ef9015e0ff)) +- **ThreadChannel:** Make `fetchStarterMessage()` work in forum posts (#8638) ([a7f816e](https://github.com/discordjs/discord.js/commit/a7f816eeb7fa1e193cf0901efbdcaf629f72465f)) +- Update `messageCount`/`totalMessageSent` on message events (#8635) ([145eb2f](https://github.com/discordjs/discord.js/commit/145eb2fc5db5ca739aa9782d5ec5210f81a6aeeb)) +- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9)) + +## Documentation + +- Correctly overwrite `setRTCRegion` method (#8642) ([f049734](https://github.com/discordjs/discord.js/commit/f0497343f1193635b260b9e2085cac7b43991f74)) +- **GuildTextThreadManager:** Document correct `@extend` (#8639) ([802b239](https://github.com/discordjs/discord.js/commit/802b2394b08151faab6810695fd5c8f27ce84d58)) +- Fix regexps incorrectly being called global (#8624) ([fc9653f](https://github.com/discordjs/discord.js/commit/fc9653f5aea4013da15fb8de0a4452400eaa7739)) +- Update misleading `Client#guildMemberAvailable` event description (#8626) ([22ac6b4](https://github.com/discordjs/discord.js/commit/22ac6b4660db6b02f62b9851e9e3bcfe5fb506b5)) +- **Options:** Update DefaultMakeCacheSettings (#8585) ([3252332](https://github.com/discordjs/discord.js/commit/32523325c6610e95fe3ffcc31d005b3418c6bc68)) +- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0)) + +## Features + +- **Widget:** Allow forum channels (#8645) ([b106956](https://github.com/discordjs/discord.js/commit/b1069563086fc616fe21abb789f28f69e57c8851)) +- **WelcomeChannel:** Add forum channel as a type (#8643) ([6f1f465](https://github.com/discordjs/discord.js/commit/6f1f465a77e362e20ec50067be0e634d35946ba5)) +- Allow forum channels in webhook update event (#8646) ([5048a3d](https://github.com/discordjs/discord.js/commit/5048a3d17ace22336e74451d30b513b3db42a26f)) +- Add support for guild forums (#7791) ([8a8d519](https://github.com/discordjs/discord.js/commit/8a8d519c9c4c082370fc6935b56dafb525b873df)) +- **GuildBanManager#create:** Add `deleteMessageSeconds` (#8326) ([03fb5b0](https://github.com/discordjs/discord.js/commit/03fb5b0a2f45275dec7885175ad691a1d9c449c4)) +- Add typeguard to BaseInteraction#isRepliable (#8565) ([55c3ee2](https://github.com/discordjs/discord.js/commit/55c3ee20ae700e78d18a3c4c04b6a7426cffc060)) +- **Integration:** Add `scopes` (#8483) ([8b3d006](https://github.com/discordjs/discord.js/commit/8b3d0061180cfd5d9ba8beae3e8d623b5ce43ea4)) +- Add `chatInputApplicationCommandMention` formatter (#8546) ([d08a57c](https://github.com/discordjs/discord.js/commit/d08a57cadd9d69a734077cc1902d931ab10336db)) + +## Refactor + +- Replace usage of deprecated `ChannelType`s (#8625) ([669c3cd](https://github.com/discordjs/discord.js/commit/669c3cd2566eac68ef38ab522dd6378ba761e8b3)) +- Split message send/edit types/documentation (#8590) ([8e1afae](https://github.com/discordjs/discord.js/commit/8e1afaebdb686033555ca58e53f34bb97f7369c8)) +- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67)) + +## Typings + +- Narrow channel type in thread managers (#8640) ([14bbc91](https://github.com/discordjs/discord.js/commit/14bbc9150a748e7ac1660c2375c7f065fcc55a6c)) +- **interactions:** Pass `Cached` type to return type of methods (#8619) ([053da5b](https://github.com/discordjs/discord.js/commit/053da5bc91d5cfa8d842b13b0b05083d2f7f086d)) +- Ensure events possess `Client<true>` (#8612) ([a9f003a](https://github.com/discordjs/discord.js/commit/a9f003ac9b56d31166cbf353d02140dad0b2517e)) +- **GuildChannelManager:** Correct `fetch` return type (#8549) ([1d4cdee](https://github.com/discordjs/discord.js/commit/1d4cdee321ab25bb0f109d55a000582825dd79f9)) +- **ThreadChannel:** `fetchStarterMessage` must return a `Message<true>` (#8560) ([b9c62ac](https://github.com/discordjs/discord.js/commit/b9c62ac0f0f534c33f9913135095f8b3d98ec05e)) +- **webhook:** Avatar can be null (#8541) ([f77612a](https://github.com/discordjs/discord.js/commit/f77612a55e9c593a21bc27e58c9fbd03d85787e3)) + +# [14.3.0](https://github.com/discordjs/discord.js/compare/14.2.0...14.3.0) - (2022-08-22) + +## Bug Fixes + +- **GuildMemberManager:** `add()` method throws an error (#8539) ([3bef901](https://github.com/discordjs/discord.js/commit/3bef9018c0be3c5dc51d03b796d08b925dc4e1b9)) +- **Guild:** Widget channel types and fixes (#8530) ([23a0b6c](https://github.com/discordjs/discord.js/commit/23a0b6ccf27410963bd4f5c53d9ee2ce019e90a8)) +- **Embed:** Reference video in video (#8473) ([c97977a](https://github.com/discordjs/discord.js/commit/c97977a3e806bd5d8682bc7fb22ebec1a8ceecdc)) + +## Documentation + +- **GuildAuditLogsEntry:** Correct `action` wording (#8499) ([7d25072](https://github.com/discordjs/discord.js/commit/7d2507279cc9d1397c7d61e7c7b856ff4bc17c86)) + +## Features + +- **GuildMemberManager:** AddRole and removeRole (#8510) ([cda3f00](https://github.com/discordjs/discord.js/commit/cda3f005b1546fdb8410e9550526956f840857fc)) +- Deprecate `ActionRow.from()` (#8504) ([f9c25dd](https://github.com/discordjs/discord.js/commit/f9c25ddcfe68f089e13f1090c3df4bd7cd74d2b7)) +- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166)) + +## Refactor + +- **GuildAuditLogsEntry:** Remove `guild` from application command permission update extra (#8520) ([2b8074d](https://github.com/discordjs/discord.js/commit/2b8074dd12f2f1e957caffb57e5fd4d7be88dc25)) + +## Typings + +- Inference of guild in `MessageManager` (#8538) ([6bb1474](https://github.com/discordjs/discord.js/commit/6bb1474d2001b76773954c959b2c2687e1df0136)) +- Allow choice's value type to be strictly inferred (#8529) ([b3f7c32](https://github.com/discordjs/discord.js/commit/b3f7c32f7f91f12766178f5e17585856e81d9a87)) +- **GuildAuditLogs:** Allow fetching to return all possible values (#8522) ([0dba8ad](https://github.com/discordjs/discord.js/commit/0dba8adbd2e6efd634bd3eb31df09467ba8a8a0d)) +- Correct `EventEmitter.on (static)` return type (#8524) ([16bbc8a](https://github.com/discordjs/discord.js/commit/16bbc8aa208a8a16c22be24696f57d5f7a5faf2b)) +- **GuildAuditLogs:** Remove static `Entry` (#8521) ([7a3d18d](https://github.com/discordjs/discord.js/commit/7a3d18dd6d1fe27393d00019b9ecd35c98b95ee7)) +- Disallow some channel types from webhook creation (#8531) ([4882b17](https://github.com/discordjs/discord.js/commit/4882b17a77484f801faa19fb971f2e6abd88e59f)) +- Implement max/min values for autocomplete (#8498) ([812f7f1](https://github.com/discordjs/discord.js/commit/812f7f1ea86fc953aa796875cbc7ccc434203d77)) +- **ModalMessageModalSubmitInteraction:** ChannelId is not nullable (#8496) ([c31a5cf](https://github.com/discordjs/discord.js/commit/c31a5cfcc82706667768eac77b5f99ba69cf3c91)) +- Change type of ApplicationCommandSubCommand.options (#8476) ([ebaf158](https://github.com/discordjs/discord.js/commit/ebaf158006d3c7db3b8c695e7c027b8af11999ba)) + +# [14.2.0](https://github.com/discordjs/discord.js/compare/14.1.2...14.2.0) - (2022-08-10) + +## Bug Fixes + +- **ThreadChannel:** Handle possibly `null` parent (#8466) ([afa27b1](https://github.com/discordjs/discord.js/commit/afa27b15c5b92bc8d55b8285834d8e03f6692d06)) +- Remove DM channels from `Client#messageDeleteBulk`'s types (#8460) ([6c6fe74](https://github.com/discordjs/discord.js/commit/6c6fe74dd84859c5319efa999404e8168f189710)) +- **Transformers:** Do not transform `Date` objects (#8463) ([0e2a095](https://github.com/discordjs/discord.js/commit/0e2a09571c8e5ee61153b04e45334a226a1b4534)) +- **ModalSubmitInteraction:** Allow deferUpdate (#8455) ([0fab869](https://github.com/discordjs/discord.js/commit/0fab869e5179dca7ddec75b5519615278e51ad82)) +- **Guild:** Unable to fetch templates (#8420) ([aac8acc](https://github.com/discordjs/discord.js/commit/aac8acc22be7d7af99933ef099eca7deda43cb40)) +- **MessageMentions:** Infinite loop in `parsedUsers` getter (#8430) ([b8a3136](https://github.com/discordjs/discord.js/commit/b8a31360a220e3d796f5381bd215d30a379ecb7c)) +- **DataResolver:** Make `Buffer` from string (#8416) ([e72b986](https://github.com/discordjs/discord.js/commit/e72b986939e2958547c0e54d6d27472c8d111609)) + +## Documentation + +- Change registration example to use global commands (#8454) ([64a4041](https://github.com/discordjs/discord.js/commit/64a4041a05e9514334a9f9e1f38a1ea18bb676d5)) +- **Colors:** Provide enum descriptions (#8437) ([6ef4754](https://github.com/discordjs/discord.js/commit/6ef4754d40c5ec65715fc1e00e643c52fe0a6209)) +- **AttachmentBuilder:** Fix #8407 (#8421) ([5b053cf](https://github.com/discordjs/discord.js/commit/5b053cf82ec2f2b717a490485af052dc956fe3c9)) + +## Features + +- **Guild:** Add `max_video_channel_users` (#8423) ([3a96ce7](https://github.com/discordjs/discord.js/commit/3a96ce7970947f6268c21a1323d986aac8cb736d)) + +## Typings + +- **Message:** Correct `bulkDelete` return type (#8465) ([c5b96a1](https://github.com/discordjs/discord.js/commit/c5b96a185cb8ba836b7cd10526c14059866f218f)) +- Fix missing types for mentionable options (#8443) ([452e94f](https://github.com/discordjs/discord.js/commit/452e94fd3ecc12de9e3408982c5c7fd931bae634)) +- **ApplicationCommandOption:** Add `ApplicationCommandBooleanOption` (#8434) ([38275fc](https://github.com/discordjs/discord.js/commit/38275fc53d633ce77ed2b142aff788dcbd4fad8c)) + +# [14.1.2](https://github.com/discordjs/discord.js/compare/14.1.1...14.1.2) - (2022-07-30) + +## Bug Fixes + +- **errors:** Error codes (#8398) ([480c85c](https://github.com/discordjs/discord.js/commit/480c85c9c3d129204b3399ed726a4e570e0b2852)) + +## Documentation + +- **Embed:** Ensure height and width are numbers (#8396) ([fca3dad](https://github.com/discordjs/discord.js/commit/fca3dada2a565eecfc7e5275cc9317df1d261871)) + +# [14.1.0](https://github.com/discordjs/discord.js/compare/14.0.3...14.1.0) - (2022-07-29) + +## Bug Fixes + +- **MessageMentions:** `ignoreRepliedUser` option in `has()` (#8202) ([b4e2c0c](https://github.com/discordjs/discord.js/commit/b4e2c0c4d5538b945f9d597c6410a6f84b315084)) +- **GuildChannelManager:** Allow unsetting rtcRegion (#8359) ([a7d49e5](https://github.com/discordjs/discord.js/commit/a7d49e56fc7c34d2e4548d9e5bf0aec45273506e)) +- **ThreadChannel:** Omit webhook fetching (#8351) ([3839958](https://github.com/discordjs/discord.js/commit/3839958e3f682c715f1017da05436d2fe34900fd)) +- **GuildAuditLogsEntry:** Replace OverwriteType with AuditLogOptionsType (#8345) ([58c1b51](https://github.com/discordjs/discord.js/commit/58c1b51c5ceab137ad9851919b338419eeeab69e)) +- **ShardClientUtil#_respond:** Construct global error (#8348) ([8e520f9](https://github.com/discordjs/discord.js/commit/8e520f946a5b9f93a939290facf4ccca2c05ff21)) +- **Presence:** Do not return NaN for activity timestamp (#8340) ([df42fdf](https://github.com/discordjs/discord.js/commit/df42fdfc421f1190f0a2267a66efd3c921ec2348)) +- **Client:** Omit private properties from toJSON (#8337) ([830c670](https://github.com/discordjs/discord.js/commit/830c670c61dcb17d8ab2a894a3203c68917d27e0)) +- **ApplicationCommandManager:** Allow passing 0n to defaultMemberPermissions (#8311) ([1fb7b30](https://github.com/discordjs/discord.js/commit/1fb7b30963cfe7ea4c05b1f3b42171c879c46a1d)) + +## Documentation + +- **InteractionResponses:** Add `showModal()` return type (#8376) ([0b61dbf](https://github.com/discordjs/discord.js/commit/0b61dbf720e844322b066e30080c3537ab3d8174)) +- **WebhookClient:** Document working options (#8375) ([ba6797e](https://github.com/discordjs/discord.js/commit/ba6797e74209161b64c412de1b6f307cb28736b8)) +- **Message:** Document gateway intent for content (#8364) ([2130aae](https://github.com/discordjs/discord.js/commit/2130aae3210a8eaf91c5ccae5463940d49052c7d)) +- Use info blocks for requirements (#8361) ([80b9738](https://github.com/discordjs/discord.js/commit/80b9738957ebf5b6eb7c9858cec0fb1c897d0a1f)) +- **WebhookClient:** Make constructor a union (#8370) ([e9920a9](https://github.com/discordjs/discord.js/commit/e9920a9c98ffb78bd7d0ae00d486476367296646)) +- Update docs and examples to PascalCase links (#8305) ([34ba9d1](https://github.com/discordjs/discord.js/commit/34ba9d1c4c80eff7e6ac199a40232d07491432cc)) + +## Features + +- Add channel & message URL formatters (#8371) ([a7deb8f](https://github.com/discordjs/discord.js/commit/a7deb8f89830ead6185c5fb46a49688b6d209ed1)) +- Restore missing typeguards (#8328) ([77ed407](https://github.com/discordjs/discord.js/commit/77ed407f6aadb68e729470c5269e9b526cb1b3f0)) +- **GuildMember:** Add dmChannel getter (#8281) ([4fc2c60](https://github.com/discordjs/discord.js/commit/4fc2c60a3bb43671b4b0202ae75eab42aba163ff)) + +## Refactor + +- Deprecate `Formatter` class (#8373) ([7fd9ed8](https://github.com/discordjs/discord.js/commit/7fd9ed8f13d17ce7e98e34f7454d9047054d8467)) +- **PermissionOverwriteManager:** Use `OverwriteType` (#8374) ([6d24805](https://github.com/discordjs/discord.js/commit/6d248051cfd431e9cb1c65cb98f56aa0a6556407)) + +## Typings + +- **GuildAuditLogsEntryExtraField:** Use `AuditLogOptionsType` (#8349) ([200ab91](https://github.com/discordjs/discord.js/commit/200ab91f527d8a5706d277b89a975096f75d141a)) + +# [14.0.3](https://github.com/discordjs/discord.js/compare/14.0.2...14.0.3) - (2022-07-19) + +## Bug Fixes + +- **Components:** Support emoji id strings (#8310) ([660e212](https://github.com/discordjs/discord.js/commit/660e212e83df026c684ee2cda7fb4e98870f342e)) + +# [14.0.2](https://github.com/discordjs/discord.js/compare/14.0.1...14.0.2) - (2022-07-18) + +## Bug Fixes + +- **DataResolver#resolveImage:** Adjust to updated resolveFile (#8308) ([3a7e93d](https://github.com/discordjs/discord.js/commit/3a7e93df576172c797f1d8bd6483234bb6af2d00)) + +# [14.0.0](https://github.com/discordjs/discord.js/compare/9.3.1...14.0.0) - (2022-07-17) + +## Bug Fixes + +- **GuildMemberManager:** Allow setting own nickname (#8066) ([52a9e21](https://github.com/discordjs/discord.js/commit/52a9e213c2dc13ee52ee0234593fdce392f43890)) +- **PermissionOverwriteManager:** Mutates user (#8283) ([3bf30b1](https://github.com/discordjs/discord.js/commit/3bf30b1e6d2d6f583f7069a1e24e7842d59fab2f)) +- **GuildChannelManager:** Access `resolveId` correctly (#8296) ([3648f6d](https://github.com/discordjs/discord.js/commit/3648f6d567cd834c301de913ce19f786a265240d)) +- **GuildChannelManager:** Edit lockPermissions (#8269) ([7876548](https://github.com/discordjs/discord.js/commit/787654816d2b6a5168d199d32cdaeb4ef6d270b9)) +- **`SelectMenuBuilder`:** Properly accept `SelectMenuOptionBuilder`s (#8174) ([31d5930](https://github.com/discordjs/discord.js/commit/31d593046466438c55f5784b0f2098e233c5edc4)) +- Remove global flag on regular expressions (#8177) ([cdd9214](https://github.com/discordjs/discord.js/commit/cdd9214212892e30b3eaa161837c37516c5bcaa0)) +- **MessagePayload:** Guard against `repliedUser` property (#8211) ([fa010b5](https://github.com/discordjs/discord.js/commit/fa010b516254c4ab2762278817f31bf289f0ab6a)) +- **ApplicationCommandManager:** Explicitly allow passing builders to methods (#8209) ([50d55bd](https://github.com/discordjs/discord.js/commit/50d55bd6b819307c86701f4808c087f359c6ccff)) +- **GuildMemberRemove:** Remove member's presence (#8181) ([11b1739](https://github.com/discordjs/discord.js/commit/11b173931968c548f8504649ae7090865892e62d)) +- Edit() data can be partial and `defaultMemberPermissions` can be `null` (#8163) ([0ffbef5](https://github.com/discordjs/discord.js/commit/0ffbef506a97a0bf22cb134fc007c2aec29cbffc)) +- **WebSocketShard:** Keep an error handler on connections (#8150) ([c34c02a](https://github.com/discordjs/discord.js/commit/c34c02ab8d119bf16d8d14d125a9b650b4bb18f4)) +- **DJSError:** Error code validation (#8149) ([31f6582](https://github.com/discordjs/discord.js/commit/31f658247fe0e1047897edab629643d140e77e07)) +- **vcs:** Nsfw property (#8132) ([2eeaad6](https://github.com/discordjs/discord.js/commit/2eeaad6f27fdf8868364fa95ed20755ee09bda87)) +- **WebSocketManager:** Correct error name (#8138) ([db2b033](https://github.com/discordjs/discord.js/commit/db2b0333d912fe83381db2ffe16829d7d03d6c2e)) +- **WebSocketShard:** Disconnected casing (#8117) ([23e183a](https://github.com/discordjs/discord.js/commit/23e183a9ac7aaa3bca2bc4eb8634d1738ec34a26)) +- **webhooks:** Revert webhook caching (and returning Message) (#8038) ([d54bf5d](https://github.com/discordjs/discord.js/commit/d54bf5d286f4057db130901591b192fd4d1668c1)) +- **ApplicationCommand:** Remove `autocomplete` check at the top level and correctly check for `dmPermission` (#8100) ([0a44b05](https://github.com/discordjs/discord.js/commit/0a44b05db83948857afbe18471e7a867da47177a)) +- **ApplicationCommand:** Fix default member permissions assignment (#8067) ([96053ba](https://github.com/discordjs/discord.js/commit/96053babe1bd65ebe1fc6a261f5eb052906afdb9)) +- **scripts:** Read directory and rerun (#8065) ([f527dea](https://github.com/discordjs/discord.js/commit/f527dea36ead194aaae1bf5da1e953df59d692fd)) +- Select menu options to accept both rest and array (#8032) ([fbe67e1](https://github.com/discordjs/discord.js/commit/fbe67e102502b4b49690cbf8ff891ead2232ecf3)) +- **CommandInteractionOptionResolver:** Handle autocompletion interactions (#8058) ([d8077c6](https://github.com/discordjs/discord.js/commit/d8077c6839dc8ceb57d3c3a86bf9746be2a91ada)) +- **scripts:** Add quotes around blob arguments (#8054) ([598f61b](https://github.com/discordjs/discord.js/commit/598f61b992fab1b3fdcab8ff960366f7af0b37ea)) +- **Message:** Force fetching (#8047) ([f2b267c](https://github.com/discordjs/discord.js/commit/f2b267c079dd8aa7277910471f3db2f88af6efb2)) +- **Attachment:** Do not destructure `data` (#8041) ([1afae90](https://github.com/discordjs/discord.js/commit/1afae909d72e648cf48d63d7de2708737a78c126)) +- **DirectoryChannel:** Type `name` and handle `url` (#8023) ([86d8fbc](https://github.com/discordjs/discord.js/commit/86d8fbc023e3925e8f86799d6ebf2d423f7bf2ec)) +- Readd `isThread` type guard (#8019) ([f8ed71b](https://github.com/discordjs/discord.js/commit/f8ed71bfca6e47e3d44ad063e23804354bd23604)) +- Add static method `from` in builders (#7990) ([ad36c0b](https://github.com/discordjs/discord.js/commit/ad36c0be7744ea4214ccf345fe80a5a1a9e89101)) +- Typings (#7965) ([7a1095b](https://github.com/discordjs/discord.js/commit/7a1095b66be3c5d81185e026281e2908c10c1695)) +- **GuildAuditLogs:** Cache guild scheduled events (#7951) ([2f03f9a](https://github.com/discordjs/discord.js/commit/2f03f9ad3f63abee5b5c46d02f1afa8885e8977c)) +- Make sure action row builders create djs builders (#7945) ([adf461b](https://github.com/discordjs/discord.js/commit/adf461baf49be754c7a10c61faf1ef3df333413a)) +- **TextBasedChannel#bulkDelete:** Return deleted message (#7943) ([191510b](https://github.com/discordjs/discord.js/commit/191510b7f87903e4bd93b891649cb290fd50c47e)) +- Remove trailing invites on channel deletion (#7932) ([5e9b757](https://github.com/discordjs/discord.js/commit/5e9b757a3733e6526770eb60a15072612294eb21)) +- **DataResolver:** Fix check for readable streams (#7928) ([28172ca](https://github.com/discordjs/discord.js/commit/28172ca7b57357436d3252ec01ec17dad865d87f)) +- **AuditLog:** Default changes to empty array (#7880) ([19eaed6](https://github.com/discordjs/discord.js/commit/19eaed63905367ef4604366b8839023384524d1f)) +- **Util:** Flatten ignoring certain fields (#7773) ([df64d3e](https://github.com/discordjs/discord.js/commit/df64d3ea382c07e66bc7cc8877ee430206c31d63)) +- Possibly missing (#7829) ([6239d83](https://github.com/discordjs/discord.js/commit/6239d83c4d5f0a396678410d7fef35e39ed29009)) +- `endReason` not being properly set in base Collector (#7833) ([0c18dab](https://github.com/discordjs/discord.js/commit/0c18dab1280205b8855d17d075b7421860d59c14)) +- **SelectMenuBuilder:** Options array (#7826) ([3617093](https://github.com/discordjs/discord.js/commit/361709332bdc871822c2b9919f14fd090d68666a)) +- **Activity:** Platform type (#7805) ([4ac91c6](https://github.com/discordjs/discord.js/commit/4ac91c61d08111ae4d49d1e64caf94e6e49832c8)) +- **ApplicationCommand:** Equal nameLocalizations and descriptionLocalizations (#7802) ([4972bd8](https://github.com/discordjs/discord.js/commit/4972bd87c17cbc6a94c9608ba2ab39c475f9921f)) +- **InteractionResponses:** Use optional chaining on nullable property (#7812) ([c5fb548](https://github.com/discordjs/discord.js/commit/c5fb54852906898ffb19282dd60168dfc6fb2eba)) +- **MessageManager:** Allow caching option of an unspecified limit (#7763) ([1b2d8de](https://github.com/discordjs/discord.js/commit/1b2d8decb638faeae8184119c5cedfcdaf9485e3)) +- **builders:** Add constructor default param (#7788) ([c286650](https://github.com/discordjs/discord.js/commit/c2866504a3824005fe756556fec4b349898b7d22)) +- **MessagePayload:** ResolveBody check body instead of data (#7738) ([3db20ab](https://github.com/discordjs/discord.js/commit/3db20abdd2d502a1ed457842181b164dc6390ba1)) +- **ActionRow:** ToJSON should include components (#7739) ([ebb4dfa](https://github.com/discordjs/discord.js/commit/ebb4dfa262adb2086c83db487002bb2e1ed5ab88)) +- Prevent `NaN` for nullable timestamps (#7750) ([8625d81](https://github.com/discordjs/discord.js/commit/8625d817145eb642aeb0da05184352f438586986)) +- **InteractionCreateAction:** Ensure text-based channel for caching messages (#7755) ([25fdb38](https://github.com/discordjs/discord.js/commit/25fdb3894d33dc395a376a3d962a063eb5735253)) +- Pass `force` correctly (#7721) ([402514f](https://github.com/discordjs/discord.js/commit/402514ff323ccf1f8c95d295f044cf0bb5547c2e)) +- Support reason in setRTCRegion helpers (#7723) ([905a6a1](https://github.com/discordjs/discord.js/commit/905a6a11663f9469ada67f8310a969453ffc5b2a)) +- **GuildMemberManager:** Return type can be null (#7680) ([74bf7d5](https://github.com/discordjs/discord.js/commit/74bf7d57ab959eb820ab1c213ac86ab1ea660398)) +- **gateway:** Use version 10 (#7689) ([8880de0](https://github.com/discordjs/discord.js/commit/8880de0cecdf273fd6df23988e4cb77774a75390)) +- Audit log static reference (#7703) ([85e531f](https://github.com/discordjs/discord.js/commit/85e531f22d7a8f8ad043647ce445726ae0df26c0)) +- Handle possibly missing property (#7641) ([0c32332](https://github.com/discordjs/discord.js/commit/0c32332a5aacbbb6c415da75c166d09cfdb34bbd)) +- **util:** Allow `escapeInlineCode` to escape double backtics (#7638) ([d5369a5](https://github.com/discordjs/discord.js/commit/d5369a56e3fcf50513f3bc582552c2838b04d199)) +- **GuildEditData:** Some fields can be null (#7632) ([4d2b559](https://github.com/discordjs/discord.js/commit/4d2b55955d1a3ff05c3047599232becdc3f2c445)) +- TOKEN_INVALID error not thrown at login with invalid token (#7630) ([cd79bef](https://github.com/discordjs/discord.js/commit/cd79bef2547594f4d0c744faa8fa67fb9fd61526)) +- **GuildScheduledEvent:** Handle missing `image` (#7625) ([c684ac5](https://github.com/discordjs/discord.js/commit/c684ac55e1d225740e67ab7bd5643de1b35f4594)) +- **guild:** Throw if ownerId falsey (#7575) ([98177aa](https://github.com/discordjs/discord.js/commit/98177aa38d3d6516d4c5354d6c7edea925dc881d)) +- Remove Modal export (#7654) ([87a6b84](https://github.com/discordjs/discord.js/commit/87a6b8445bfbf3981cd39813fe961dfa1c7f2bce)) +- **Embed:** Fix incorrect destructuring import (#7615) ([cbdb408](https://github.com/discordjs/discord.js/commit/cbdb408dffd1c7f2193c15989528a3de5fd9f13a)) +- **ThreadMembersUpdate:** Only emit added & removed thread members (#7539) ([c12d61a](https://github.com/discordjs/discord.js/commit/c12d61a3421afcdc41f77c0fddde4efbb257fa69)) +- **Util:** EscapeInlineCode properly (#7587) ([851f380](https://github.com/discordjs/discord.js/commit/851f380eb10d23ffd08e8b845aed4039abbcd03b)) +- **GuildStickerManager:** Correctly access guild ID (#7605) ([4b08d9b](https://github.com/discordjs/discord.js/commit/4b08d9b376bda7a7f4bb3fb8c555d25cca648de4)) +- **MessageManager:** Pin route (#7610) ([cb566c8](https://github.com/discordjs/discord.js/commit/cb566c8b6abff489a944db7952e5c5a48e0c98b0)) +- Handle partial data for `Typing#user` (#7542) ([c6cb5e9](https://github.com/discordjs/discord.js/commit/c6cb5e9ebbf46d81404119a6aa11bb8ebb17d5a4)) +- **guild:** Fix typo accessing user instead of users (#7537) ([8203c5d](https://github.com/discordjs/discord.js/commit/8203c5d843f2431c0f49023282f1bf73d85881d1)) +- **test:** `MessageActionRow` to `ActionRow` (#7523) ([d1d1b07](https://github.com/discordjs/discord.js/commit/d1d1b076bebf7cb706b2436a40d87c6efaed1e1d)) +- **MessagePayload:** Don't set reply flags to target flags (#7514) ([4f30652](https://github.com/discordjs/discord.js/commit/4f306521d829fef21ebd70557b37f8199b82572b)) +- **invite:** Add back channelId property (#7501) ([78aa36f](https://github.com/discordjs/discord.js/commit/78aa36f9f5913b86c82376ecdf20653b15340bbe)) +- Properly serialize `undefined` values (#7497) ([8dbd345](https://github.com/discordjs/discord.js/commit/8dbd34544cbeb499282f01dda9d35ed9bca93591)) +- Allow unsafe embeds to be serialized (#7494) ([942ea1a](https://github.com/discordjs/discord.js/commit/942ea1acbfb49289ccb3a1882b5a2da0a7d0bccf)) +- Attachment types (#7478) ([395a68f](https://github.com/discordjs/discord.js/commit/395a68ff49c622d5136d6b775beaf8e88a2d8610)) +- Use case converter for json component serialization (#7464) ([2d45544](https://github.com/discordjs/discord.js/commit/2d4554440ed9329a5876a9c674c3eb2de0f2f917)) +- **GuildAuditLogs:** Typings and consistency (#7445) ([c1b27f8](https://github.com/discordjs/discord.js/commit/c1b27f8eed8ea04a48bc106453892bddcdc6b73e)) +- **dataresolver:** Ensure fetched file is convert to a buffer (#7457) ([9311fa7](https://github.com/discordjs/discord.js/commit/9311fa7b42b2b5a74e411aa263daa4fbfc270645)) +- **messagepayload:** ResolveFile property names (#7458) ([a8106f7](https://github.com/discordjs/discord.js/commit/a8106f7c586f0ecac76e7f72c53b0da215a6fbf1)) +- **ci:** Ci error (#7454) ([0af9bc8](https://github.com/discordjs/discord.js/commit/0af9bc841ffe1a297d308500d696bad4b85abda9)) +- **threads:** Require being sendable to be unarchivable (#7406) ([861f0e2](https://github.com/discordjs/discord.js/commit/861f0e2134662ab64a11d313130aff58b413d495)) +- **guildmember:** Check if member has administrator permission (#7384) ([81d8b54](https://github.com/discordjs/discord.js/commit/81d8b54ff6b98b0e7ee2c57eaee6bc0b707e135a)) +- **guild:** Remove `maximumPresences` default value (#7440) ([55b388a](https://github.com/discordjs/discord.js/commit/55b388a763dc7223e88b62ae928fe85fe8b8fe58)) +- **guildchannelmanager:** Edit always sets parent to null (#7446) ([b97aedd](https://github.com/discordjs/discord.js/commit/b97aedd8e15f9358960cb59403f3a8ea24b87141)) +- **guildmember:** Make `pending` nullable (#7401) ([fe11ff5](https://github.com/discordjs/discord.js/commit/fe11ff5f6e85571a981e90eba5b9f3bda7a2cd04)) +- **clientpresence:** Fix used opcodes (#7415) ([a921ec7](https://github.com/discordjs/discord.js/commit/a921ec7dc525c58d40b4678e66270f9238abed31)) +- Correctly export UnsafeSelectMenuComponent from builders (#7421) ([aadfbda](https://github.com/discordjs/discord.js/commit/aadfbda586d57a7b775ad26c201f0dc34618180b)) +- MessageReaction.me being false when it shouldn't (#7378) ([04502ce](https://github.com/discordjs/discord.js/commit/04502ce702da53c4b00bf391d0fd936746851381)) +- Fix some typos (#7393) ([92a04f4](https://github.com/discordjs/discord.js/commit/92a04f4d98f6c6760214034cc8f5a1eaa78893c7)) +- **messagementions:** Fix `has` method (#7292) ([3a5ab2c](https://github.com/discordjs/discord.js/commit/3a5ab2c4e54de4e67ab6e323d7eac86482da7382)) +- **guildmembermanager:** Use rest in edit (#7356) ([00ce1c5](https://github.com/discordjs/discord.js/commit/00ce1c56ac224691a8691a3525cb14ae002319c6)) +- **typings:** Mark `RESTOptions` as Partial in `ClientOptions` (#7349) ([e1ecc1a](https://github.com/discordjs/discord.js/commit/e1ecc1a80a9358cdbafbe8542c40b9de8cad467e)) +- **Webhook:** Use correct method name (#7348) ([11e5e5a](https://github.com/discordjs/discord.js/commit/11e5e5ac5b70138f56332eb3e61a42443670b0de)) +- **thread:** Don't assign directly to getters (#7346) ([2db0cdd](https://github.com/discordjs/discord.js/commit/2db0cdd357c3a02decb4fd4168db87888efba283)) +- Missed enums and typings from #7290 (#7331) ([47633f0](https://github.com/discordjs/discord.js/commit/47633f0fd2435d6d8c694d8d37b26039a7b3797a)) +- **guildchannelmanager:** Remove reverse enum lookup (#7304) ([857bba4](https://github.com/discordjs/discord.js/commit/857bba448029f3f070c67fb40b59a3a2a2e5c6f4)) +- Import `clear{Timeout,Interval}` from `node:timers` (#7269) ([8ddd44e](https://github.com/discordjs/discord.js/commit/8ddd44ed85b32c86243efe0ec35b283eaaa8212c)) +- **ApplicationCommand:** Use new ApplicationCommandOptionType enums (#7257) ([06f5210](https://github.com/discordjs/discord.js/commit/06f5210f58bbba6102173033a9f1e6fb004fdf5d)) +- Use enums from discord-api-types (#7258) ([f284a46](https://github.com/discordjs/discord.js/commit/f284a4641fd68de9190bda97ec1eab0981149630)) +- **exports:** Export ApplicationCommandType properly (#7256) ([f753882](https://github.com/discordjs/discord.js/commit/f75388259262bf6b4a64375b97800bd72378f3bc)) +- **Shard:** EventEmitter listener warning (#7240) ([ff3a8b8](https://github.com/discordjs/discord.js/commit/ff3a8b83234d3826fc49c5a8c3cb52ef9f281ffd)) +- **timestamps:** Account for timestamps of 0 when creating Dates (#7226) ([a8509c9](https://github.com/discordjs/discord.js/commit/a8509c91ca0147393b407221405b6b917677961a)) +- **MessageEmbed:** CreatedAt field can be zero (#7218) ([37cad54](https://github.com/discordjs/discord.js/commit/37cad54dbdade39607397b8ad697eca94f1b7197)) +- **BaseClient:** Do not append default options if provided is not an object (#6453) ([b92a7d7](https://github.com/discordjs/discord.js/commit/b92a7d72332c35b607db54aa6aca24b8e10e00ad)) +- Snowflakeutil import (#7219) ([962f4bf](https://github.com/discordjs/discord.js/commit/962f4bf88211dbfb5ad0295a9467dede1e2688ee)) +- **Role:** Remove unused process (#7215) ([63034b4](https://github.com/discordjs/discord.js/commit/63034b44c9849087e391684d9b6c0c6ae9a21113)) +- **WebhookClient:** Updated webhook url regex (#6804) ([1c615d1](https://github.com/discordjs/discord.js/commit/1c615d1bb2606d5f19e55076d4ecab95c619518e)) +- **Sweepers:** Add sweepStickers function (#7213) ([95f8375](https://github.com/discordjs/discord.js/commit/95f8375d425f58f501f32ead03f7927e6596f8e6)) +- **InteractionCreate:** Use ChatInputCommandInteraction instead (#7210) ([49dada3](https://github.com/discordjs/discord.js/commit/49dada35f92470d3e4426362510847b93dd42d1a)) +- **Structues:** Rename old module's name (#7207) ([fbef454](https://github.com/discordjs/discord.js/commit/fbef45489457a2198357dc4dd303740d79036784)) +- **WebSocket:** Remove application command handler (#7202) ([033151c](https://github.com/discordjs/discord.js/commit/033151cf92fe43536b8a4c0f4d7d9ed75a2095c5)) +- **User:** `bannerURL()` should not throw when not present (#6789) ([3872acf](https://github.com/discordjs/discord.js/commit/3872acfeb8390f6f7202d69cf1f7f8616a7b0b34)) +- **VoiceState:** Ensure `suppress` & `streaming` have proper fallback values (#6377) ([a0d5f13](https://github.com/discordjs/discord.js/commit/a0d5f13dd9b27c44f5183a2a9af4c4fdecb312c0)) +- **sweepers:** Provide default for object param (#7182) ([ae2f013](https://github.com/discordjs/discord.js/commit/ae2f013653c8a9f9ffb12ae8fcdb1bb604b39236)) + +## Deprecation + +- **Caching:** Clean up deprecated cache sweeping (#7118) ([12ffa06](https://github.com/discordjs/discord.js/commit/12ffa069aa8b247e945fef16a543f41c2c391bf1)) + +## Documentation + +- Align webhook method return types with implementation (#8253) ([5aeed99](https://github.com/discordjs/discord.js/commit/5aeed9935058241648507d7f651679226a89dbb3)) +- Remove `@private` constructor documentation (#8255) ([452dec5](https://github.com/discordjs/discord.js/commit/452dec57ca422f5e7424a0f0e78c3e152717f413)) +- **ApplicationCommand:** Add `min_length` and `max_length` to ApplicationCommandOptionData (#8239) ([43f62bb](https://github.com/discordjs/discord.js/commit/43f62bb6678ec332795c8cfbe0c01854b95aa61e)) +- **MessageInteraction#commandName:** Updated description (#8212) ([ab238a9](https://github.com/discordjs/discord.js/commit/ab238a9046e0201dbd4755fa41fa69c44b186912)) +- Add missing `@extends` (#8205) ([e0c8282](https://github.com/discordjs/discord.js/commit/e0c82824905dcebf62c2d1afcc5e5590a5594838)) +- **Constants:** Fix SweeperKeys type (#8157) ([af04992](https://github.com/discordjs/discord.js/commit/af04992ed3c2617fda686c2bc7338dcada283dc6)) +- **Channels:** Internally document channel creation (#8154) ([5e5853a](https://github.com/discordjs/discord.js/commit/5e5853a4e885c47e3dde519761dd59a5ec0e06fc)) +- Update threads to use `ThreadAutoArchiveDuration` (#8153) ([ee36d60](https://github.com/discordjs/discord.js/commit/ee36d60dc6714c83569a20716fa8ca8e1bd7de4f)) +- **APITypes:** Remove duplicate type definition (#8144) ([a061233](https://github.com/discordjs/discord.js/commit/a0612335101c7ce2a07d95da4b79f0d4a2b1a6a0)) +- Document missing type definitions (#8130) ([203bc4a](https://github.com/discordjs/discord.js/commit/203bc4a2cf0c2d90a003093318aa0741605610f5)) +- **InteractionResponse:** Fix return (#8141) ([f1ac17c](https://github.com/discordjs/discord.js/commit/f1ac17c961cf95d99e205133605d10d8be5bd737)) +- **PermissionsBitField:** Fix `@name` of bitfield (#8115) ([3a77ce0](https://github.com/discordjs/discord.js/commit/3a77ce0b18c60a0b21ba088590ff89f2ace94087)) +- `TextBasedChannel` -> `TextBasedChannels` typos (#8110) ([db663a5](https://github.com/discordjs/discord.js/commit/db663a55c2ed2faf61e217009158da50dfcf274f)) +- Remove `number`s from enums (#8098) ([0a138da](https://github.com/discordjs/discord.js/commit/0a138dab95a86512f08ac3be356f77f38f2ea880)) +- **GuildAuditLogs:** Fix and reimplement type definitions (#8108) ([4155136](https://github.com/discordjs/discord.js/commit/415513696c7b7e139d1b958e480bf0c7e4d14111)) +- **WebSocketOptions:** Add `version` to docs and typings (#8050) ([386c41f](https://github.com/discordjs/discord.js/commit/386c41f24fb3c9d06967d9c1881a57645c3a71f2)) +- **BaseGuildTextChannel:** Update `setType()`'s parameter type (#8088) ([9c0f190](https://github.com/discordjs/discord.js/commit/9c0f190de1f743d9bd597ffd656503c672db71c1)) +- Update outdated examples (#8081) ([51eadf3](https://github.com/discordjs/discord.js/commit/51eadf37371a6138847efdb4b5b81ee132001cf0)) +- **ThreadMemberManager:** Require `member` in `FetchThreadMemberOptions` (#8079) ([552ec72](https://github.com/discordjs/discord.js/commit/552ec72542ec3b2b3ebf35c9fd84ab502dd746cf)) +- **AutocompleteInteraction:** Change useless log in responds example (#8077) ([ac7bf69](https://github.com/discordjs/discord.js/commit/ac7bf692bfce8204e278205dde811515a51f154b)) +- Description and missing `@typedef` fixes (#8087) ([a2eebf6](https://github.com/discordjs/discord.js/commit/a2eebf6c66f3e4c96ece9d2ae2a1133c84257f42)) +- Ignore docs of unexported functions (#8051) ([94bdcac](https://github.com/discordjs/discord.js/commit/94bdcaca62414a77d4ee0b8b79752a2be937320b)) +- **ClientOptions:** Fix closeTimeout default (#8049) ([b2eea1c](https://github.com/discordjs/discord.js/commit/b2eea1c900ba73d4b98b72f5c196f51e27d3ab8f)) +- **DirectoryChannel:** Extend `Channel` (#8022) ([f3f34f0](https://github.com/discordjs/discord.js/commit/f3f34f07b3b396015b130b8e9d938a3eec688fc3)) +- **Attachment:** Remove constructor doc (#8009) ([0a7953e](https://github.com/discordjs/discord.js/commit/0a7953e46310c77483d277539b47f1a7ab051fd9)) +- **VoiceChannel:** Annotate that it is implementing TextBasedChannel (#8007) ([5987dbe](https://github.com/discordjs/discord.js/commit/5987dbe5cff6991ae6905b0387411fa042d3e9b7)) +- Add missing discord-api-types external types (#8001) ([546d486](https://github.com/discordjs/discord.js/commit/546d48655f36ed9a6c6c5ce3c2eabcca1a86a945)) +- **InteractionResponses:** Replace outdated Embed example for reply (#7875) ([d308c66](https://github.com/discordjs/discord.js/commit/d308c66eeca6bdc3471637ae3aaaaa0a2f5c9989)) +- Require parameter (#7838) ([f4ccc67](https://github.com/discordjs/discord.js/commit/f4ccc6772c15e32489ca22fb2c3e803b85d4dbf9)) +- **ApplicationCommand:** Fix and improve localization docs (#7804) ([61a44c5](https://github.com/discordjs/discord.js/commit/61a44c509c40abaf7ffb95b10942889cbbf155ac)) +- **ApplicationCommand:** Fix ApplicationCommandOptionChoice (#7794) ([f1d0084](https://github.com/discordjs/discord.js/commit/f1d0084da26b0111ca029c789ad9e8e6c2882b4d)) +- Add back static properties and methods (#7706) ([520f471](https://github.com/discordjs/discord.js/commit/520f471ac56cbc01402b79197333a8a34c4ac5c9)) +- **InteractionCollector:** Document channel option type (#7551) ([e787cd5](https://github.com/discordjs/discord.js/commit/e787cd5fa5d013319347392ee4f799a677f6f512)) +- Correctly type getters (#7500) ([ffecf08](https://github.com/discordjs/discord.js/commit/ffecf084956f954cf10e1b844e00326e443a86f2)) +- ApplicationCommandData typedef (#7389) ([d32db88](https://github.com/discordjs/discord.js/commit/d32db8833e1058fb36f2e83af79d5353a9f2f693)) +- **channel:** Fix `isDMBased` docs (#7411) ([f2a7a9f](https://github.com/discordjs/discord.js/commit/f2a7a9f1b30af272a6a8d81825d09f84e749cc24)) +- **messageattachment:** Fix `contentType` docs (#7413) ([2800e07](https://github.com/discordjs/discord.js/commit/2800e07e5974e07b9f8ce043722b9b99a5bcc80d)) +- Add supported option types for autocomplete (#7368) ([8bb3751](https://github.com/discordjs/discord.js/commit/8bb37513400d646d784d59875d6b6a6ec10160cd)) +- Add external builder docs links (#7390) ([0b866c9](https://github.com/discordjs/discord.js/commit/0b866c9fb284971113e288e52327d4506db28011)) +- Add EnumResolvers (#7353) ([72767a1](https://github.com/discordjs/discord.js/commit/72767a1059526bdf617e80d5a9e5da1fbd2936d3)) +- **locales:** Update Discord API docs link (#7266) ([b640272](https://github.com/discordjs/discord.js/commit/b6402723c31bed3c49f8b8cde873b65b9f373fd7)) +- **StageInstance:** Deprecate discoverableDisabled (#7179) ([bd33ebb](https://github.com/discordjs/discord.js/commit/bd33ebb507eab36bc2219103dbd1e0217b9f38c0)) +- **shardingmanager:** Fix type of `execArgv` option (#7284) ([e65da44](https://github.com/discordjs/discord.js/commit/e65da44d9c564d1ffcb0f4df2bcdaf0ce0636f35)) +- **interaction:** Add locale list link (#7261) ([37ec0bd](https://github.com/discordjs/discord.js/commit/37ec0bda6df75fb1dc69b7a1eafbb8ea19e68457)) +- Fix a typo and use milliseconds instead of ms (#7251) ([0dd56af](https://github.com/discordjs/discord.js/commit/0dd56afe1cdf16f1e7d9afe1f8c29c31d1833a25)) +- Fix command interaction docs (#7212) ([137ea24](https://github.com/discordjs/discord.js/commit/137ea249df3aa6b8375ecb42aa456a6fdb811f19)) +- **TextBasedChannel:** Fixed syntax error in examples (#7163) ([b454740](https://github.com/discordjs/discord.js/commit/b454740ae87b6c3c13536181965519c7277e5840)) +- **TextBasedChannel:** Fix #createMessageComponentCollector description (#7168) ([d4e6e03](https://github.com/discordjs/discord.js/commit/d4e6e0370857dff00185d59faf8aaac12b343a7a)) +- Fixes the examples for kick and ban (#7170) ([db669b8](https://github.com/discordjs/discord.js/commit/db669b897132ec458d50ca6c1e3afa761e98ffc3)) +- **RoleManager:** Fix incorrect example (#7174) ([f79ea67](https://github.com/discordjs/discord.js/commit/f79ea67d3a9ba134a9acef0a443bd089c4e173a6)) + +## Features + +- **builder:** Add max min length in string option (#8214) ([96c8d21](https://github.com/discordjs/discord.js/commit/96c8d21f95eb366c46ae23505ba9054f44821b25)) +- **applicationCommand:** Add max min length in string option (#8215) ([94ee60d](https://github.com/discordjs/discord.js/commit/94ee60d3d438f6657bdef51471528769af09624c)) +- Add website documentation early mvp (#8183) ([d95197c](https://github.com/discordjs/discord.js/commit/d95197cc78593df4d0a8d1cc492b0e41b4ab58b8)) +- **BaseInteraction:** Add support for `app_permissions` (#8194) ([002d6a5](https://github.com/discordjs/discord.js/commit/002d6a5aede3d1c0e08bd58eeef38a3b9202f525)) +- **util:** ParseWebhookURL (#8166) ([c4653f9](https://github.com/discordjs/discord.js/commit/c4653f97b1529eb0b99fccdba67c37eb4f467ff9)) +- **AutocompleteInteraction:** Add `commandGuildId` (#8086) ([10a6c42](https://github.com/discordjs/discord.js/commit/10a6c4287dd45a30290814e50fa29a086f85da02)) +- **guild:** Add support for setting MFA level (#8024) ([c5176be](https://github.com/discordjs/discord.js/commit/c5176be14b697ff506eb973c4119644eab544304)) +- **vcs:** Add missing property and methods (#8002) ([0415300](https://github.com/discordjs/discord.js/commit/0415300243877ddbcb501c0a26b1ff65618a1da7)) +- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21)) +- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc)) +- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86)) +- Backport handle zombie connection (#7626) ([e1176fa](https://github.com/discordjs/discord.js/commit/e1176faa27898d4f127c293c099201cb294e10ee)) +- **CommandInteraction:** Add 'commandGuildId' (#8018) ([aa59a40](https://github.com/discordjs/discord.js/commit/aa59a409b36c7ef7018d1785d2dba4da17b57864)) +- Allow builders to accept rest params and arrays (#7874) ([ad75be9](https://github.com/discordjs/discord.js/commit/ad75be9a9cf90c8624495df99b75177e6c24022f)) +- **MessageReaction:** Add react method (#7810) ([a328778](https://github.com/discordjs/discord.js/commit/a3287782b57c28b94c390c24e7d5f2d8c303301f)) +- **Collector:** Add `ignore` event (#7644) ([5244fe3](https://github.com/discordjs/discord.js/commit/5244fe3c1cd400985b00e95d8e5ec73823cf4f25)) +- **GuildMemberManager:** Add `GuildMemberManager#fetchMe()` (#7526) ([349766d](https://github.com/discordjs/discord.js/commit/349766dd6925e2d5e5597cc78c73e46f17c56eab)) +- **guildChannelManager:** Add `videoQualityMode` option for `create()` (#7980) ([cdd2ba0](https://github.com/discordjs/discord.js/commit/cdd2ba036ab1559783eb067786c52aff61807557)) +- **EnumResolvers:** Remove Enumresolvers (#7876) ([76694c1](https://github.com/discordjs/discord.js/commit/76694c1497de1b083a792fd1fda20f0eace50c48)) +- Move `me` to `GuildMemberManager` manager (#7669) ([aed687b](https://github.com/discordjs/discord.js/commit/aed687b09f87862eb2f33fb9f95b2cbd0b770585)) +- **rest:** Use undici (#7747) ([d1ec8c3](https://github.com/discordjs/discord.js/commit/d1ec8c37ffb7fe3b63eaa8c382f22ca1fb348c9b)) +- **VoiceChannel:** Add support for text in voice (#6921) ([4ba0f56](https://github.com/discordjs/discord.js/commit/4ba0f56b6af64bac30eea807fb3e9f3c41c3c83c)) +- **SelectMenu:** Allow emojis in options and option constructors (#7797) ([f22245e](https://github.com/discordjs/discord.js/commit/f22245e9d072ac4ef63b0ae0d84d5ba94608ce22)) +- Allow `createMessageComponentCollector` without using `fetchReply` (#7623) ([a58556a](https://github.com/discordjs/discord.js/commit/a58556adc02b2b9239c8f277a4387c743c9d6f04)) +- Add guild directory support (#6788) ([b01f414](https://github.com/discordjs/discord.js/commit/b01f4147d4f3bca021bc269c9f06463f06e3db53)) +- **GuildBanManager:** Support pagination results (#7734) ([fc2a8bb](https://github.com/discordjs/discord.js/commit/fc2a8bb6750919ecd6ee7c872df05f4b677ff5d3)) +- **CommandInteraction:** Add support for localized slash commands (#7684) ([01a423d](https://github.com/discordjs/discord.js/commit/01a423d110cfcddb3d794fcc32579a1547dd472d)) +- Allow emoji strings to be passed through constructors (#7718) ([0faac04](https://github.com/discordjs/discord.js/commit/0faac04b69f1dda3dc860cd584af100e36a40917)) +- **StageInstanceManager:** Add `sendStartNotification` option to create (#7730) ([29f8807](https://github.com/discordjs/discord.js/commit/29f88079559cc02ccfef7a7c16458d481e573fb5)) +- Add `makeURLSearchParams` utility function (#7744) ([8eaec11](https://github.com/discordjs/discord.js/commit/8eaec114a98026024c21545988860c123948c55d)) +- **modal:** Add `awaitModalSubmit` (#7751) ([3037fca](https://github.com/discordjs/discord.js/commit/3037fca196a0f9238d53bb51394daf737bbf3742)) +- **Actions:** Add parent structure to events parameters (#7577) ([3f3e432](https://github.com/discordjs/discord.js/commit/3f3e4327c86da86734c19a96e97115bd505b4532)) +- Export `UnsafeModalBuilder` and `UnsafeTextInputBuilder` (#7628) ([6fec252](https://github.com/discordjs/discord.js/commit/6fec25239dfed46a30826d38dc97f3680f24ec65)) +- **VoiceChannel:** Support `video_quality_mode` (#7722) ([3b3dabf](https://github.com/discordjs/discord.js/commit/3b3dabf3da2e2f24b81967d68b581d7f7452273f)) +- Add API v10 support (#7477) ([72577c4](https://github.com/discordjs/discord.js/commit/72577c4bfd02524a27afb6ff4aebba9301a690d3)) +- **embed:** Remove Embed.setColor (#7662) ([9b0d8cb](https://github.com/discordjs/discord.js/commit/9b0d8cb2d8f7b55753de584eb3a3f347f87596c2)) +- **StageInstance:** Add support for associated guild event (#7576) ([3dff31f](https://github.com/discordjs/discord.js/commit/3dff31f63fe4afdcc818193d737e1917f1ac8105)) +- **VoiceState:** Add edit method (#7569) ([b162f27](https://github.com/discordjs/discord.js/commit/b162f27e46524bfc64515969d753c6e8f30e6c40)) +- **ModalSubmitInteraction:** Add boolean properties (#7596) ([8907390](https://github.com/discordjs/discord.js/commit/89073903a253d9408839573502c72cae93fe70b6)) +- Add Modals and Text Inputs (#7023) ([ed92015](https://github.com/discordjs/discord.js/commit/ed920156344233241a21b0c0b99736a3a855c23c)) +- **discord.js:** Partial transition to undici (#7482) ([5158332](https://github.com/discordjs/discord.js/commit/51583320d3b0f6452cd96bad1021f2a57e4cc6f6)) +- **message:** Add `reason` on pin and unpin (#7520) ([00728f7](https://github.com/discordjs/discord.js/commit/00728f72b36123b607502624b4b02a02ee524d4a)) +- Re-export AuditLogEvent enum (#7528) ([6a2fa70](https://github.com/discordjs/discord.js/commit/6a2fa70b8e79a460be38916eeb605976ad6fe68b)) +- **options:** Add support for custom JSON transformers (#7476) ([dee27db](https://github.com/discordjs/discord.js/commit/dee27db35af379b0835f9fd5cc19563f7bf3dfc0)) +- Add CategoryChannelChildManager (#7320) ([5cf5071](https://github.com/discordjs/discord.js/commit/5cf5071061760c2f9c1e36d7648aef544b03323a)) + - **Co-authored-by:** Antonio Román <kyradiscord@gmail.com> +- Attachment application command option type (#7200) ([0034396](https://github.com/discordjs/discord.js/commit/003439671d359dcfe481446ef12b90bd71c57835)) +- **builders:** Add attachment command option type (#7203) ([ae0f35f](https://github.com/discordjs/discord.js/commit/ae0f35f51d68dfa5a7dc43d161ef9365171debdb)) +- **scheduledevents:** Add image option (#7436) ([fbc71ef](https://github.com/discordjs/discord.js/commit/fbc71ef6b668c4b1e2b065d9b65541d9303db0a0)) +- Add methods to managers (#7300) ([dd751ae](https://github.com/discordjs/discord.js/commit/dd751ae19da196cc2f90ccd35c7d8e99878daaf9)) +- **channel:** Add .url getter (#7402) ([f59d630](https://github.com/discordjs/discord.js/commit/f59d6305cb0cd0d154a909f18be76407c4d452d3)) +- **components:** Add unsafe message component builders (#7387) ([6b6222b](https://github.com/discordjs/discord.js/commit/6b6222bf513d1ee8cd98fba0ad313def560b864f)) +- **thread:** Add `newlyCreated` to `threadCreate` event (#7386) ([51beda5](https://github.com/discordjs/discord.js/commit/51beda56f74e44ed013b5d25044b8d5fd1978b29)) +- **channel:** Add isDMBased typeguard (#7362) ([388f535](https://github.com/discordjs/discord.js/commit/388f53550cca7ded7350a050fda03c36e4c1fdf7)) +- **`Interaction`:** Add `.commandType` property to `CommandInteraction` and `AutocompleteInteraction` (#7357) ([567db60](https://github.com/discordjs/discord.js/commit/567db60475c8704661b2e788c9905ef364d6c00c)) +- **scheduledevent:** Add support for event cover images (#7337) ([355f579](https://github.com/discordjs/discord.js/commit/355f579771771a28a293c327a38574c8918d18f8)) +- **enumResolvers:** Strengthen typings (#7344) ([9a566e8](https://github.com/discordjs/discord.js/commit/9a566e8068f28fce87c07861ef1d2877c6ae105f)) +- Allow setting message flags when sending (#7312) ([706db92](https://github.com/discordjs/discord.js/commit/706db9228a91ef42e49d2ec749eac153b9ef75d0)) +- **minor:** Add application_id to Webhook (#7317) ([5ccdb0a](https://github.com/discordjs/discord.js/commit/5ccdb0ab266e4f74c331386ac2d6dd32bc225c62)) +- **threadchannel:** Add `createdTimestamp` field (#7306) ([9a16234](https://github.com/discordjs/discord.js/commit/9a1623425ae2d69f5c16f0096af4951ff5096e80)) +- **GuildPreview:** Add stickers (#7152) ([cf25de9](https://github.com/discordjs/discord.js/commit/cf25de9373df98b3c1cd0ca0a092d9dc8172929d)) +- Enum resolvers & internal enum string removal (#7290) ([213acd7](https://github.com/discordjs/discord.js/commit/213acd799738b888d550cdf3f08906764f8288e0)) +- **guildemojimanager:** Add `delete` and `edit` methods (#7286) ([9181a31](https://github.com/discordjs/discord.js/commit/9181a31e0ba330502052c94da544bb15c8b66f11)) +- **interaction:** Add `isRepliable` type guard (#7259) ([da05a88](https://github.com/discordjs/discord.js/commit/da05a8856b11cc1bf0df424c88a1cf9573e5b654)) +- **Channel:** Improve typeguards (#6957) ([37a22e0](https://github.com/discordjs/discord.js/commit/37a22e04c27724c2a65b05c701e3000ba3653ba1)) +- Add Locales to Interactions (#7131) ([9052e32](https://github.com/discordjs/discord.js/commit/9052e321d1c9c8841962d4e8dc5d9e060b104438)) +- **Permissions:** Remove deprecated thread-related permissions (#6755) ([ab3ff5a](https://github.com/discordjs/discord.js/commit/ab3ff5a262caf7d6225b8d6b54ab2c6b6613c0d0)) +- **VoiceRegion:** Remove the unsent vip field (#6759) ([caaef53](https://github.com/discordjs/discord.js/commit/caaef53dd97ecac9f714072ddba5ae9a99ab1027)) +- **richpresenceassets:** Add YouTube and custom image support (#7184) ([d06d70c](https://github.com/discordjs/discord.js/commit/d06d70ccf26c04c1122fac8430922588a489f95e)) +- **Collector:** Yield all collected values (#7073) ([2b480cb](https://github.com/discordjs/discord.js/commit/2b480cb14e6f52855efcb372da7fb455c15b13b1)) + +## Refactor + +- **Util:** Rename `fetchRecommendedShards` (#8298) ([cafde77](https://github.com/discordjs/discord.js/commit/cafde77d73452d729ba8e2cb1cac3f14235b889b)) +- **Embed:** Add all the types (#8254) ([64f8140](https://github.com/discordjs/discord.js/commit/64f814066cc4adebaca47eb8d7a2040a8df399ae)) +- **rest:** Add content-type(s) to uploads (#8290) ([103a358](https://github.com/discordjs/discord.js/commit/103a3584c95a7b7f57fa62d47b86520d5ec32303)) +- Make `GuildAuditLogsEntry.action` return an `AuditLogEvent` (#8256) ([f0b68d5](https://github.com/discordjs/discord.js/commit/f0b68d57368d7ac3db97925df68c11a945ccd84c)) +- **builder:** Remove `unsafe*Builder`s (#8074) ([a4d1862](https://github.com/discordjs/discord.js/commit/a4d18629828234f43f03d1bd4851d4b727c6903b)) +- Make `ShardEvents` the events of `Shard` (#8185) ([c5750d5](https://github.com/discordjs/discord.js/commit/c5750d59f529ab48a5bc88a73a1c449ef6ddbffd)) +- **Util:** Make single `replace` call in `cleanContent` (#8210) ([6b20645](https://github.com/discordjs/discord.js/commit/6b206457400ce31d566b02a0c135042afb540853)) +- **ApplicationCommandManager:** Use `makeURLSearchParams` (#8196) ([cb3dca4](https://github.com/discordjs/discord.js/commit/cb3dca4ae029724421f3d04a784ace0ae2de75e2)) +- Use `Base` prefix for channel and interaction base classes (#8099) ([e24970e](https://github.com/discordjs/discord.js/commit/e24970e3c3d24f71ba711e59666cd8a49a33e33b)) +- **Constants:** Remove leftover code (#8156) ([cd17aad](https://github.com/discordjs/discord.js/commit/cd17aad720430d23af51c364caeb8b22bf6cb6b5)) +- Errors (#8068) ([e68effa](https://github.com/discordjs/discord.js/commit/e68effa822f064a324ed5b92e797c9fc3ce5e211)) +- **ClientOptions:** Remove `$` prefix from `ws.properties` keys (#8094) ([90a98fe](https://github.com/discordjs/discord.js/commit/90a98fee16b7d1d06768461f4e85127c0edf8419)) +- Use `GuildFeature` enum (#8101) ([e5ec1c4](https://github.com/discordjs/discord.js/commit/e5ec1c4dbc3fa54b2c43d1fec24932d7363e17cb)) +- **util:** Make utility functions top level (#8052) ([e53d162](https://github.com/discordjs/discord.js/commit/e53d1621986035b0c92a1782f6e013d408480e00)) +- **ApplicationCommand:** Permissions v2 (#7857) ([c7391db](https://github.com/discordjs/discord.js/commit/c7391db11b3efd4b1a6904affb26887ad06d6db4)) +- ***:** Include name/reason/etc fields into options/data params (#8026) ([9c8b310](https://github.com/discordjs/discord.js/commit/9c8b3102ce00d1f2c1255c150fb3030f8b6dd026)) +- **ThreadMemberManager:** Consistent thread member fetching (#8021) ([da9107c](https://github.com/discordjs/discord.js/commit/da9107c007536952107bd92943b6c714538d5aeb)) +- **interactions:** Remove redundant interaction typeguards (#8027) ([f57d676](https://github.com/discordjs/discord.js/commit/f57d6768ad24f6e37dc598f9c93709449d3bc4dd)) +- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a)) +- **channel:** Remove redundant channel type guards (#8012) ([70c733b](https://github.com/discordjs/discord.js/commit/70c733bb9a5bde0f79e6bea0bdc416458bda4c06)) +- Always return `Message` instances in interactions (#7917) ([9720e55](https://github.com/discordjs/discord.js/commit/9720e555340431c3b3ad7bd670ad0ac7eee8865f)) +- **attachment:** Don't return attachment builders from API (#7852) ([dfadcbc](https://github.com/discordjs/discord.js/commit/dfadcbc2fd50be64c8a0c1cae3be10f83678c5ee)) +- Clean up modal submissions (#7994) ([643dab3](https://github.com/discordjs/discord.js/commit/643dab3b1b5305d002fcefed62755bbe11fc3267)) +- **ThreadChannel:** Remove `MAX` helper from threads (#7846) ([dfd9eb2](https://github.com/discordjs/discord.js/commit/dfd9eb20b2d3e0e7db26744b1f15134ac6eda139)) +- **Activity:** Remove undocumented properties (#7844) ([5ba7740](https://github.com/discordjs/discord.js/commit/5ba7740fcfefda1eeba81ace4e6351eac02522a4)) +- **MessageAttachment:** Use `Attachment` instead (#7691) ([ab4c608](https://github.com/discordjs/discord.js/commit/ab4c608b97ff319935e1a7f23564622bfd7ddd57)) +- **Util:** Remove splitting (#7780) ([54e5629](https://github.com/discordjs/discord.js/commit/54e56299865a6746744544ba25d5540a1166d27c)) +- Tidy up builders and components (#7711) ([96a0d83](https://github.com/discordjs/discord.js/commit/96a0d83a1366703ecae40b5e0d5171be9123d079)) +- Remove nickname parsing (#7736) ([78a3afc](https://github.com/discordjs/discord.js/commit/78a3afcd7fdac358e06764cc0d675e1215c785f3)) +- Remove store channels (#7634) ([aedddb8](https://github.com/discordjs/discord.js/commit/aedddb875e740e1f1bd77f06ce1b361fd3b7bc36)) +- **IntegrationApplication:** Remove `summary` (#7729) ([eb6b472](https://github.com/discordjs/discord.js/commit/eb6b472f72488cad7e96befccc00270cf6dc01b8)) +- **GuildAuditLogs:** Remove build (#7704) ([cedd053](https://github.com/discordjs/discord.js/commit/cedd0536baa1301984daf89dfda4e63a7be595a2)) +- **InteractionCollector:** Simplify constructor logic (#7667) ([07b23a9](https://github.com/discordjs/discord.js/commit/07b23a99c7088a7c740f23051f3f755f091519b0)) +- Remove undocumented checks (#7637) ([9a6e691](https://github.com/discordjs/discord.js/commit/9a6e691eaa6c3d133098b2734414590cb838de2e)) +- Allow builders to accept emoji strings (#7616) ([fb9a9c2](https://github.com/discordjs/discord.js/commit/fb9a9c221121ee1c7986f9c775b77b9691a0ae15)) +- Use `static` fields (#7701) ([e805777](https://github.com/discordjs/discord.js/commit/e805777a7a81d1dc7a2edd9741ecb04e685a3886)) +- **EmbedBuilder:** Allow hex strings in setColor (#7673) ([f472975](https://github.com/discordjs/discord.js/commit/f4729759f600372455f062c75859f084e23a5d78)) +- Don't return builders from API data (#7584) ([549716e](https://github.com/discordjs/discord.js/commit/549716e4fcec89ca81216a6d22aa8e623175e37a)) +- **embed:** Allow hex strings in `setColor()` (#7593) ([79d6c04](https://github.com/discordjs/discord.js/commit/79d6c0489c3d563fdd05de63c4fcf93a6deefce1)) +- **InteractionResponses:** Use ClientOptions.jsonTransformer (#7599) ([fac55bc](https://github.com/discordjs/discord.js/commit/fac55bcfd1e8b76aae1273415f74fa6de7aca66d)) +- Deprecate invite stage instance (#7437) ([d2bc9d4](https://github.com/discordjs/discord.js/commit/d2bc9d444f42a70a3c4cc4c68eb107bcaebec509)) +- **guild:** Move `premiumSubscriptionCount` to `AnonymousGuild` (#7451) ([6d3da22](https://github.com/discordjs/discord.js/commit/6d3da226d3c003d137639e719394a807330e4844)) +- **actions:** Use optional chaining (#7460) ([d1bb362](https://github.com/discordjs/discord.js/commit/d1bb36256f2f86022884e6ee9e05b0536cb6384d)) +- **guildbanmanager:** Rename days option to deleteMessageDays (#7447) ([0dfdb2c](https://github.com/discordjs/discord.js/commit/0dfdb2cf11e236e67dd34277108973b5b79790a8)) +- Make public builder props getters (#7422) ([e8252ed](https://github.com/discordjs/discord.js/commit/e8252ed3b981a4b7e4013f12efadd2f5d9318d3e)) +- Remove redundant API defaults (#7449) ([532846b](https://github.com/discordjs/discord.js/commit/532846b1f8260d85022a022d093553310052afc9)) +- Allow discord.js builders to accept camelCase (#7424) ([94bf727](https://github.com/discordjs/discord.js/commit/94bf727cc3a2f11c88e95cdb151b235f775cd1ca)) +- Replace `WSCodes`, `WSEvents`, and `InviteScopes` with `discord-api-types` equivalent (#7409) ([cc25455](https://github.com/discordjs/discord.js/commit/cc25455d2c75177e3eddc880b7fd53cb122387c4)) +- Make constants enums top level and `PascalCase` (#7379) ([d8184f9](https://github.com/discordjs/discord.js/commit/d8184f94dd08daab37195f52828e06af5ed1c1e0)) +- **`Bitfield`:** Use discord-api-types enums instead (#7313) ([fbb1d03](https://github.com/discordjs/discord.js/commit/fbb1d0328bcd517027ad2eedb8753d17489ed851)) +- Use `@discordjs/rest` (#7298) ([ec0fba1](https://github.com/discordjs/discord.js/commit/ec0fba1ed0d3c5b1bb18171ece6fe5ee42d48497)) +- Switch to /builders `Embed` (#7067) ([d2d3a80](https://github.com/discordjs/discord.js/commit/d2d3a80c556a104099a1ddb1b24f1b921c553257)) +- Remove transformPermissions (#7303) ([b4ed8fd](https://github.com/discordjs/discord.js/commit/b4ed8fd3ed953085cd908b2845d4384c8555d3a2)) +- Remove VoiceChannel#editable (#7291) ([164589c](https://github.com/discordjs/discord.js/commit/164589c5516a847457444d11098981d557b6778b)) +- Remove boolean option for `Webhook#fetchMessage` (#7293) ([347ff80](https://github.com/discordjs/discord.js/commit/347ff80bbc9bc5243b7f68ba5d745782eadeba21)) +- **subcommandgroup:** Required default to false (#7217) ([6112767](https://github.com/discordjs/discord.js/commit/6112767128a664f32205425f52ba52220d57834f)) +- **invite:** Make `channel` and `inviter` getters (#7278) ([18b0ed4](https://github.com/discordjs/discord.js/commit/18b0ed4cbe8285637a971c7c99ee49d18060a403)) +- Remove required from getMember (#7188) ([c90e47f](https://github.com/discordjs/discord.js/commit/c90e47f90403e5b1b3499b213dcdf2704fd96b66)) +- Remove djs components and use /builders components instead (#7252) ([101d7c5](https://github.com/discordjs/discord.js/commit/101d7c5ffa03edcf8cb8a0647b77d5c9a38e4bdd)) +- Default *URL methods to animated hash (#7149) ([7c07976](https://github.com/discordjs/discord.js/commit/7c07976018728154be0ce0314d3e8dfe8eb9ed5b)) +- Use setPosition inside edit (#7263) ([0b23b7f](https://github.com/discordjs/discord.js/commit/0b23b7f0394a20596c8d85b82870c3f35ea6b0e0)) +- Don't disable import order lint (#7262) ([0a5d5f3](https://github.com/discordjs/discord.js/commit/0a5d5f38c0b1a249fa2efe16f3b601c90622a4d5)) +- Remove discord.js enums and use discord-api-types enums instead (#7077) ([aa6d1c7](https://github.com/discordjs/discord.js/commit/aa6d1c74de01dd9a8f020c43fb2c193c4729df8d)) +- **application:** Remove fetchAssets (#7250) ([1479e40](https://github.com/discordjs/discord.js/commit/1479e40bcecc4c28ecb9f05fa4fbbdfe3bd387e1)) +- PresenceUpdate and demuxProbe (#7248) ([1745973](https://github.com/discordjs/discord.js/commit/174597302408f13c5bb685e2fb02ae2137cb481d)) +- **embeds:** Don't create new embed instances when unnecessary (#7227) ([822dc67](https://github.com/discordjs/discord.js/commit/822dc678da626de7b4fb22a747cd3cd2e8376732)) +- **GuildMember:** Throw better errors on #kickable and #bannable (#7137) ([4fd127e](https://github.com/discordjs/discord.js/commit/4fd127e79edfa1851f8a10242838f9d7aa68c8c3)) +- **SnowflakeUtil:** Switch to `@sapphire/snowflake` (#7079) ([e082dfb](https://github.com/discordjs/discord.js/commit/e082dfb1584926e4c05face5966d16e4a2921bc5)) +- **InteractionCreate:** Remove interaction event (#6326) ([ae876d9](https://github.com/discordjs/discord.js/commit/ae876d962453ccf843f8e6f70666a98a3173bb75)) +- **MessageCreate:** Remove message event (#6324) ([171e917](https://github.com/discordjs/discord.js/commit/171e917fb96b6bf39a6ad70e83be646f72fe451e)) +- **integration:** Turn undefined into null and consistency (#7209) ([13eb782](https://github.com/discordjs/discord.js/commit/13eb78256da901e6c3c405f546f36617ef5e8239)) +- Remove `deleted` field (#7092) ([cee7fd1](https://github.com/discordjs/discord.js/commit/cee7fd181c464e44eabf20b511d12589f2453722)) +- **Dates:** Save timestamps everywhere and use Date.parse (#7108) ([55e21f5](https://github.com/discordjs/discord.js/commit/55e21f53663a91863c63b6d9f3a8c35564664061)) +- **RoleManager:** Remove `comparePositions()` (#7201) ([fbbac27](https://github.com/discordjs/discord.js/commit/fbbac279789427b2c36869dc47b65fb08431e14d)) +- Better Command Terminology (#7197) ([b7856e7](https://github.com/discordjs/discord.js/commit/b7856e7809ff6fa21fe00286f885808535624f7c)) +- **Actions:** Remove deleted maps (#7076) ([5022b14](https://github.com/discordjs/discord.js/commit/5022b14da09e9b421f947e9bc385a0574cbf07d1)) +- **Client:** Remove applicationCommand events (#6492) ([6085b4f](https://github.com/discordjs/discord.js/commit/6085b4f72723d4ff82f7fea504241d14c94af21e)) +- Remove `Util.removeMentions()` (#6530) ([0c24cc8](https://github.com/discordjs/discord.js/commit/0c24cc8ec0d818315cc8f8bcf74fce060847ac79)) +- **Constants:** Change APPLICATION_COMMAND -> CHAT_INPUT_COMMAND (#7018) ([75616a3](https://github.com/discordjs/discord.js/commit/75616a305f9af33013486b13a872a39212101ce7)) +- **Guild:** Remove deprecated setXPositions methods (#6897) ([43e5e3c](https://github.com/discordjs/discord.js/commit/43e5e3c339a96fa895267d4538eee1d5e5843d05)) +- **UserFlags:** Update flag names (#6938) ([b246fc4](https://github.com/discordjs/discord.js/commit/b246fc4101b8e4957ffd1af8e2e4986a020ca211)) + +## Styling + +- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629)) + +## Typings + +- **GuildFeature:** Allow feature strings to be passed (#8264) ([b7d4e55](https://github.com/discordjs/discord.js/commit/b7d4e55419207d4e25f5c40cab221c7c04a617bf)) +- **CategoryChannelChildManager:** Fix Holds type (#8288) ([33a7a5c](https://github.com/discordjs/discord.js/commit/33a7a5cbdc00d2a5034dc1ec91fec5da7042f9d0)) +- Remove `MemberMention` (#8292) ([bf65b37](https://github.com/discordjs/discord.js/commit/bf65b37d1a9ea8417e26ad4afacea1eb45a0ff5a)) +- **GuildMemberManager:** Fix placement for `fetchMe()` (#8258) ([7525615](https://github.com/discordjs/discord.js/commit/75256153a9923d94ca709a37aaccc48dfb43c153)) +- Convert `Events` to an enum (#8246) ([feb3bdd](https://github.com/discordjs/discord.js/commit/feb3bdda0a3c3da80378c8cbcafca2968551eef9)) +- **GuildMemberManager:** Non-void return of `edit()` (#8186) ([c7a205f](https://github.com/discordjs/discord.js/commit/c7a205f7b992eea43af13a4638e2a03db7bc0d8a)) +- Add missing shard types (#8180) ([27d8deb](https://github.com/discordjs/discord.js/commit/27d8deb4716a87704370a95103b16fa1b763de18)) +- Implement `GuildChannelEditOptions` (#8184) ([b83e0c0](https://github.com/discordjs/discord.js/commit/b83e0c0caffc2b767aa1ba4412580970a6901899)) +- **Status:** Add missing members (#8179) ([8421f92](https://github.com/discordjs/discord.js/commit/8421f9203bd2d85ef8e64c3fb9a991c74223a75d)) +- **GuildScheduledEvent#scheduledStartAt:** Should be nullish (#8111) ([65dc8d6](https://github.com/discordjs/discord.js/commit/65dc8d677ee81469c0eeb4ecdd83fe2f68cc8982)) +- Fix modal builder constructor data type (#8143) ([7279f9c](https://github.com/discordjs/discord.js/commit/7279f9c31b14bc1e78c63b7298e80e37ca5dfe0c)) +- Use `ThreadAutoArchiveDuration` from discord-api-types (#8145) ([a3799f9](https://github.com/discordjs/discord.js/commit/a3799f9ebb027904830457119708d550e2009200)) +- **Shard#reconnecting:** Fix event name (#8118) ([95e6d6e](https://github.com/discordjs/discord.js/commit/95e6d6ede03c4fb92a8d8027a085e84b043fd895)) +- **ApplicationCommand:** Fix typo in setDMPermission (#8097) ([4df491c](https://github.com/discordjs/discord.js/commit/4df491ce8578a1b01ee8412a4df8137a302e7202)) +- Fix `setType()` parameter and `ChannelData.type` (#8089) ([b4e28a8](https://github.com/discordjs/discord.js/commit/b4e28a8ff6bf165c54a8726d3bc3a3cc0c1e469b)) +- Fix `ApplicationCommandPermissionsUpdate` event typings (#8071) ([9964454](https://github.com/discordjs/discord.js/commit/9964454c2944a0523399481a5f609144486e549b)) +- **AutocompleteOption:** Fix and improve types (#8069) ([476b7d5](https://github.com/discordjs/discord.js/commit/476b7d519c719152ea04e207f6dd09bb23e733db)) +- **ThreadMemberManager:** Fix return type of fetching members with no arguments (#8060) ([2392a6f](https://github.com/discordjs/discord.js/commit/2392a6f5de2efcf6b326173d26295c928b94adb6)) +- Remove isAutocomplete typeguard from typings (#8063) ([c0f079d](https://github.com/discordjs/discord.js/commit/c0f079d2325a636c83ac676c525bfa89ce308b3c)) +- **AttachmentBuilder:** Fix data type (#8016) ([7fa698d](https://github.com/discordjs/discord.js/commit/7fa698d23e548987762c4c66c96c510d9ea56eb4)) +- **modal:** Fix `showModal()` typings (#8014) ([0ccc243](https://github.com/discordjs/discord.js/commit/0ccc243c8ffbf852660c899cc2ad47bd5ebb65cb)) +- Fix some attachment related typings (#8013) ([6aa6232](https://github.com/discordjs/discord.js/commit/6aa623240ee94b117c7e69c1d09b50923a8f7a4c)) +- **AttachmentBuilder:** Remove name parameter from constructor (#8008) ([6266b0c](https://github.com/discordjs/discord.js/commit/6266b0c1e323f9522010f90f34ce6f17fcb6e769)) +- Add types to `EventEmitter` static methods (#7986) ([d60c464](https://github.com/discordjs/discord.js/commit/d60c464e618e4159d2656e7832798909832f33cd)) +- Nullify `guildScheduledEventUpdate`'s old parameter (#7955) ([fdeac9d](https://github.com/discordjs/discord.js/commit/fdeac9d9fba06c532eca296ddd8479047bc732bf)) +- Make `CacheType` generic more accurate for return values (#7868) ([e07b910](https://github.com/discordjs/discord.js/commit/e07b910e684bc3cf71fb93417951ad42351bace4)) +- **guildScheduledEvent:** Mark `entityMetadata` as nullable (#7908) ([64bdf53](https://github.com/discordjs/discord.js/commit/64bdf53116945ffb51764bb8ec539d530aefcfb1)) +- **discord.js:** Export missing enums (#7864) ([5eeef3f](https://github.com/discordjs/discord.js/commit/5eeef3f708eb900ec994d837fb4cd414a4f4b437)) +- Fix return type of `toString()` on channels (#7836) ([ece6289](https://github.com/discordjs/discord.js/commit/ece628986c7eb1a66f46076d8f8518c9ff00aaf3)) +- **Message#activity:** Make `partyId` optional and use enum for `type` (#7845) ([bfeaf85](https://github.com/discordjs/discord.js/commit/bfeaf856f76eb7cb756ac55aac13636ccdb345b6)) +- Cleanup *Data type definitions (#7716) ([585169f](https://github.com/discordjs/discord.js/commit/585169f2f097ffb1940d17f549e4290aa55acde2)) +- Fix BooleanCache never resolving to true (#7809) ([440ac24](https://github.com/discordjs/discord.js/commit/440ac243ca1d6f8cd04603e63e3f2f6ea1722ee8)) +- **CommandInteraction:** Add awaitModalSubmit (#7811) ([a6d9ce5](https://github.com/discordjs/discord.js/commit/a6d9ce57c6cae90d0afc60010cad44fdc2c2d06c)) +- **ThreadChannel:** Fix autoArchiveDuration types (#7816) ([0857476](https://github.com/discordjs/discord.js/commit/08574763eb665b5a43ccfb826929f1e3f0d1c3a7)) +- Add missing typing (#7781) ([f094e33](https://github.com/discordjs/discord.js/commit/f094e338617a1a3c9f48a325e4b8e9b5a405aa91)) +- **VoiceChannel:** Nullify property (#7793) ([446eb39](https://github.com/discordjs/discord.js/commit/446eb390ce58b7e7f60e297b25f53773a55f7fb9)) +- **ModalSubmitInteraction:** Message (#7705) ([b577bcc](https://github.com/discordjs/discord.js/commit/b577bcc1df5c6424fef9984e19a5f11c77371cf3)) +- **Embed:** Add missing getters and add video to EmbedData (#7728) ([fd1dc72](https://github.com/discordjs/discord.js/commit/fd1dc72c0a77dbe18753d8db22972dfa5fe4ab36)) +- **ModalSubmitInteraction:** Fix `components` type (#7732) ([6f4e97b](https://github.com/discordjs/discord.js/commit/6f4e97bfafe4a058f6ec85d321676401d701ee55)) +- **interactionCollector:** Filter should have a collected argument (#7753) ([e4f2705](https://github.com/discordjs/discord.js/commit/e4f27051ca921d299c302b600a8c2917e9356ef6)) +- Fix regressions (#7649) ([5748dbe](https://github.com/discordjs/discord.js/commit/5748dbe08783beb80c526de38ccd105eb0e82664)) +- **Constants:** Add `NonSystemMessageTypes` (#7678) ([9afc030](https://github.com/discordjs/discord.js/commit/9afc03054e4c8973702d6c18e618643f76382dd9)) +- Fix auto archive duration type (#7688) ([8e3b2d7](https://github.com/discordjs/discord.js/commit/8e3b2d7abd38136534969cf77c6a748ee3a20355)) +- **InteractionResponseFields:** Add webhook (#7597) ([daf2829](https://github.com/discordjs/discord.js/commit/daf2829cb58d1a44cb1f1ece21e428d1a23e99c9)) +- **Embed:** Add forgotten `footer` type (#7665) ([8fb9816](https://github.com/discordjs/discord.js/commit/8fb98165a9d098ab316475d6baacb015783eb638)) +- **ColorResolvable:** Simplify string types (#7643) ([2297c2b](https://github.com/discordjs/discord.js/commit/2297c2b9479ace16f5f7155479605a4ac2718e3d)) +- Allow component classes in action row data (#7614) ([230c0c4](https://github.com/discordjs/discord.js/commit/230c0c4cb137882ff7bab783a4aeaa83ae941de5)) +- **ActionRow:** Allow components to be passed to constructors (#7531) ([e71c76c](https://github.com/discordjs/discord.js/commit/e71c76c7f795837dbcc3576e507bd286640b4296)) +- **showModal:** Align types with the documentation (#7600) ([0d7e4ed](https://github.com/discordjs/discord.js/commit/0d7e4edd969513692c061c107be4bbe7e4b54321)) +- Modals type and doc fixes (#7608) ([93854a8](https://github.com/discordjs/discord.js/commit/93854a8013d07234cb849bfcbfa99f74a4c3cdb4)) +- **InteractionResponseFields:** Add boolean properties (#7565) ([53defb8](https://github.com/discordjs/discord.js/commit/53defb82e36108468e35077b887ee28b811891ab)) +- Allow raw components for reply and message options (#7573) ([2d4971b](https://github.com/discordjs/discord.js/commit/2d4971b032a01c05b55c93d6475e61b0d25d69d3)) +- Fix component *Data types (#7536) ([a8321d8](https://github.com/discordjs/discord.js/commit/a8321d8026df2e6a09d867939986bf77f894f3a8)) +- Use discord-api-types `Locale` (#7541) ([8346003](https://github.com/discordjs/discord.js/commit/83460037be840ba623f3b02a3e6f218943f9d2b7)) +- **anychannel:** Add PartialGroupDMChannel (#7472) ([cf66930](https://github.com/discordjs/discord.js/commit/cf669301c7be8eaecf91d7f764eccc67d7a5b4c6)) +- Remove `ApplicationCommandInteractionOptionResolver` (#7491) ([71f4fa8](https://github.com/discordjs/discord.js/commit/71f4fa82ed6206d6843345a5394119f2a728aa35)) +- **embed:** Fix timestamp allowed types (#7470) ([7959a68](https://github.com/discordjs/discord.js/commit/7959a68d8ec600af248f5506f39871cae7eeeb04)) +- Remove duplicate rate limit for thread creation (#7465) ([2d2de1d](https://github.com/discordjs/discord.js/commit/2d2de1d3fd15a098d69e09710e9a7a3352234fef)) +- Correct types for InteractionCollector guild and channel (#7452) ([6ce906a](https://github.com/discordjs/discord.js/commit/6ce906a02fcb051cb6df3e9f453ba9f53db03bd0)) +- Fix `GuildAuditLogsTypes` keys & typos (#7423) ([3d8c776](https://github.com/discordjs/discord.js/commit/3d8c77600be51a86a99b526078bb1b1fcb9a0811)) +- Remove duplicate `GuildChannelOverwriteOptions` interface (#7428) ([83458ff](https://github.com/discordjs/discord.js/commit/83458ff7c782b8efdaaac931d2dee1764dad25bf)) +- Use `GuildFeature` enum from `discord-api-types` (#7397) ([a7b80b9](https://github.com/discordjs/discord.js/commit/a7b80b9d9bf4902bd85b592986771eadf7a765dc)) +- Fix *BitField.Flags properties (#7363) ([e6a26d2](https://github.com/discordjs/discord.js/commit/e6a26d25b3cf8dfcc8aa8997b021f1774f3b754b)) +- Fix MessageMentions channel types (#7316) ([c05b388](https://github.com/discordjs/discord.js/commit/c05b38873bb3c37c6e4ebcb6b6373a8858cc03de)) +- Fix channel create overloads (#7294) ([1c6c944](https://github.com/discordjs/discord.js/commit/1c6c9449ad68601c6c98748d73be8114401d38ef)) +- Fix regressions and inconsistencies (#7260) ([26a9dc3](https://github.com/discordjs/discord.js/commit/26a9dc32062cd071917bbe7264050315b4d6dd3c)) +- **interaction:** Remove renamed typeguards (#7220) ([68b9564](https://github.com/discordjs/discord.js/commit/68b9564f1821726377a1e929a3ca1fc65b4ad598)) +- AssertType -> expectType ([3f36746](https://github.com/discordjs/discord.js/commit/3f36746561a40cd61a7cd2e054b7ef80d58fc707)) +- Fix cache types resolving to `never` (#7164) ([c978dbb](https://github.com/discordjs/discord.js/commit/c978dbb6233bcd85408caf0bca7619c9c5d508f0)) + +# [14.12.0](https://github.com/discordjs/discord.js/compare/14.11.0...14.12.0) - (2023-07-31) + +## Bug Fixes + +- **ChannelUpdate:** Check against unknown channels (#9697) ([7fb91c5](https://github.com/discordjs/discord.js/commit/7fb91c57f72b74395d67f2207246033c703f1f19)) +- **Action:** Use existing recipients if available (#9653) ([719e54a](https://github.com/discordjs/discord.js/commit/719e54a921f74890519f066a9f56e52fdcfacf07)) +- Everyone role members (#9685) ([0803eb5](https://github.com/discordjs/discord.js/commit/0803eb562bdc7644fa611a0a87dea3e8b0d4c7af)) +- `awaitMessageComponent` with `MessageComponentInteraction`s (#8598) ([b61e4fb](https://github.com/discordjs/discord.js/commit/b61e4fb0dcb9e5d43a7626c5a4760f5801e06fae)) +- **ThreadManager:** Fix internal crash upon conditionally resolving thread members (#9648) ([a6dbe16](https://github.com/discordjs/discord.js/commit/a6dbe163dd3df12ad98465b1dfc040b8eff8805e)) +- **User:** Check global name in equals (#9631) ([8f3bd38](https://github.com/discordjs/discord.js/commit/8f3bd3807233fca2a057948406bdc8aef008b6cb)) +- **WebSocketManager:** Await WebSocket destroy (#9519) ([75308f2](https://github.com/discordjs/discord.js/commit/75308f266933454301b10ee8e1d940d782fdb637)) +- **Client:** Safe call for possibly null WebSocket (#9600) ([24a6149](https://github.com/discordjs/discord.js/commit/24a61495b9bf07887dd535a05ffbec2895faa888)) +- **ThreadManager:** Ensure `fetchActive()` only returns active threads in a channel (#9568) ([53aa24d](https://github.com/discordjs/discord.js/commit/53aa24d41809382c1af57bd1871107c8359e4a15)) +- **LimitedCollection:** Allow items to be stored if keepOverLimit is true when maxSize is 0 (#9534) ([9345d1b](https://github.com/discordjs/discord.js/commit/9345d1b1ac4f7b1f66b919602dff995782151407)) +- **AutocompleteInteraction:** Prevent snake casing of locales (#9565) ([7196fe3](https://github.com/discordjs/discord.js/commit/7196fe36e8089dde7bcaf0db4dd09cf524125e0c)) + +## Documentation + +- Change `Channel` to `BaseChannel` (#9718) ([e5effb6](https://github.com/discordjs/discord.js/commit/e5effb6f6a3e547006eb9bc054cc168844a157f2)) +- **BaseChannel:** Remove `APIChannel` (#9717) ([125405f](https://github.com/discordjs/discord.js/commit/125405f1cf11433c69ff1ae9d6b8f7e713fc37c0)) +- **BuildersSelectMenuOption:** Update link (#9690) ([ede9f4e](https://github.com/discordjs/discord.js/commit/ede9f4e5e203bcfb8820ae7ec3418482735ff9c1)) +- **ClientOptions:** Change default value of sweepers in docs (#9591) ([911e6ef](https://github.com/discordjs/discord.js/commit/911e6eff75f5d05e837d5dfaacf557d6594df16a)) +- **Client:** Correct invite gateway permission checks (#9597) ([e1b6eee](https://github.com/discordjs/discord.js/commit/e1b6eeed0e2e18f9900bc945c9f82d2d05f28a78)) +- Fix broken links to new documentation (#9563) ([d01e8aa](https://github.com/discordjs/discord.js/commit/d01e8aa8af00f5caacffe98caef3ead02e80a9bf)) + +## Features + +- Add ws option support for "buildIdentifyThrottler" (#9728) ([6307f81](https://github.com/discordjs/discord.js/commit/6307f813854ed9dc76d2c4351bd69dd0490d0928)) +- **Client:** Add `guildAvailable` event (#9692) ([3c85fb2](https://github.com/discordjs/discord.js/commit/3c85fb21e62b30e75a7200b704e242c3a0adeda1)) +- User avatar decorations (#8914) ([8d97017](https://github.com/discordjs/discord.js/commit/8d9701745840e23854e8f0b057d21cb10e7d1d54)) +- Add silent option to ShardingManager (#9506) ([df40dcd](https://github.com/discordjs/discord.js/commit/df40dcdb850c398642ebc5cd6e4c48034280f464)) +- **EmbedBuilder:** Add `.length` (#8682) ([53c17e0](https://github.com/discordjs/discord.js/commit/53c17e00c0668c3d1497142dde7384c058c46c64)) +- Guild onboarding (#9120) ([dc73c93](https://github.com/discordjs/discord.js/commit/dc73c938ff9d04a0d7d57630faeb8e81ea343006)) +- Add resume event in shard (#9650) ([a73d54e](https://github.com/discordjs/discord.js/commit/a73d54e43a01719f683e8fd21714e85ffe737add)) +- **presence:** Re-introduce image resolving for other platforms (#9637) ([73c2f8a](https://github.com/discordjs/discord.js/commit/73c2f8aa17aac51b05382444148cb1f60081ee03)) +- Add message to send resume event to shard (#9626) ([a873ec1](https://github.com/discordjs/discord.js/commit/a873ec1e8511829ba95e85bbc9a4074e40c76086)) +- Support new username system (#9512) ([1ab60f9](https://github.com/discordjs/discord.js/commit/1ab60f9da4d6b7ea144fa05b97b029a4bfaeede2)) +- **GuildAuditLogsEntry#extra:** Add missing `channel` property (#9518) ([2272321](https://github.com/discordjs/discord.js/commit/227232112d1cd9f211e177996b7cdee2940f471e)) + +## Performance + +- **Channel:** Linear speed position getter (#9497) ([09b0382](https://github.com/discordjs/discord.js/commit/09b0382c458ed0f3df5b8fa778c504b3e658ac49)) +- **Role:** Improve `members` getter (#9529) ([37181ab](https://github.com/discordjs/discord.js/commit/37181ab2322e48e17ff0d1040bcc510dc7c34e93)) + +## Refactor + +- **User:** Remove deprecation warning from tag (#9660) ([cf8012c](https://github.com/discordjs/discord.js/commit/cf8012c20022aff184d7bce0ad436c136e428d9c)) +- **GuildMember:** Make `_roles` property non-enumerable (#9387) ([46167a7](https://github.com/discordjs/discord.js/commit/46167a79d7d0cac5599459a31c33b2bbcf6e06da)) +- **rest:** Switch api to fetch-like and provide strategies (#9416) ([cdaa0a3](https://github.com/discordjs/discord.js/commit/cdaa0a36f586459f1e5ede868c4250c7da90455c)) + +## Typings + +- **MessageManager:** Allow comparison of messages again (#9612) ([a48d0ef](https://github.com/discordjs/discord.js/commit/a48d0efb09613eac6bf3c1bd996f58f5fff7667c)) +- **AutoModerationActionExecution:** Add forum channels as a possible type in `channel()` (#9623) ([d64330a](https://github.com/discordjs/discord.js/commit/d64330a1570b3a2047ef959a6bce268372c70e99)) +- **ModalSubmitFields:** Components is an array (#9406) ([1cab79f](https://github.com/discordjs/discord.js/commit/1cab79f6fde6f367141c9f7ed91bcb70ed2e5c17)) +- Use `readonly` arrays and `const` type parameters in places (#9641) ([cd69868](https://github.com/discordjs/discord.js/commit/cd6986854f4c2d143d2cd9b81d096738480dfa63)) +- **BaseInteraction:** `appPermissions` not `null` in guilds (#9601) ([6c2242f](https://github.com/discordjs/discord.js/commit/6c2242f4f970b1c75c243f74ae64f30ecbf8ba0d)) + +# [14.11.0](https://github.com/discordjs/discord.js/compare/14.10.2...14.11.0) - (2023-05-06) + +## Bug Fixes + +- **WebSocketManager:** Properly emit shard error events (#9521) ([e627468](https://github.com/discordjs/discord.js/commit/e6274681fd10b0d75e1d3b448c94b50ec6810367)) +- **WebSocketManager:** Emit raw ws events again (#9502) ([c429763](https://github.com/discordjs/discord.js/commit/c429763be8e94f0f0cbc630e8bb1d415d46f1465)) + +## Documentation + +- **Client:** Update Sapphire's snowflake utility links (#9501) ([1b7981e](https://github.com/discordjs/discord.js/commit/1b7981e4696b8ae74ceffa876fc0a9be7d0b9f93)) + +## Features + +- **Guild:** Safety alerts channel and mention raid protection (#8959) ([6b2c3fb](https://github.com/discordjs/discord.js/commit/6b2c3fb9d0571de808e990cf064f73240ab93451)) + +## Performance + +- **Role:** Linear speed position getter (#9493) ([8e9a2b4](https://github.com/discordjs/discord.js/commit/8e9a2b4630f78bb9e45345ec2a16812bfac70a20)) + +## Refactor + +- **GuildChannel:** Simplify constructor (#9499) ([f2ad076](https://github.com/discordjs/discord.js/commit/f2ad0762c521422ab64e5b10344a6fd67961031b)) + +## Typings + +- **StringSelectMenuComponentData:** `options` is required (#9515) ([d7b18f0](https://github.com/discordjs/discord.js/commit/d7b18f0681d4147ff192c98108c035d6d0f96cce)) + +# [14.10.2](https://github.com/discordjs/discord.js/compare/14.10.1...14.10.2) - (2023-05-01) + +## Bug Fixes + +- Correct `isJSONEncodable()` import (#9495) ([201b002](https://github.com/discordjs/discord.js/commit/201b002ad405b845ace5f708077c1f157bb4126d)) +- **Client:** `generateInvite()` scope validation (#9492) ([b327f49](https://github.com/discordjs/discord.js/commit/b327f4925ff557e0aa8273d7f017aa616226ca06)) + +# [14.10.1](https://github.com/discordjs/discord.js/compare/14.10.0...14.10.1) - (2023-05-01) + +## Bug Fixes + +- **Client:** Spelling of InvalidScopesWithPermissions ([ac9bf3a](https://github.com/discordjs/discord.js/commit/ac9bf3ac06ec78dbaca2ce4a82cceb0d82484211)) + +## Refactor + +- **ShardClientUtil:** Logic de-duplication (#9491) ([a9f2bff](https://github.com/discordjs/discord.js/commit/a9f2bff82a18c6a3afdee99e5830e1d7b4da65dc)) + +# [14.10.0](https://github.com/discordjs/discord.js/compare/14.9.0...14.10.0) - (2023-05-01) + +## Bug Fixes + +- **ShardClientUtil:** Fix client event names (#9474) ([ad217cc](https://github.com/discordjs/discord.js/commit/ad217cc7604dda6a33df73db82799fd5bb4e85a9)) +- **BaseClient:** Prevent user agent mutation (#9425) ([217e5d8](https://github.com/discordjs/discord.js/commit/217e5d81005a2506c96335f7fb96fa21d7dbb04c)) +- **BitField:** Use only enum names in iterating (#9357) ([40d07fb](https://github.com/discordjs/discord.js/commit/40d07fbbbd51d62793d9ea541f41f157b5dad224)) +- Use new permission name (#9274) ([d2d27ce](https://github.com/discordjs/discord.js/commit/d2d27ce7346bc37b34938c84bd3b106a4fa51f53)) +- **Message#editable:** Fix permissions check in locked threads (#9319) ([d4c1fec](https://github.com/discordjs/discord.js/commit/d4c1fecbe264bc52a70aaf0ec303d35e2f15bbcd)) +- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2)) + +## Documentation + +- **AutoModerationRule:** Update docs (#9464) ([1b15d31](https://github.com/discordjs/discord.js/commit/1b15d31b5ae1b1739716fab00b18083c1d7d389a)) +- **APITypes:** Document role & user select menu components (#9435) ([c6ca5a8](https://github.com/discordjs/discord.js/commit/c6ca5a83e7b72613f95c2145606a1330f64ae894)) +- **BaseMessageOptions:** Fix embeds and components (#9437) ([5c52bb9](https://github.com/discordjs/discord.js/commit/5c52bb95906250518a8813820d543f43dd7abdf9)) +- **InteractionResponses:** ShowModal docs change (#9434) ([7d34100](https://github.com/discordjs/discord.js/commit/7d341000d44b762a2fe0434a6b518f7d63539d34)) +- Use ESM code in examples (#9427) ([ce287f2](https://github.com/discordjs/discord.js/commit/ce287f21d1540da7f17cac8a57dc33a67f391ef3)) +- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9)) +- **Options:** Fix links and invalid syntax (#9322) ([86e5f5a](https://github.com/discordjs/discord.js/commit/86e5f5a119c6d2588b988a33236d358ded357847)) +- Cleanup MessageCreateOptions and MessageReplyOptions (#9283) ([300059c](https://github.com/discordjs/discord.js/commit/300059cb266e6cca42c30ee7f997c48ab2cc565e)) +- **Events:** Document auto moderation events (#9342) ([79bcdfa](https://github.com/discordjs/discord.js/commit/79bcdfa767e7e842164e1174b6f4834ed731d329)) +- Add `SnowflakeUtil` (#9371) ([8ffcf77](https://github.com/discordjs/discord.js/commit/8ffcf77840b62590fcb4731380d28b22d0b98741)) +- Use stable tag (#9343) ([c0f2dd7](https://github.com/discordjs/discord.js/commit/c0f2dd713151a29c98e1eebad66721a208be1fc0)) +- Remove `JSONEncondable` (#9344) ([b2eec5f](https://github.com/discordjs/discord.js/commit/b2eec5f9fcf37ebb3b7f87a67a6ee3160c182183)) + +## Features + +- **Attachment:** Voice messages (#9392) ([3e01f91](https://github.com/discordjs/discord.js/commit/3e01f91bbba2cbacacc6c921ed664752f679960b)) +- **BaseInteraction:** Support new channel payload (#9337) ([29389e3](https://github.com/discordjs/discord.js/commit/29389e39f479b832e54c7cb3ddd363aebe99674f)) +- **RoleTagData:** Add guildConnections (#9366) ([2dddbe1](https://github.com/discordjs/discord.js/commit/2dddbe1f321f2e2722dba4a28f7d18384cf50353)) + +## Performance + +- **RoleManager:** Dont call Role#position getter twice per role (#9352) ([bfee6c8](https://github.com/discordjs/discord.js/commit/bfee6c8d889502ea39ad919dd9b1e6253a2af571)) + +## Refactor + +- **WebSocketManager:** Use /ws package internally (#9099) ([a9e0de4](https://github.com/discordjs/discord.js/commit/a9e0de4288ea39a6a089b8379dcd44ac0053dac7)) +- Remove `fromInteraction` in internal channel creation (#9335) ([794abe8](https://github.com/discordjs/discord.js/commit/794abe8450bae000cd0544922cdf53e7b3e4c59c)) + +## Typings + +- **AutoModerationActionMetadataOptions:** Make channel property optional (#9460) ([d26df5f](https://github.com/discordjs/discord.js/commit/d26df5fabaf227fb9d10ba5cc1ab326de55aadbc)) +- **CategoryChannel:** Ensure `parent` and `parentId` are `null` (#9327) ([8218ffc](https://github.com/discordjs/discord.js/commit/8218ffc78d23234b32c05a97fde2f4bea64d7aa6)) +- **GuildTextBasedChannel:** Remove unnecessary exclusion of forum channels (#9326) ([7ff3d52](https://github.com/discordjs/discord.js/commit/7ff3d528d942a0daa990194915ff8328dec99149)) + +# [14.9.0](https://github.com/discordjs/discord.js/compare/14.8.0...14.9.0) - (2023-04-01) + +## Bug Fixes + +- Add support for new guild feature `GUILD_WEB_PAGE_VANITY_URL` (#9219) ([de1aac6](https://github.com/discordjs/discord.js/commit/de1aac674acb3830124646fcd52cdd98cdb71ba5)) +- Resolving string bitfield (#9262) ([7987565](https://github.com/discordjs/discord.js/commit/79875658cf4a8daa25210c2c620c73a710ca22de)) +- **AutocompleteInteraction:** Send `name_localizations` correctly (#9238) ([1864d37](https://github.com/discordjs/discord.js/commit/1864d37d36e53d127e74b6969a5f542193bfc3c7)) +- Keep symbols in actions manager (#9293) ([984bd55](https://github.com/discordjs/discord.js/commit/984bd55b437507e7ebfdf09ac944c8eba0340d27)) +- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b)) +- **ClientUser:** No mutation on edit (#9259) ([abd6ae9](https://github.com/discordjs/discord.js/commit/abd6ae9fc8ea03722e8b36e29c3fdc1c2cfc93e8)) +- **Message#editable:** Update editable check in threads locked (#9216) ([22e880a](https://github.com/discordjs/discord.js/commit/22e880aaa0d8c644fc8d16a524d17f4f53a056f6)) +- **ThreadManager:** Add `members` and conditionally include `hasMore` (#9164) ([e9a8eb3](https://github.com/discordjs/discord.js/commit/e9a8eb323f3a554dc8f9dab361cd1bac7b88e1cc)) +- **ThreadManager:** Respect `cache` and `force` in fetching (#9239) ([cc57563](https://github.com/discordjs/discord.js/commit/cc57563e73d78a0d71d1444d1ee8215a26a81fa8)) +- **TextBasedChannelTypes:** Add `GuildStageVoice` (#9232) ([51edba7](https://github.com/discordjs/discord.js/commit/51edba78bc4d4cb44b4dd2b79e4bbc515dc46f5b)) + +## Documentation + +- Describe private properties (#8879) ([2792e48](https://github.com/discordjs/discord.js/commit/2792e48119f1cf5fa7d5e6b63369457b0719d4e4)) +- Differ `User#send` (#9251) ([384b4d1](https://github.com/discordjs/discord.js/commit/384b4d10e8642f0f280ea1651f33cd378c341333)) +- Fix compare position example (#9272) ([d16114c](https://github.com/discordjs/discord.js/commit/d16114c52646ca92c53f9b44a0dd10af98dbddcd)) +- **Role:** Fix example for `comparePositionTo()` (#9270) ([bc641fa](https://github.com/discordjs/discord.js/commit/bc641fa9360b851642bc51839cef6bd5600d71f7)) +- Add more examples (#9252) ([bf507ab](https://github.com/discordjs/discord.js/commit/bf507ab2659d95e2991e83293b3834f21283ff33)) +- **FetchArchivedThreadOptions:** `before` respects `archive_timestamp`, not creation timestamp (#9240) ([178c8dc](https://github.com/discordjs/discord.js/commit/178c8dcfeea1c4a6a32835baea389f25feefbac7)) +- Update `APISelectMenuComponent` (#9235) ([56cf138](https://github.com/discordjs/discord.js/commit/56cf138e029e7884a4e7efb606055687ca67b4ac)) + +## Features + +- **Guild:** Add `max_stage_video_channel_users` (#8422) ([34bc36a](https://github.com/discordjs/discord.js/commit/34bc36ac4b04ad033d0dcc3d2701fcf2e682743c)) +- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b)) +- Add GuildBasedTextChannelTypes (#9234) ([5f93dcc](https://github.com/discordjs/discord.js/commit/5f93dcce466286f0fdead8faf4131e98d1c9db55)) + +## Refactor + +- Call `GuildBanManager#create()` directly (#9263) ([f340f3b](https://github.com/discordjs/discord.js/commit/f340f3b1fd719e8f7cf6fa28a41835bc16039fc7)) +- **FetchThreadsOptions:** Remove `active` (#9241) ([519e163](https://github.com/discordjs/discord.js/commit/519e163f8aa3b55420f86d2d60c2584b3a2eb327)) + +# [14.8.0](https://github.com/discordjs/discord.js/compare/14.7.1...14.8.0) - (2023-03-12) + +## Bug Fixes + +- **snowflake:** Snowflakes length (#9144) ([955e8fe](https://github.com/discordjs/discord.js/commit/955e8fe312c42ad4937cc1994d1d81e517c413c8)) +- **Actions:** Inject built data by using a symbol (#9203) ([a63ac88](https://github.com/discordjs/discord.js/commit/a63ac88fcca5b61209892a6e560e35d58f5adc3b)) +- **Message#deletable:** Add check for deletable message types (#9168) ([e78b8ad](https://github.com/discordjs/discord.js/commit/e78b8ad3fb6692cba2c565b508254c723f185f0c)) +- **Message:** `bulkDeletable` permissions should be retrieved later for DMs (#9146) ([a9495bd](https://github.com/discordjs/discord.js/commit/a9495bd8f014c8021a214b83ffc531a2af5defef)) +- **AutoModerationActionExecution:** Transform `action` (#9111) ([9156a28](https://github.com/discordjs/discord.js/commit/9156a2889cd0946dfd0b30a5f8365abfbc377b3d)) +- **MessageReaction:** `toJSON()` infinite recursion (#9070) ([f268e1d](https://github.com/discordjs/discord.js/commit/f268e1d9798744e169ae87089ea2e1f214364d95)) +- **ThreadChannel:** Insert starter message from threads created in forum channels (#9100) ([0b76ab4](https://github.com/discordjs/discord.js/commit/0b76ab4c403dd646c71482856ab993b263b7c474)) +- **ApplicationRoleConnectionMetadata:** Export the class correctly (#9076) ([071516c](https://github.com/discordjs/discord.js/commit/071516c35239bd4e1cae572c855d86b335c8536d)) +- Don't auth for interaction `showModal()` (#9046) ([b803a9a](https://github.com/discordjs/discord.js/commit/b803a9a899aaa75a3ea2bc6623c6afb28f495e8c)) +- **WebSocketShard:** Zombie connection fix (#8989) ([876b181](https://github.com/discordjs/discord.js/commit/876b1813128ec702d3ef1e7b0074a4613e88c332)) +- Keep other properties in triggerMetadata (#8977) ([d8dd197](https://github.com/discordjs/discord.js/commit/d8dd197a936dfffc05f9e5bc3184ec9022c56b51)) +- **escapeX:** Emojis with underlines (#8945) ([07b597d](https://github.com/discordjs/discord.js/commit/07b597df16b9412c23ec2387d54564e4d1bcf7ed)) +- **WebSocketShard:** Either start close timeout or emit destroyed but never both (#8956) ([43ce2a5](https://github.com/discordjs/discord.js/commit/43ce2a572eb8977b6994680171ac0c5f9bda1703)) +- **DMChannel:** `recipientId` edge case (#8950) ([7ce9909](https://github.com/discordjs/discord.js/commit/7ce990954e2f73d7a996df0afa42ab287cb12514)) +- Return only boolean for `disabled` (#8965) ([6614603](https://github.com/discordjs/discord.js/commit/66146033268a4db1279b2eaee4bd418f326c0d4b)) +- Export missing `escapeX()` functions (#8944) ([25c27ea](https://github.com/discordjs/discord.js/commit/25c27eac1417e75c9b601b17cf177b1f47b699a9)) +- **WebSocketShard:** Only cleanup the connection if a connection still exists (#8946) ([5eab5fc](https://github.com/discordjs/discord.js/commit/5eab5fc06ca6be36ecf1557f2ad29a670d4d5ae7)) +- Add `@discordjs/formatters` to dependency list (#8939) ([18b3a19](https://github.com/discordjs/discord.js/commit/18b3a19810a6436fa8bb4b490ec5137eaecbd465)) +- **resolveColor:** Invalid colors (#8933) ([c76e170](https://github.com/discordjs/discord.js/commit/c76e17078602914c3e1d227a3acc98eaa99c18d4)) +- **WebSocketShard:** Clear listeners on reconnect (#8927) ([aa8c57d](https://github.com/discordjs/discord.js/commit/aa8c57dab60104549e28451abf35c0387595d67e)) +- Re-export formatters (#8909) ([b14604a](https://github.com/discordjs/discord.js/commit/b14604abdecca575b1fca693c1593e3585bcca8c)) + +## Documentation + +- **MessageManager:** Add clarification to fetch messages (#9222) ([f5ec1ca](https://github.com/discordjs/discord.js/commit/f5ec1cada5ebf0ca4093bdfc81aaf56900c794ef)) +- Make interactionResponse as optional (#9179) ([664cccb](https://github.com/discordjs/discord.js/commit/664cccb2706db33635aa2556954de57f93b3d3db)) +- Fix typos (#9127) ([1ba1f23](https://github.com/discordjs/discord.js/commit/1ba1f238f04221ec890fc921678909b5b7d92c26)) +- **chatInputApplicationCommandMention:** Parameters are not nullable (#9091) ([6f78e82](https://github.com/discordjs/discord.js/commit/6f78e8285b3ce762de010e68d49b377a47dc5a63)) +- No `@type` description and reveal info block (#9097) ([405f940](https://github.com/discordjs/discord.js/commit/405f9400e8e3ffea9f3847ab5abb431a34538a96)) +- **ThreadEditOptions:** Move info tag back to `invitable` (#9020) ([f3fe3ce](https://github.com/discordjs/discord.js/commit/f3fe3ced622676b406a62b43f085aedde7a621aa)) +- Fix a typo in the MentionableSelectMenuInteraction link (#9000) ([6d7a143](https://github.com/discordjs/discord.js/commit/6d7a143667f33ef2ea45d8016ac4738237707881)) +- **ApplicationRoleConnectionMetadata:** Add documentation (#8976) ([2e22b31](https://github.com/discordjs/discord.js/commit/2e22b31892d9b858fcb24fa580b486b4154e823f)) +- Fix malformed overridden documentation (#8954) ([0b8b114](https://github.com/discordjs/discord.js/commit/0b8b114761f961a2bf8e5aae342ed711b154a89e)) +- **GuildForumThreadManager:** Fix `sticker` type (#8940) ([dd62be0](https://github.com/discordjs/discord.js/commit/dd62be077d3e4fbd73a0c10ca344d93d3d19fa38)) +- Fix deprecated links (#8907) ([976b234](https://github.com/discordjs/discord.js/commit/976b234e9dc9999e5dee47b58c85afbc1cd494c2)) +- **UserFlagsBitField:** Make `.Flags` static (#8902) ([c48ff5e](https://github.com/discordjs/discord.js/commit/c48ff5e4205899e3b6cd35812ca857236bef6864)) + +## Features + +- **Collector:** Add lastCollectedTimestamp (#9044) ([4458a13](https://github.com/discordjs/discord.js/commit/4458a13925164762b519ded1037ae8775d879f71)) +- **StageChannel:** Add messages (#9134) ([ffdb197](https://github.com/discordjs/discord.js/commit/ffdb197f988657100e2a9ff0ca17b759339a1dda)) +- **AutoModerationActionExecution:** Add `channel`, `user` and `member` getters (#9142) ([095bd77](https://github.com/discordjs/discord.js/commit/095bd77515aa31bb0e95a350b4355980fea9268d)) +- **AutoModeration:** Support `custom_message` (#9171) ([c1000b8](https://github.com/discordjs/discord.js/commit/c1000b86ed6d5413afcd6ee7e80505e5a845430b)) +- **ThreadMemberManager:** Support pagination fetching (#9035) ([765d5a3](https://github.com/discordjs/discord.js/commit/765d5a3b2d5529c3a2a4b29512f6932264443ed1)) +- **InteractionResponse:** Add new methods (#9132) ([dc9924f](https://github.com/discordjs/discord.js/commit/dc9924fb5f24c8dac963d6b86ba279a89545e73b)) +- **GuildMember:** Add `flags` (#9087) ([76b2116](https://github.com/discordjs/discord.js/commit/76b21162aca7cd4897826437da3063524e1e7553)) +- **Client:** `guildAuditLogEntryCreate` event (#9058) ([9439107](https://github.com/discordjs/discord.js/commit/9439107a1d6a9b77b5f991973d96bc6100da4753)) +- Add role subscription data (#9025) ([1ba22f4](https://github.com/discordjs/discord.js/commit/1ba22f4c9e4173f8866339d3eadb2939d4b32034)) +- **Sticker:** Add support for gif stickers (#9038) ([6a9875d](https://github.com/discordjs/discord.js/commit/6a9875da054a875a4711394547d47439bbe66fb6)) +- **GuildAuditLogs:** Support `after` (#9011) ([0076589](https://github.com/discordjs/discord.js/commit/0076589ccc93e09d77a448874d1ceff5d0e91aa2)) +- Add role subscriptions (#8915) ([3407e1e](https://github.com/discordjs/discord.js/commit/3407e1eea3c8d5629465553f342ac30ceae27a47)) +- Add `not_found` to guild member chunk data (#8975) ([be294ea](https://github.com/discordjs/discord.js/commit/be294eaf9901ea139ce485deeec9178959ffa91f)) +- **ClientApplication:** Add role connections (#8855) ([22e2bbb](https://github.com/discordjs/discord.js/commit/22e2bbb0d24e3f30516f262308d5786f2f666713)) +- **CommandInteractionOptionResolver:** Add `channelTypes` option to `getChannel` (#8934) ([429dbcc](https://github.com/discordjs/discord.js/commit/429dbccc85cabd9986b2e8bf443bf384e4ddc61a)) +- **ForumChannel:** Add `defaultForumLayout` (#8895) ([cbafd47](https://github.com/discordjs/discord.js/commit/cbafd479b331633ed97f7b1a22ef03c6a2f4cf31)) +- Add support for nsfw commands (#7976) ([7a51344](https://github.com/discordjs/discord.js/commit/7a5134459c5f06864bf74631d83b96d9c21b72d8)) +- **InteractionResponse:** CreatedTimestamp (#8917) ([627511d](https://github.com/discordjs/discord.js/commit/627511d6522f772b84c25e6a3f6da06b06bb912e)) +- **Guild:** Add disableInvites method (#8801) ([45faa19](https://github.com/discordjs/discord.js/commit/45faa199820e7c4ccdb2997c7e3b353f566d2312)) + +## Refactor + +- Compare with `undefined` directly (#9191) ([869153c](https://github.com/discordjs/discord.js/commit/869153c3fdf155783e7c0ecebd3627b087c3a026)) +- **GuildMemberManager:** Tidy up fetching guild members (#8972) ([4e0e125](https://github.com/discordjs/discord.js/commit/4e0e1250399aa12c340ac92a86ec2c05704fe2bb)) +- **BitField:** Reverse iterator/toArray responsibilities (#9118) ([f70df91](https://github.com/discordjs/discord.js/commit/f70df910ed12e397066d0bdb27343af21ead4d92)) +- Moved the escapeX functions from discord.js to @discord.js/formatters (#8957) ([13ce78a](https://github.com/discordjs/discord.js/commit/13ce78af6e3aedc793f53a099a6a615df44311f7)) +- Use `deprecate()` directly (#9026) ([1c871b5](https://github.com/discordjs/discord.js/commit/1c871b5b576dddef12c5afacecf416dbd6243dea)) +- **Guild:** Destructure object in guild editing (#8971) ([d3e9f2a](https://github.com/discordjs/discord.js/commit/d3e9f2a355a1f5272d62a507eb6ecd8808904fff)) +- **GuildManager:** Better handling of creation code (#8974) ([d7a09f6](https://github.com/discordjs/discord.js/commit/d7a09f6fcee30c31b4418166bf7bf9e894841f87)) +- **sharding:** Use switch statement (#8928) ([6540914](https://github.com/discordjs/discord.js/commit/6540914b4a7f244f5e40fe2a3b7e73986763d81b)) +- Use consistent naming for options (#8901) ([a7b55c1](https://github.com/discordjs/discord.js/commit/a7b55c1460cf63fb482f7d05657120eec96bee82)) +- **CommandInteractionOptionResolver:** Loosen mentionable checks (#8910) ([1b151db](https://github.com/discordjs/discord.js/commit/1b151db59c4340417f8a28a88064f45336ac8c78)) + +## Styling + +- Run prettier (#9041) ([2798ba1](https://github.com/discordjs/discord.js/commit/2798ba1eb3d734f0cf2eeccd2e16cfba6804873b)) + +## Typings + +- Allow sending messages with `SuppressNotifications` flag (#9177) ([71a427f](https://github.com/discordjs/discord.js/commit/71a427f6322be76fe2d1cb265de09f171b1b354a)) +- Remove `EscapeMarkdownOptions` (#9153) ([fd0246c](https://github.com/discordjs/discord.js/commit/fd0246ca4c75e60d8e117d9ac5af7067c7a63277)) +- **Attachment:** Make `attachment` private (#8982) ([da23cd5](https://github.com/discordjs/discord.js/commit/da23cd5d69de4856d075f00738f75c68c555ae5b)) +- Fix type of Attachment#name (#9101) ([4e0a89f](https://github.com/discordjs/discord.js/commit/4e0a89f58f43f362bfde80d8319dce767c62850f)) +- Allow builders to set channel types in discord.js (#8990) ([7dec892](https://github.com/discordjs/discord.js/commit/7dec892218f7b470a5f8e78732a524a53da24d26)) +- Swap message reaction and emoji identifier types (#8969) ([ad49845](https://github.com/discordjs/discord.js/commit/ad4984526020f2baeefaeeebbded66c6848c4b85)) +- **widget:** Add missing `name` (#8978) ([898b5ac](https://github.com/discordjs/discord.js/commit/898b5ac416cbbb415b125bb27221d0901fdd180e)) +- Use StringSelectMenuOptionBuilder (#8949) ([bec51de](https://github.com/discordjs/discord.js/commit/bec51de1038c35c6edaaa13934781758fe1951de)) +- Fix actions type in automod (#8962) ([5915f39](https://github.com/discordjs/discord.js/commit/5915f39810b712c05a46fa21ab4e12b4cfa3c25a)) +- Subcommand group `options` is required (#8966) ([5dc5e90](https://github.com/discordjs/discord.js/commit/5dc5e902688fc563087cd5061dcb59dd68fd4eda)) +- Add generic to `ActionRowBuilder.from()` (#8414) ([153352a](https://github.com/discordjs/discord.js/commit/153352ad7a1ccb4a9461523cf2597d81df93b69c)) + +# [14.7.1](https://github.com/discordjs/discord.js/compare/14.7.0...14.7.1) - (2022-12-01) + +## Bug Fixes + +- Prevent crash on no select menu option (#8881) ([11d195d](https://github.com/discordjs/discord.js/commit/11d195d04ff57d51adb0f0d3a0a7342f9e34aba0)) + +# [14.7.0](https://github.com/discordjs/discord.js/compare/14.6.0...14.7.0) - (2022-11-28) + +## Bug Fixes + +- **MessageMentions:** Add `InGuild` generic (#8828) ([f982803](https://github.com/discordjs/discord.js/commit/f9828034cd21e6f702762a46923e0f42115596f6)) +- **Activity:** Fix equals() not checking for differing emoji (#8841) ([7e06f68](https://github.com/discordjs/discord.js/commit/7e06f68185423ba7cb310220b213f445b6571e29)) +- Fixed react/astro/guide/discord.js build, updated dependencies, fix crawlvatar (#8861) ([d0c8256](https://github.com/discordjs/discord.js/commit/d0c82561b8a1765a1daa362ca903f3ffb3fa33ee)) +- **escapeMarkdown:** Fix double escaping (#8798) ([d6873b7](https://github.com/discordjs/discord.js/commit/d6873b7159352479475b3a0daa215bddbdd3a79b)) +- **Transfomers:** Call `.toJSON` in `toSnakeCase` (#8790) ([017f9b1](https://github.com/discordjs/discord.js/commit/017f9b1ed4014dc1db0b78c1a77e463b4403de5d)) +- Censor token in debug output (#8764) ([53d8e87](https://github.com/discordjs/discord.js/commit/53d8e87d7f3a329608250656950bd0a200adb1c7)) +- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4)) + +## Documentation + +- Describe InteractionEditReplyOptions (#8840) ([cb77fd0](https://github.com/discordjs/discord.js/commit/cb77fd02d083438de2aff6f0769baf7d1797bc65)) +- **AutoModerationRuleManager:** Describe cache (#8848) ([d275480](https://github.com/discordjs/discord.js/commit/d2754802cc3479e6288cdbfcd48c76bf57e09a07)) +- Fix message action row components (#8819) ([65bc0ad](https://github.com/discordjs/discord.js/commit/65bc0adbf4d7870d33b92585ca18f964f24bc84e)) +- Specify `ActionRowBuilder` for `components` (#8834) ([8ed5c1b](https://github.com/discordjs/discord.js/commit/8ed5c1beb622f71ce0bd89e4cbeff50e464da8fe)) +- Add `@extends` for select menu classes (#8824) ([09f65b7](https://github.com/discordjs/discord.js/commit/09f65b724b0d2f36bbe89b83570c0d18093b5126)) +- Make WebSocketShard.lastPingTimestamp public (#8768) ([68c9cb3](https://github.com/discordjs/discord.js/commit/68c9cb37bc3df6326b720291827ea477e421faf2)) +- **MessageReplyOptions:** Remove duplicate stickers field (#8766) ([6e348ff](https://github.com/discordjs/discord.js/commit/6e348ffd1d8db8d8ad2da7823460814695e01a43)) + +## Features + +- **Webhook:** Add `channel` property (#8812) ([decbce4](https://github.com/discordjs/discord.js/commit/decbce401062af75f633e6acacc88207b115a719)) +- Auto Moderation (#7938) ([fd4ba5e](https://github.com/discordjs/discord.js/commit/fd4ba5eaba66898699127fc0d5f0ab52c18e3db0)) +- **SelectMenuInteractions:** Add `values` property (#8805) ([b2fabd1](https://github.com/discordjs/discord.js/commit/b2fabd130a76ea54cfbfa1b871ef8659513c2c7a)) +- **ThreadChannel:** Add a helper for pin and unpin (#8786) ([e74aa7f](https://github.com/discordjs/discord.js/commit/e74aa7f6b0fe04e3473fc4a62a73a7db87307685)) +- Add `Message#bulkDeletable` (#8760) ([ff85481](https://github.com/discordjs/discord.js/commit/ff85481d3e7cd6f7c5e38edbe43b27b104e82fba)) +- New select menus (#8793) ([5152abf](https://github.com/discordjs/discord.js/commit/5152abf7285581abf7689e9050fdc56c4abb1e2b)) +- **InteractionResponses:** Add message parameter (#8773) ([8b400ca](https://github.com/discordjs/discord.js/commit/8b400ca975c6bad00060b9c67068f42bd53524ba)) +- Support resume urls (#8784) ([88cd9d9](https://github.com/discordjs/discord.js/commit/88cd9d906074eb79e85df0ef49287f11133d2e0d)) +- Allow deletion of ephemeral messages (#8774) ([fc10774](https://github.com/discordjs/discord.js/commit/fc107744618857bf28c2167f204253baf690ede8)) +- **GuildChannelManager:** Add `.addFollower()` method (#8567) ([caeb1cb](https://github.com/discordjs/discord.js/commit/caeb1cbfdb2f2f007252c4d7e9f47a575c24bcb5)) + +## Refactor + +- **Embed:** Use `embedLength` function from builders (#8735) ([cb3826c](https://github.com/discordjs/discord.js/commit/cb3826ce6dbcd3cf7ab639af6cdfcea80336aa1d)) + +# [14.6.0](https://github.com/discordjs/discord.js/compare/14.5.0...14.6.0) - (2022-10-10) + +## Bug Fixes + +- **ClientOptions:** Make `ClientOptions#intents` returns an IntentsBitField (#8617) ([4c2955a](https://github.com/discordjs/discord.js/commit/4c2955a5de6779c29c09e63ba9ad2b235904f842)) +- Correctly construct a builder (#8727) ([e548e6a](https://github.com/discordjs/discord.js/commit/e548e6a10b7e1720f5e8f3c859b0b64d5134a012)) +- **Components:** Error with unknown components (#8724) ([6fd331d](https://github.com/discordjs/discord.js/commit/6fd331dd528e78fd023c908bd58af3faa9ed6c65)) +- **Client:** Don't auth for webhook fetches with token (#8709) ([01d75c8](https://github.com/discordjs/discord.js/commit/01d75c8b8b14f33c95a4da83a8494db848beeb8c)) +- Re-export util (#8699) ([a306219](https://github.com/discordjs/discord.js/commit/a306219673335584accd2ff77ab34d2812ef6c5d)) +- Throw discord.js errors correctly (#8697) ([ace974f](https://github.com/discordjs/discord.js/commit/ace974fc1fdbc5bcaa0d7f6f6d17de185c9f9cbf)) + +## Documentation + +- **Utils:** Remove `private` from `parseEmoji` (#8718) ([a31e605](https://github.com/discordjs/discord.js/commit/a31e605e09064a300e31a3c91466b613654ba98e)) +- Update UserContextMenuCommandInteraction documentation (#8717) ([7556db2](https://github.com/discordjs/discord.js/commit/7556db243d9480949835668fcb5724fdd5d70e08)) +- Fix `AwaitMessageComponentOptions` typedef (#8696) ([9effd82](https://github.com/discordjs/discord.js/commit/9effd82abe82ba71ae627673da21ba07e1ede23e)) + +## Features + +- **Util:** Escape more markdown characters (#8701) ([7b8966b](https://github.com/discordjs/discord.js/commit/7b8966bca156db79933403289741893a6e10ccd5)) +- **GuildChannelManager:** Allow creating channels with a default auto archive duration (#8693) ([628759b](https://github.com/discordjs/discord.js/commit/628759bcff8b0d4c77926cee2b8c18d8fdb4c260)) +- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3)) +- **ForumChannel:** Add `defaultSortOrder` (#8633) ([883f6e9](https://github.com/discordjs/discord.js/commit/883f6e9202a559c986f4b15fccb422b5aea7bea8)) + +## Refactor + +- Rename Error to DiscordjsError internally (#8706) ([aec44a0](https://github.com/discordjs/discord.js/commit/aec44a0c93f620b22242f35e626d817e831fc8cb)) + +## Typings + +- Fix events augmentation (#8681) ([ac83ada](https://github.com/discordjs/discord.js/commit/ac83ada306ec153c13260d2bd53e4d704884b68a)) +- **Message:** Remove `& this` from `#inGuild` typeguard (#8704) ([c0f7a1a](https://github.com/discordjs/discord.js/commit/c0f7a1a89a4cf62edc7065bd200b2ce4018e0a27)) +- **ModalBuilder:** Fix constructor typings (#8690) ([2ea2a85](https://github.com/discordjs/discord.js/commit/2ea2a85e6335d57f44689f9b6e284129104de8fc)) + +# [14.5.0](https://github.com/discordjs/discord.js/compare/14.4.0...14.5.0) - (2022-09-25) + +## Bug Fixes + +- **ThreadChannel:** Add forum channel to parent (#8664) ([0126d9b](https://github.com/discordjs/discord.js/commit/0126d9b810a156c4bf1b8b93f2121f3319855bac)) +- **GuildChannelManager:** Allow creating webhooks on forums (#8661) ([16fcdc3](https://github.com/discordjs/discord.js/commit/16fcdc36877d1a65ce9995c9fe3502aa268c9388)) +- **ForumChannel:** Implement missing properties and methods (#8662) ([8622939](https://github.com/discordjs/discord.js/commit/862293922924f453f69b0b0f8efe87ddebbd387d)) +- RepliableInteraction respect cached generic (#8667) ([578bc95](https://github.com/discordjs/discord.js/commit/578bc951bdcdc21ec5aee86e7a47a17e8c867dfc)) +- **ThreadChannel:** Allow editing flags (#8671) ([1244854](https://github.com/discordjs/discord.js/commit/1244854e1365d7e4a8d01703a7ec13610ed100c7)) +- **GuildChannelManager:** Typo in `flags` property name when editing (#8669) ([fc8ed81](https://github.com/discordjs/discord.js/commit/fc8ed816e643754a938211a17b41a2cec95df265)) + +## Documentation + +- Fix duplicate typedefs (#8677) ([d79aa2d](https://github.com/discordjs/discord.js/commit/d79aa2d0d0b186bd28cbfc82f3d6ecf3deb41c50)) +- **ForumChannel:** Add `@implements` (#8678) ([8ca407e](https://github.com/discordjs/discord.js/commit/8ca407e089c3050b61a51a52b9100e4613ad1666)) + +## Features + +- **GuildChannelManager:** Allow editing `flags` (#8637) ([abb7226](https://github.com/discordjs/discord.js/commit/abb7226af3445f5b724815bb2f7a121a52a563b5)) + +## Refactor + +- **GuildBanManager:** Add deprecation warning for `deleteMessageDays` (#8659) ([e993122](https://github.com/discordjs/discord.js/commit/e9931229ae62a120ae0761ee2a2c10ea0cb1a6fb)) + +## Typings + +- **GuildChannelManager:** Handle forum channel overload (#8660) ([1486bc9](https://github.com/discordjs/discord.js/commit/1486bc9336369d229972df5e28b9428365b92bff)) +- **Caches:** Allow `GuildForumThreadManager` and `GuildTextThreadManager` (#8665) ([2487e3b](https://github.com/discordjs/discord.js/commit/2487e3bf76260a4a2fbf375e0b01a43f347922a3)) + +# [14.4.0](https://github.com/discordjs/discord.js/compare/14.3.0...14.4.0) - (2022-09-21) + +## Bug Fixes + +- Correct applied tags type (#8641) ([f6f15d8](https://github.com/discordjs/discord.js/commit/f6f15d8e877d4ffbe908a093e64809ef9015e0ff)) +- **ThreadChannel:** Make `fetchStarterMessage()` work in forum posts (#8638) ([a7f816e](https://github.com/discordjs/discord.js/commit/a7f816eeb7fa1e193cf0901efbdcaf629f72465f)) +- Update `messageCount`/`totalMessageSent` on message events (#8635) ([145eb2f](https://github.com/discordjs/discord.js/commit/145eb2fc5db5ca739aa9782d5ec5210f81a6aeeb)) +- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9)) + +## Documentation + +- Correctly overwrite `setRTCRegion` method (#8642) ([f049734](https://github.com/discordjs/discord.js/commit/f0497343f1193635b260b9e2085cac7b43991f74)) +- **GuildTextThreadManager:** Document correct `@extend` (#8639) ([802b239](https://github.com/discordjs/discord.js/commit/802b2394b08151faab6810695fd5c8f27ce84d58)) +- Fix regexps incorrectly being called global (#8624) ([fc9653f](https://github.com/discordjs/discord.js/commit/fc9653f5aea4013da15fb8de0a4452400eaa7739)) +- Update misleading `Client#guildMemberAvailable` event description (#8626) ([22ac6b4](https://github.com/discordjs/discord.js/commit/22ac6b4660db6b02f62b9851e9e3bcfe5fb506b5)) +- **Options:** Update DefaultMakeCacheSettings (#8585) ([3252332](https://github.com/discordjs/discord.js/commit/32523325c6610e95fe3ffcc31d005b3418c6bc68)) +- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0)) + +## Features + +- **Widget:** Allow forum channels (#8645) ([b106956](https://github.com/discordjs/discord.js/commit/b1069563086fc616fe21abb789f28f69e57c8851)) +- **WelcomeChannel:** Add forum channel as a type (#8643) ([6f1f465](https://github.com/discordjs/discord.js/commit/6f1f465a77e362e20ec50067be0e634d35946ba5)) +- Allow forum channels in webhook update event (#8646) ([5048a3d](https://github.com/discordjs/discord.js/commit/5048a3d17ace22336e74451d30b513b3db42a26f)) +- Add support for guild forums (#7791) ([8a8d519](https://github.com/discordjs/discord.js/commit/8a8d519c9c4c082370fc6935b56dafb525b873df)) +- **GuildBanManager#create:** Add `deleteMessageSeconds` (#8326) ([03fb5b0](https://github.com/discordjs/discord.js/commit/03fb5b0a2f45275dec7885175ad691a1d9c449c4)) +- Add typeguard to BaseInteraction#isRepliable (#8565) ([55c3ee2](https://github.com/discordjs/discord.js/commit/55c3ee20ae700e78d18a3c4c04b6a7426cffc060)) +- **Integration:** Add `scopes` (#8483) ([8b3d006](https://github.com/discordjs/discord.js/commit/8b3d0061180cfd5d9ba8beae3e8d623b5ce43ea4)) +- Add `chatInputApplicationCommandMention` formatter (#8546) ([d08a57c](https://github.com/discordjs/discord.js/commit/d08a57cadd9d69a734077cc1902d931ab10336db)) + +## Refactor + +- Replace usage of deprecated `ChannelType`s (#8625) ([669c3cd](https://github.com/discordjs/discord.js/commit/669c3cd2566eac68ef38ab522dd6378ba761e8b3)) +- Split message send/edit types/documentation (#8590) ([8e1afae](https://github.com/discordjs/discord.js/commit/8e1afaebdb686033555ca58e53f34bb97f7369c8)) +- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67)) + +## Typings + +- Narrow channel type in thread managers (#8640) ([14bbc91](https://github.com/discordjs/discord.js/commit/14bbc9150a748e7ac1660c2375c7f065fcc55a6c)) +- **interactions:** Pass `Cached` type to return type of methods (#8619) ([053da5b](https://github.com/discordjs/discord.js/commit/053da5bc91d5cfa8d842b13b0b05083d2f7f086d)) +- Ensure events possess `Client<true>` (#8612) ([a9f003a](https://github.com/discordjs/discord.js/commit/a9f003ac9b56d31166cbf353d02140dad0b2517e)) +- **GuildChannelManager:** Correct `fetch` return type (#8549) ([1d4cdee](https://github.com/discordjs/discord.js/commit/1d4cdee321ab25bb0f109d55a000582825dd79f9)) +- **ThreadChannel:** `fetchStarterMessage` must return a `Message<true>` (#8560) ([b9c62ac](https://github.com/discordjs/discord.js/commit/b9c62ac0f0f534c33f9913135095f8b3d98ec05e)) +- **webhook:** Avatar can be null (#8541) ([f77612a](https://github.com/discordjs/discord.js/commit/f77612a55e9c593a21bc27e58c9fbd03d85787e3)) + +# [14.3.0](https://github.com/discordjs/discord.js/compare/14.2.0...14.3.0) - (2022-08-22) + +## Bug Fixes + +- **GuildMemberManager:** `add()` method throws an error (#8539) ([3bef901](https://github.com/discordjs/discord.js/commit/3bef9018c0be3c5dc51d03b796d08b925dc4e1b9)) +- **Guild:** Widget channel types and fixes (#8530) ([23a0b6c](https://github.com/discordjs/discord.js/commit/23a0b6ccf27410963bd4f5c53d9ee2ce019e90a8)) +- **Embed:** Reference video in video (#8473) ([c97977a](https://github.com/discordjs/discord.js/commit/c97977a3e806bd5d8682bc7fb22ebec1a8ceecdc)) + +## Documentation + +- **GuildAuditLogsEntry:** Correct `action` wording (#8499) ([7d25072](https://github.com/discordjs/discord.js/commit/7d2507279cc9d1397c7d61e7c7b856ff4bc17c86)) + +## Features + +- **GuildMemberManager:** AddRole and removeRole (#8510) ([cda3f00](https://github.com/discordjs/discord.js/commit/cda3f005b1546fdb8410e9550526956f840857fc)) +- Deprecate `ActionRow.from()` (#8504) ([f9c25dd](https://github.com/discordjs/discord.js/commit/f9c25ddcfe68f089e13f1090c3df4bd7cd74d2b7)) +- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166)) + +## Refactor + +- **GuildAuditLogsEntry:** Remove `guild` from application command permission update extra (#8520) ([2b8074d](https://github.com/discordjs/discord.js/commit/2b8074dd12f2f1e957caffb57e5fd4d7be88dc25)) + +## Typings + +- Inference of guild in `MessageManager` (#8538) ([6bb1474](https://github.com/discordjs/discord.js/commit/6bb1474d2001b76773954c959b2c2687e1df0136)) +- Allow choice's value type to be strictly inferred (#8529) ([b3f7c32](https://github.com/discordjs/discord.js/commit/b3f7c32f7f91f12766178f5e17585856e81d9a87)) +- **GuildAuditLogs:** Allow fetching to return all possible values (#8522) ([0dba8ad](https://github.com/discordjs/discord.js/commit/0dba8adbd2e6efd634bd3eb31df09467ba8a8a0d)) +- Correct `EventEmitter.on (static)` return type (#8524) ([16bbc8a](https://github.com/discordjs/discord.js/commit/16bbc8aa208a8a16c22be24696f57d5f7a5faf2b)) +- **GuildAuditLogs:** Remove static `Entry` (#8521) ([7a3d18d](https://github.com/discordjs/discord.js/commit/7a3d18dd6d1fe27393d00019b9ecd35c98b95ee7)) +- Disallow some channel types from webhook creation (#8531) ([4882b17](https://github.com/discordjs/discord.js/commit/4882b17a77484f801faa19fb971f2e6abd88e59f)) +- Implement max/min values for autocomplete (#8498) ([812f7f1](https://github.com/discordjs/discord.js/commit/812f7f1ea86fc953aa796875cbc7ccc434203d77)) +- **ModalMessageModalSubmitInteraction:** ChannelId is not nullable (#8496) ([c31a5cf](https://github.com/discordjs/discord.js/commit/c31a5cfcc82706667768eac77b5f99ba69cf3c91)) +- Change type of ApplicationCommandSubCommand.options (#8476) ([ebaf158](https://github.com/discordjs/discord.js/commit/ebaf158006d3c7db3b8c695e7c027b8af11999ba)) + +# [14.2.0](https://github.com/discordjs/discord.js/compare/14.1.2...14.2.0) - (2022-08-10) + +## Bug Fixes + +- **ThreadChannel:** Handle possibly `null` parent (#8466) ([afa27b1](https://github.com/discordjs/discord.js/commit/afa27b15c5b92bc8d55b8285834d8e03f6692d06)) +- Remove DM channels from `Client#messageDeleteBulk`'s types (#8460) ([6c6fe74](https://github.com/discordjs/discord.js/commit/6c6fe74dd84859c5319efa999404e8168f189710)) +- **Transformers:** Do not transform `Date` objects (#8463) ([0e2a095](https://github.com/discordjs/discord.js/commit/0e2a09571c8e5ee61153b04e45334a226a1b4534)) +- **ModalSubmitInteraction:** Allow deferUpdate (#8455) ([0fab869](https://github.com/discordjs/discord.js/commit/0fab869e5179dca7ddec75b5519615278e51ad82)) +- **Guild:** Unable to fetch templates (#8420) ([aac8acc](https://github.com/discordjs/discord.js/commit/aac8acc22be7d7af99933ef099eca7deda43cb40)) +- **MessageMentions:** Infinite loop in `parsedUsers` getter (#8430) ([b8a3136](https://github.com/discordjs/discord.js/commit/b8a31360a220e3d796f5381bd215d30a379ecb7c)) +- **DataResolver:** Make `Buffer` from string (#8416) ([e72b986](https://github.com/discordjs/discord.js/commit/e72b986939e2958547c0e54d6d27472c8d111609)) + +## Documentation + +- Change registration example to use global commands (#8454) ([64a4041](https://github.com/discordjs/discord.js/commit/64a4041a05e9514334a9f9e1f38a1ea18bb676d5)) +- **Colors:** Provide enum descriptions (#8437) ([6ef4754](https://github.com/discordjs/discord.js/commit/6ef4754d40c5ec65715fc1e00e643c52fe0a6209)) +- **AttachmentBuilder:** Fix #8407 (#8421) ([5b053cf](https://github.com/discordjs/discord.js/commit/5b053cf82ec2f2b717a490485af052dc956fe3c9)) + +## Features + +- **Guild:** Add `max_video_channel_users` (#8423) ([3a96ce7](https://github.com/discordjs/discord.js/commit/3a96ce7970947f6268c21a1323d986aac8cb736d)) + +## Typings + +- **Message:** Correct `bulkDelete` return type (#8465) ([c5b96a1](https://github.com/discordjs/discord.js/commit/c5b96a185cb8ba836b7cd10526c14059866f218f)) +- Fix missing types for mentionable options (#8443) ([452e94f](https://github.com/discordjs/discord.js/commit/452e94fd3ecc12de9e3408982c5c7fd931bae634)) +- **ApplicationCommandOption:** Add `ApplicationCommandBooleanOption` (#8434) ([38275fc](https://github.com/discordjs/discord.js/commit/38275fc53d633ce77ed2b142aff788dcbd4fad8c)) + +# [14.1.2](https://github.com/discordjs/discord.js/compare/14.1.1...14.1.2) - (2022-07-30) + +## Bug Fixes + +- **errors:** Error codes (#8398) ([480c85c](https://github.com/discordjs/discord.js/commit/480c85c9c3d129204b3399ed726a4e570e0b2852)) + +## Documentation + +- **Embed:** Ensure height and width are numbers (#8396) ([fca3dad](https://github.com/discordjs/discord.js/commit/fca3dada2a565eecfc7e5275cc9317df1d261871)) + +# [14.1.0](https://github.com/discordjs/discord.js/compare/14.0.3...14.1.0) - (2022-07-29) + +## Bug Fixes + +- **MessageMentions:** `ignoreRepliedUser` option in `has()` (#8202) ([b4e2c0c](https://github.com/discordjs/discord.js/commit/b4e2c0c4d5538b945f9d597c6410a6f84b315084)) +- **GuildChannelManager:** Allow unsetting rtcRegion (#8359) ([a7d49e5](https://github.com/discordjs/discord.js/commit/a7d49e56fc7c34d2e4548d9e5bf0aec45273506e)) +- **ThreadChannel:** Omit webhook fetching (#8351) ([3839958](https://github.com/discordjs/discord.js/commit/3839958e3f682c715f1017da05436d2fe34900fd)) +- **GuildAuditLogsEntry:** Replace OverwriteType with AuditLogOptionsType (#8345) ([58c1b51](https://github.com/discordjs/discord.js/commit/58c1b51c5ceab137ad9851919b338419eeeab69e)) +- **ShardClientUtil#_respond:** Construct global error (#8348) ([8e520f9](https://github.com/discordjs/discord.js/commit/8e520f946a5b9f93a939290facf4ccca2c05ff21)) +- **Presence:** Do not return NaN for activity timestamp (#8340) ([df42fdf](https://github.com/discordjs/discord.js/commit/df42fdfc421f1190f0a2267a66efd3c921ec2348)) +- **Client:** Omit private properties from toJSON (#8337) ([830c670](https://github.com/discordjs/discord.js/commit/830c670c61dcb17d8ab2a894a3203c68917d27e0)) +- **ApplicationCommandManager:** Allow passing 0n to defaultMemberPermissions (#8311) ([1fb7b30](https://github.com/discordjs/discord.js/commit/1fb7b30963cfe7ea4c05b1f3b42171c879c46a1d)) + +## Documentation + +- **InteractionResponses:** Add `showModal()` return type (#8376) ([0b61dbf](https://github.com/discordjs/discord.js/commit/0b61dbf720e844322b066e30080c3537ab3d8174)) +- **WebhookClient:** Document working options (#8375) ([ba6797e](https://github.com/discordjs/discord.js/commit/ba6797e74209161b64c412de1b6f307cb28736b8)) +- **Message:** Document gateway intent for content (#8364) ([2130aae](https://github.com/discordjs/discord.js/commit/2130aae3210a8eaf91c5ccae5463940d49052c7d)) +- Use info blocks for requirements (#8361) ([80b9738](https://github.com/discordjs/discord.js/commit/80b9738957ebf5b6eb7c9858cec0fb1c897d0a1f)) +- **WebhookClient:** Make constructor a union (#8370) ([e9920a9](https://github.com/discordjs/discord.js/commit/e9920a9c98ffb78bd7d0ae00d486476367296646)) +- Update docs and examples to PascalCase links (#8305) ([34ba9d1](https://github.com/discordjs/discord.js/commit/34ba9d1c4c80eff7e6ac199a40232d07491432cc)) + +## Features + +- Add channel & message URL formatters (#8371) ([a7deb8f](https://github.com/discordjs/discord.js/commit/a7deb8f89830ead6185c5fb46a49688b6d209ed1)) +- Restore missing typeguards (#8328) ([77ed407](https://github.com/discordjs/discord.js/commit/77ed407f6aadb68e729470c5269e9b526cb1b3f0)) +- **GuildMember:** Add dmChannel getter (#8281) ([4fc2c60](https://github.com/discordjs/discord.js/commit/4fc2c60a3bb43671b4b0202ae75eab42aba163ff)) + +## Refactor + +- Deprecate `Formatter` class (#8373) ([7fd9ed8](https://github.com/discordjs/discord.js/commit/7fd9ed8f13d17ce7e98e34f7454d9047054d8467)) +- **PermissionOverwriteManager:** Use `OverwriteType` (#8374) ([6d24805](https://github.com/discordjs/discord.js/commit/6d248051cfd431e9cb1c65cb98f56aa0a6556407)) + +## Typings + +- **GuildAuditLogsEntryExtraField:** Use `AuditLogOptionsType` (#8349) ([200ab91](https://github.com/discordjs/discord.js/commit/200ab91f527d8a5706d277b89a975096f75d141a)) + +# [14.0.3](https://github.com/discordjs/discord.js/compare/14.0.2...14.0.3) - (2022-07-19) + +## Bug Fixes + +- **Components:** Support emoji id strings (#8310) ([660e212](https://github.com/discordjs/discord.js/commit/660e212e83df026c684ee2cda7fb4e98870f342e)) + +# [14.0.2](https://github.com/discordjs/discord.js/compare/14.0.1...14.0.2) - (2022-07-18) + +## Bug Fixes + +- **DataResolver#resolveImage:** Adjust to updated resolveFile (#8308) ([3a7e93d](https://github.com/discordjs/discord.js/commit/3a7e93df576172c797f1d8bd6483234bb6af2d00)) + +# [14.0.0](https://github.com/discordjs/discord.js/compare/9.3.1...14.0.0) - (2022-07-17) + +## Bug Fixes + +- **GuildMemberManager:** Allow setting own nickname (#8066) ([52a9e21](https://github.com/discordjs/discord.js/commit/52a9e213c2dc13ee52ee0234593fdce392f43890)) +- **PermissionOverwriteManager:** Mutates user (#8283) ([3bf30b1](https://github.com/discordjs/discord.js/commit/3bf30b1e6d2d6f583f7069a1e24e7842d59fab2f)) +- **GuildChannelManager:** Access `resolveId` correctly (#8296) ([3648f6d](https://github.com/discordjs/discord.js/commit/3648f6d567cd834c301de913ce19f786a265240d)) +- **GuildChannelManager:** Edit lockPermissions (#8269) ([7876548](https://github.com/discordjs/discord.js/commit/787654816d2b6a5168d199d32cdaeb4ef6d270b9)) +- **`SelectMenuBuilder`:** Properly accept `SelectMenuOptionBuilder`s (#8174) ([31d5930](https://github.com/discordjs/discord.js/commit/31d593046466438c55f5784b0f2098e233c5edc4)) +- Remove global flag on regular expressions (#8177) ([cdd9214](https://github.com/discordjs/discord.js/commit/cdd9214212892e30b3eaa161837c37516c5bcaa0)) +- **MessagePayload:** Guard against `repliedUser` property (#8211) ([fa010b5](https://github.com/discordjs/discord.js/commit/fa010b516254c4ab2762278817f31bf289f0ab6a)) +- **ApplicationCommandManager:** Explicitly allow passing builders to methods (#8209) ([50d55bd](https://github.com/discordjs/discord.js/commit/50d55bd6b819307c86701f4808c087f359c6ccff)) +- **GuildMemberRemove:** Remove member's presence (#8181) ([11b1739](https://github.com/discordjs/discord.js/commit/11b173931968c548f8504649ae7090865892e62d)) +- Edit() data can be partial and `defaultMemberPermissions` can be `null` (#8163) ([0ffbef5](https://github.com/discordjs/discord.js/commit/0ffbef506a97a0bf22cb134fc007c2aec29cbffc)) +- **WebSocketShard:** Keep an error handler on connections (#8150) ([c34c02a](https://github.com/discordjs/discord.js/commit/c34c02ab8d119bf16d8d14d125a9b650b4bb18f4)) +- **DJSError:** Error code validation (#8149) ([31f6582](https://github.com/discordjs/discord.js/commit/31f658247fe0e1047897edab629643d140e77e07)) +- **vcs:** Nsfw property (#8132) ([2eeaad6](https://github.com/discordjs/discord.js/commit/2eeaad6f27fdf8868364fa95ed20755ee09bda87)) +- **WebSocketManager:** Correct error name (#8138) ([db2b033](https://github.com/discordjs/discord.js/commit/db2b0333d912fe83381db2ffe16829d7d03d6c2e)) +- **WebSocketShard:** Disconnected casing (#8117) ([23e183a](https://github.com/discordjs/discord.js/commit/23e183a9ac7aaa3bca2bc4eb8634d1738ec34a26)) +- **webhooks:** Revert webhook caching (and returning Message) (#8038) ([d54bf5d](https://github.com/discordjs/discord.js/commit/d54bf5d286f4057db130901591b192fd4d1668c1)) +- **ApplicationCommand:** Remove `autocomplete` check at the top level and correctly check for `dmPermission` (#8100) ([0a44b05](https://github.com/discordjs/discord.js/commit/0a44b05db83948857afbe18471e7a867da47177a)) +- **ApplicationCommand:** Fix default member permissions assignment (#8067) ([96053ba](https://github.com/discordjs/discord.js/commit/96053babe1bd65ebe1fc6a261f5eb052906afdb9)) +- **scripts:** Read directory and rerun (#8065) ([f527dea](https://github.com/discordjs/discord.js/commit/f527dea36ead194aaae1bf5da1e953df59d692fd)) +- Select menu options to accept both rest and array (#8032) ([fbe67e1](https://github.com/discordjs/discord.js/commit/fbe67e102502b4b49690cbf8ff891ead2232ecf3)) +- **CommandInteractionOptionResolver:** Handle autocompletion interactions (#8058) ([d8077c6](https://github.com/discordjs/discord.js/commit/d8077c6839dc8ceb57d3c3a86bf9746be2a91ada)) +- **scripts:** Add quotes around blob arguments (#8054) ([598f61b](https://github.com/discordjs/discord.js/commit/598f61b992fab1b3fdcab8ff960366f7af0b37ea)) +- **Message:** Force fetching (#8047) ([f2b267c](https://github.com/discordjs/discord.js/commit/f2b267c079dd8aa7277910471f3db2f88af6efb2)) +- **Attachment:** Do not destructure `data` (#8041) ([1afae90](https://github.com/discordjs/discord.js/commit/1afae909d72e648cf48d63d7de2708737a78c126)) +- **DirectoryChannel:** Type `name` and handle `url` (#8023) ([86d8fbc](https://github.com/discordjs/discord.js/commit/86d8fbc023e3925e8f86799d6ebf2d423f7bf2ec)) +- Readd `isThread` type guard (#8019) ([f8ed71b](https://github.com/discordjs/discord.js/commit/f8ed71bfca6e47e3d44ad063e23804354bd23604)) +- Add static method `from` in builders (#7990) ([ad36c0b](https://github.com/discordjs/discord.js/commit/ad36c0be7744ea4214ccf345fe80a5a1a9e89101)) +- Typings (#7965) ([7a1095b](https://github.com/discordjs/discord.js/commit/7a1095b66be3c5d81185e026281e2908c10c1695)) +- **GuildAuditLogs:** Cache guild scheduled events (#7951) ([2f03f9a](https://github.com/discordjs/discord.js/commit/2f03f9ad3f63abee5b5c46d02f1afa8885e8977c)) +- Make sure action row builders create djs builders (#7945) ([adf461b](https://github.com/discordjs/discord.js/commit/adf461baf49be754c7a10c61faf1ef3df333413a)) +- **TextBasedChannel#bulkDelete:** Return deleted message (#7943) ([191510b](https://github.com/discordjs/discord.js/commit/191510b7f87903e4bd93b891649cb290fd50c47e)) +- Remove trailing invites on channel deletion (#7932) ([5e9b757](https://github.com/discordjs/discord.js/commit/5e9b757a3733e6526770eb60a15072612294eb21)) +- **DataResolver:** Fix check for readable streams (#7928) ([28172ca](https://github.com/discordjs/discord.js/commit/28172ca7b57357436d3252ec01ec17dad865d87f)) +- **AuditLog:** Default changes to empty array (#7880) ([19eaed6](https://github.com/discordjs/discord.js/commit/19eaed63905367ef4604366b8839023384524d1f)) +- **Util:** Flatten ignoring certain fields (#7773) ([df64d3e](https://github.com/discordjs/discord.js/commit/df64d3ea382c07e66bc7cc8877ee430206c31d63)) +- Possibly missing (#7829) ([6239d83](https://github.com/discordjs/discord.js/commit/6239d83c4d5f0a396678410d7fef35e39ed29009)) +- `endReason` not being properly set in base Collector (#7833) ([0c18dab](https://github.com/discordjs/discord.js/commit/0c18dab1280205b8855d17d075b7421860d59c14)) +- **SelectMenuBuilder:** Options array (#7826) ([3617093](https://github.com/discordjs/discord.js/commit/361709332bdc871822c2b9919f14fd090d68666a)) +- **Activity:** Platform type (#7805) ([4ac91c6](https://github.com/discordjs/discord.js/commit/4ac91c61d08111ae4d49d1e64caf94e6e49832c8)) +- **ApplicationCommand:** Equal nameLocalizations and descriptionLocalizations (#7802) ([4972bd8](https://github.com/discordjs/discord.js/commit/4972bd87c17cbc6a94c9608ba2ab39c475f9921f)) +- **InteractionResponses:** Use optional chaining on nullable property (#7812) ([c5fb548](https://github.com/discordjs/discord.js/commit/c5fb54852906898ffb19282dd60168dfc6fb2eba)) +- **MessageManager:** Allow caching option of an unspecified limit (#7763) ([1b2d8de](https://github.com/discordjs/discord.js/commit/1b2d8decb638faeae8184119c5cedfcdaf9485e3)) +- **builders:** Add constructor default param (#7788) ([c286650](https://github.com/discordjs/discord.js/commit/c2866504a3824005fe756556fec4b349898b7d22)) +- **MessagePayload:** ResolveBody check body instead of data (#7738) ([3db20ab](https://github.com/discordjs/discord.js/commit/3db20abdd2d502a1ed457842181b164dc6390ba1)) +- **ActionRow:** ToJSON should include components (#7739) ([ebb4dfa](https://github.com/discordjs/discord.js/commit/ebb4dfa262adb2086c83db487002bb2e1ed5ab88)) +- Prevent `NaN` for nullable timestamps (#7750) ([8625d81](https://github.com/discordjs/discord.js/commit/8625d817145eb642aeb0da05184352f438586986)) +- **InteractionCreateAction:** Ensure text-based channel for caching messages (#7755) ([25fdb38](https://github.com/discordjs/discord.js/commit/25fdb3894d33dc395a376a3d962a063eb5735253)) +- Pass `force` correctly (#7721) ([402514f](https://github.com/discordjs/discord.js/commit/402514ff323ccf1f8c95d295f044cf0bb5547c2e)) +- Support reason in setRTCRegion helpers (#7723) ([905a6a1](https://github.com/discordjs/discord.js/commit/905a6a11663f9469ada67f8310a969453ffc5b2a)) +- **GuildMemberManager:** Return type can be null (#7680) ([74bf7d5](https://github.com/discordjs/discord.js/commit/74bf7d57ab959eb820ab1c213ac86ab1ea660398)) +- **gateway:** Use version 10 (#7689) ([8880de0](https://github.com/discordjs/discord.js/commit/8880de0cecdf273fd6df23988e4cb77774a75390)) +- Audit log static reference (#7703) ([85e531f](https://github.com/discordjs/discord.js/commit/85e531f22d7a8f8ad043647ce445726ae0df26c0)) +- Handle possibly missing property (#7641) ([0c32332](https://github.com/discordjs/discord.js/commit/0c32332a5aacbbb6c415da75c166d09cfdb34bbd)) +- **util:** Allow `escapeInlineCode` to escape double backtics (#7638) ([d5369a5](https://github.com/discordjs/discord.js/commit/d5369a56e3fcf50513f3bc582552c2838b04d199)) +- **GuildEditData:** Some fields can be null (#7632) ([4d2b559](https://github.com/discordjs/discord.js/commit/4d2b55955d1a3ff05c3047599232becdc3f2c445)) +- TOKEN_INVALID error not thrown at login with invalid token (#7630) ([cd79bef](https://github.com/discordjs/discord.js/commit/cd79bef2547594f4d0c744faa8fa67fb9fd61526)) +- **GuildScheduledEvent:** Handle missing `image` (#7625) ([c684ac5](https://github.com/discordjs/discord.js/commit/c684ac55e1d225740e67ab7bd5643de1b35f4594)) +- **guild:** Throw if ownerId falsey (#7575) ([98177aa](https://github.com/discordjs/discord.js/commit/98177aa38d3d6516d4c5354d6c7edea925dc881d)) +- Remove Modal export (#7654) ([87a6b84](https://github.com/discordjs/discord.js/commit/87a6b8445bfbf3981cd39813fe961dfa1c7f2bce)) +- **Embed:** Fix incorrect destructuring import (#7615) ([cbdb408](https://github.com/discordjs/discord.js/commit/cbdb408dffd1c7f2193c15989528a3de5fd9f13a)) +- **ThreadMembersUpdate:** Only emit added & removed thread members (#7539) ([c12d61a](https://github.com/discordjs/discord.js/commit/c12d61a3421afcdc41f77c0fddde4efbb257fa69)) +- **Util:** EscapeInlineCode properly (#7587) ([851f380](https://github.com/discordjs/discord.js/commit/851f380eb10d23ffd08e8b845aed4039abbcd03b)) +- **GuildStickerManager:** Correctly access guild ID (#7605) ([4b08d9b](https://github.com/discordjs/discord.js/commit/4b08d9b376bda7a7f4bb3fb8c555d25cca648de4)) +- **MessageManager:** Pin route (#7610) ([cb566c8](https://github.com/discordjs/discord.js/commit/cb566c8b6abff489a944db7952e5c5a48e0c98b0)) +- Handle partial data for `Typing#user` (#7542) ([c6cb5e9](https://github.com/discordjs/discord.js/commit/c6cb5e9ebbf46d81404119a6aa11bb8ebb17d5a4)) +- **guild:** Fix typo accessing user instead of users (#7537) ([8203c5d](https://github.com/discordjs/discord.js/commit/8203c5d843f2431c0f49023282f1bf73d85881d1)) +- **test:** `MessageActionRow` to `ActionRow` (#7523) ([d1d1b07](https://github.com/discordjs/discord.js/commit/d1d1b076bebf7cb706b2436a40d87c6efaed1e1d)) +- **MessagePayload:** Don't set reply flags to target flags (#7514) ([4f30652](https://github.com/discordjs/discord.js/commit/4f306521d829fef21ebd70557b37f8199b82572b)) +- **invite:** Add back channelId property (#7501) ([78aa36f](https://github.com/discordjs/discord.js/commit/78aa36f9f5913b86c82376ecdf20653b15340bbe)) +- Properly serialize `undefined` values (#7497) ([8dbd345](https://github.com/discordjs/discord.js/commit/8dbd34544cbeb499282f01dda9d35ed9bca93591)) +- Allow unsafe embeds to be serialized (#7494) ([942ea1a](https://github.com/discordjs/discord.js/commit/942ea1acbfb49289ccb3a1882b5a2da0a7d0bccf)) +- Attachment types (#7478) ([395a68f](https://github.com/discordjs/discord.js/commit/395a68ff49c622d5136d6b775beaf8e88a2d8610)) +- Use case converter for json component serialization (#7464) ([2d45544](https://github.com/discordjs/discord.js/commit/2d4554440ed9329a5876a9c674c3eb2de0f2f917)) +- **GuildAuditLogs:** Typings and consistency (#7445) ([c1b27f8](https://github.com/discordjs/discord.js/commit/c1b27f8eed8ea04a48bc106453892bddcdc6b73e)) +- **dataresolver:** Ensure fetched file is convert to a buffer (#7457) ([9311fa7](https://github.com/discordjs/discord.js/commit/9311fa7b42b2b5a74e411aa263daa4fbfc270645)) +- **messagepayload:** ResolveFile property names (#7458) ([a8106f7](https://github.com/discordjs/discord.js/commit/a8106f7c586f0ecac76e7f72c53b0da215a6fbf1)) +- **ci:** Ci error (#7454) ([0af9bc8](https://github.com/discordjs/discord.js/commit/0af9bc841ffe1a297d308500d696bad4b85abda9)) +- **threads:** Require being sendable to be unarchivable (#7406) ([861f0e2](https://github.com/discordjs/discord.js/commit/861f0e2134662ab64a11d313130aff58b413d495)) +- **guildmember:** Check if member has administrator permission (#7384) ([81d8b54](https://github.com/discordjs/discord.js/commit/81d8b54ff6b98b0e7ee2c57eaee6bc0b707e135a)) +- **guild:** Remove `maximumPresences` default value (#7440) ([55b388a](https://github.com/discordjs/discord.js/commit/55b388a763dc7223e88b62ae928fe85fe8b8fe58)) +- **guildchannelmanager:** Edit always sets parent to null (#7446) ([b97aedd](https://github.com/discordjs/discord.js/commit/b97aedd8e15f9358960cb59403f3a8ea24b87141)) +- **guildmember:** Make `pending` nullable (#7401) ([fe11ff5](https://github.com/discordjs/discord.js/commit/fe11ff5f6e85571a981e90eba5b9f3bda7a2cd04)) +- **clientpresence:** Fix used opcodes (#7415) ([a921ec7](https://github.com/discordjs/discord.js/commit/a921ec7dc525c58d40b4678e66270f9238abed31)) +- Correctly export UnsafeSelectMenuComponent from builders (#7421) ([aadfbda](https://github.com/discordjs/discord.js/commit/aadfbda586d57a7b775ad26c201f0dc34618180b)) +- MessageReaction.me being false when it shouldn't (#7378) ([04502ce](https://github.com/discordjs/discord.js/commit/04502ce702da53c4b00bf391d0fd936746851381)) +- Fix some typos (#7393) ([92a04f4](https://github.com/discordjs/discord.js/commit/92a04f4d98f6c6760214034cc8f5a1eaa78893c7)) +- **messagementions:** Fix `has` method (#7292) ([3a5ab2c](https://github.com/discordjs/discord.js/commit/3a5ab2c4e54de4e67ab6e323d7eac86482da7382)) +- **guildmembermanager:** Use rest in edit (#7356) ([00ce1c5](https://github.com/discordjs/discord.js/commit/00ce1c56ac224691a8691a3525cb14ae002319c6)) +- **typings:** Mark `RESTOptions` as Partial in `ClientOptions` (#7349) ([e1ecc1a](https://github.com/discordjs/discord.js/commit/e1ecc1a80a9358cdbafbe8542c40b9de8cad467e)) +- **Webhook:** Use correct method name (#7348) ([11e5e5a](https://github.com/discordjs/discord.js/commit/11e5e5ac5b70138f56332eb3e61a42443670b0de)) +- **thread:** Don't assign directly to getters (#7346) ([2db0cdd](https://github.com/discordjs/discord.js/commit/2db0cdd357c3a02decb4fd4168db87888efba283)) +- Missed enums and typings from #7290 (#7331) ([47633f0](https://github.com/discordjs/discord.js/commit/47633f0fd2435d6d8c694d8d37b26039a7b3797a)) +- **guildchannelmanager:** Remove reverse enum lookup (#7304) ([857bba4](https://github.com/discordjs/discord.js/commit/857bba448029f3f070c67fb40b59a3a2a2e5c6f4)) +- Import `clear{Timeout,Interval}` from `node:timers` (#7269) ([8ddd44e](https://github.com/discordjs/discord.js/commit/8ddd44ed85b32c86243efe0ec35b283eaaa8212c)) +- **ApplicationCommand:** Use new ApplicationCommandOptionType enums (#7257) ([06f5210](https://github.com/discordjs/discord.js/commit/06f5210f58bbba6102173033a9f1e6fb004fdf5d)) +- Use enums from discord-api-types (#7258) ([f284a46](https://github.com/discordjs/discord.js/commit/f284a4641fd68de9190bda97ec1eab0981149630)) +- **exports:** Export ApplicationCommandType properly (#7256) ([f753882](https://github.com/discordjs/discord.js/commit/f75388259262bf6b4a64375b97800bd72378f3bc)) +- **Shard:** EventEmitter listener warning (#7240) ([ff3a8b8](https://github.com/discordjs/discord.js/commit/ff3a8b83234d3826fc49c5a8c3cb52ef9f281ffd)) +- **timestamps:** Account for timestamps of 0 when creating Dates (#7226) ([a8509c9](https://github.com/discordjs/discord.js/commit/a8509c91ca0147393b407221405b6b917677961a)) +- **MessageEmbed:** CreatedAt field can be zero (#7218) ([37cad54](https://github.com/discordjs/discord.js/commit/37cad54dbdade39607397b8ad697eca94f1b7197)) +- **BaseClient:** Do not append default options if provided is not an object (#6453) ([b92a7d7](https://github.com/discordjs/discord.js/commit/b92a7d72332c35b607db54aa6aca24b8e10e00ad)) +- Snowflakeutil import (#7219) ([962f4bf](https://github.com/discordjs/discord.js/commit/962f4bf88211dbfb5ad0295a9467dede1e2688ee)) +- **Role:** Remove unused process (#7215) ([63034b4](https://github.com/discordjs/discord.js/commit/63034b44c9849087e391684d9b6c0c6ae9a21113)) +- **WebhookClient:** Updated webhook url regex (#6804) ([1c615d1](https://github.com/discordjs/discord.js/commit/1c615d1bb2606d5f19e55076d4ecab95c619518e)) +- **Sweepers:** Add sweepStickers function (#7213) ([95f8375](https://github.com/discordjs/discord.js/commit/95f8375d425f58f501f32ead03f7927e6596f8e6)) +- **InteractionCreate:** Use ChatInputCommandInteraction instead (#7210) ([49dada3](https://github.com/discordjs/discord.js/commit/49dada35f92470d3e4426362510847b93dd42d1a)) +- **Structues:** Rename old module's name (#7207) ([fbef454](https://github.com/discordjs/discord.js/commit/fbef45489457a2198357dc4dd303740d79036784)) +- **WebSocket:** Remove application command handler (#7202) ([033151c](https://github.com/discordjs/discord.js/commit/033151cf92fe43536b8a4c0f4d7d9ed75a2095c5)) +- **User:** `bannerURL()` should not throw when not present (#6789) ([3872acf](https://github.com/discordjs/discord.js/commit/3872acfeb8390f6f7202d69cf1f7f8616a7b0b34)) +- **VoiceState:** Ensure `suppress` & `streaming` have proper fallback values (#6377) ([a0d5f13](https://github.com/discordjs/discord.js/commit/a0d5f13dd9b27c44f5183a2a9af4c4fdecb312c0)) +- **sweepers:** Provide default for object param (#7182) ([ae2f013](https://github.com/discordjs/discord.js/commit/ae2f013653c8a9f9ffb12ae8fcdb1bb604b39236)) + +## Deprecation + +- **Caching:** Clean up deprecated cache sweeping (#7118) ([12ffa06](https://github.com/discordjs/discord.js/commit/12ffa069aa8b247e945fef16a543f41c2c391bf1)) + +## Documentation + +- Align webhook method return types with implementation (#8253) ([5aeed99](https://github.com/discordjs/discord.js/commit/5aeed9935058241648507d7f651679226a89dbb3)) +- Remove `@private` constructor documentation (#8255) ([452dec5](https://github.com/discordjs/discord.js/commit/452dec57ca422f5e7424a0f0e78c3e152717f413)) +- **ApplicationCommand:** Add `min_length` and `max_length` to ApplicationCommandOptionData (#8239) ([43f62bb](https://github.com/discordjs/discord.js/commit/43f62bb6678ec332795c8cfbe0c01854b95aa61e)) +- **MessageInteraction#commandName:** Updated description (#8212) ([ab238a9](https://github.com/discordjs/discord.js/commit/ab238a9046e0201dbd4755fa41fa69c44b186912)) +- Add missing `@extends` (#8205) ([e0c8282](https://github.com/discordjs/discord.js/commit/e0c82824905dcebf62c2d1afcc5e5590a5594838)) +- **Constants:** Fix SweeperKeys type (#8157) ([af04992](https://github.com/discordjs/discord.js/commit/af04992ed3c2617fda686c2bc7338dcada283dc6)) +- **Channels:** Internally document channel creation (#8154) ([5e5853a](https://github.com/discordjs/discord.js/commit/5e5853a4e885c47e3dde519761dd59a5ec0e06fc)) +- Update threads to use `ThreadAutoArchiveDuration` (#8153) ([ee36d60](https://github.com/discordjs/discord.js/commit/ee36d60dc6714c83569a20716fa8ca8e1bd7de4f)) +- **APITypes:** Remove duplicate type definition (#8144) ([a061233](https://github.com/discordjs/discord.js/commit/a0612335101c7ce2a07d95da4b79f0d4a2b1a6a0)) +- Document missing type definitions (#8130) ([203bc4a](https://github.com/discordjs/discord.js/commit/203bc4a2cf0c2d90a003093318aa0741605610f5)) +- **InteractionResponse:** Fix return (#8141) ([f1ac17c](https://github.com/discordjs/discord.js/commit/f1ac17c961cf95d99e205133605d10d8be5bd737)) +- **PermissionsBitField:** Fix `@name` of bitfield (#8115) ([3a77ce0](https://github.com/discordjs/discord.js/commit/3a77ce0b18c60a0b21ba088590ff89f2ace94087)) +- `TextBasedChannel` -> `TextBasedChannels` typos (#8110) ([db663a5](https://github.com/discordjs/discord.js/commit/db663a55c2ed2faf61e217009158da50dfcf274f)) +- Remove `number`s from enums (#8098) ([0a138da](https://github.com/discordjs/discord.js/commit/0a138dab95a86512f08ac3be356f77f38f2ea880)) +- **GuildAuditLogs:** Fix and reimplement type definitions (#8108) ([4155136](https://github.com/discordjs/discord.js/commit/415513696c7b7e139d1b958e480bf0c7e4d14111)) +- **WebSocketOptions:** Add `version` to docs and typings (#8050) ([386c41f](https://github.com/discordjs/discord.js/commit/386c41f24fb3c9d06967d9c1881a57645c3a71f2)) +- **BaseGuildTextChannel:** Update `setType()`'s parameter type (#8088) ([9c0f190](https://github.com/discordjs/discord.js/commit/9c0f190de1f743d9bd597ffd656503c672db71c1)) +- Update outdated examples (#8081) ([51eadf3](https://github.com/discordjs/discord.js/commit/51eadf37371a6138847efdb4b5b81ee132001cf0)) +- **ThreadMemberManager:** Require `member` in `FetchThreadMemberOptions` (#8079) ([552ec72](https://github.com/discordjs/discord.js/commit/552ec72542ec3b2b3ebf35c9fd84ab502dd746cf)) +- **AutocompleteInteraction:** Change useless log in responds example (#8077) ([ac7bf69](https://github.com/discordjs/discord.js/commit/ac7bf692bfce8204e278205dde811515a51f154b)) +- Description and missing `@typedef` fixes (#8087) ([a2eebf6](https://github.com/discordjs/discord.js/commit/a2eebf6c66f3e4c96ece9d2ae2a1133c84257f42)) +- Ignore docs of unexported functions (#8051) ([94bdcac](https://github.com/discordjs/discord.js/commit/94bdcaca62414a77d4ee0b8b79752a2be937320b)) +- **ClientOptions:** Fix closeTimeout default (#8049) ([b2eea1c](https://github.com/discordjs/discord.js/commit/b2eea1c900ba73d4b98b72f5c196f51e27d3ab8f)) +- **DirectoryChannel:** Extend `Channel` (#8022) ([f3f34f0](https://github.com/discordjs/discord.js/commit/f3f34f07b3b396015b130b8e9d938a3eec688fc3)) +- **Attachment:** Remove constructor doc (#8009) ([0a7953e](https://github.com/discordjs/discord.js/commit/0a7953e46310c77483d277539b47f1a7ab051fd9)) +- **VoiceChannel:** Annotate that it is implementing TextBasedChannel (#8007) ([5987dbe](https://github.com/discordjs/discord.js/commit/5987dbe5cff6991ae6905b0387411fa042d3e9b7)) +- Add missing discord-api-types external types (#8001) ([546d486](https://github.com/discordjs/discord.js/commit/546d48655f36ed9a6c6c5ce3c2eabcca1a86a945)) +- **InteractionResponses:** Replace outdated Embed example for reply (#7875) ([d308c66](https://github.com/discordjs/discord.js/commit/d308c66eeca6bdc3471637ae3aaaaa0a2f5c9989)) +- Require parameter (#7838) ([f4ccc67](https://github.com/discordjs/discord.js/commit/f4ccc6772c15e32489ca22fb2c3e803b85d4dbf9)) +- **ApplicationCommand:** Fix and improve localization docs (#7804) ([61a44c5](https://github.com/discordjs/discord.js/commit/61a44c509c40abaf7ffb95b10942889cbbf155ac)) +- **ApplicationCommand:** Fix ApplicationCommandOptionChoice (#7794) ([f1d0084](https://github.com/discordjs/discord.js/commit/f1d0084da26b0111ca029c789ad9e8e6c2882b4d)) +- Add back static properties and methods (#7706) ([520f471](https://github.com/discordjs/discord.js/commit/520f471ac56cbc01402b79197333a8a34c4ac5c9)) +- **InteractionCollector:** Document channel option type (#7551) ([e787cd5](https://github.com/discordjs/discord.js/commit/e787cd5fa5d013319347392ee4f799a677f6f512)) +- Correctly type getters (#7500) ([ffecf08](https://github.com/discordjs/discord.js/commit/ffecf084956f954cf10e1b844e00326e443a86f2)) +- ApplicationCommandData typedef (#7389) ([d32db88](https://github.com/discordjs/discord.js/commit/d32db8833e1058fb36f2e83af79d5353a9f2f693)) +- **channel:** Fix `isDMBased` docs (#7411) ([f2a7a9f](https://github.com/discordjs/discord.js/commit/f2a7a9f1b30af272a6a8d81825d09f84e749cc24)) +- **messageattachment:** Fix `contentType` docs (#7413) ([2800e07](https://github.com/discordjs/discord.js/commit/2800e07e5974e07b9f8ce043722b9b99a5bcc80d)) +- Add supported option types for autocomplete (#7368) ([8bb3751](https://github.com/discordjs/discord.js/commit/8bb37513400d646d784d59875d6b6a6ec10160cd)) +- Add external builder docs links (#7390) ([0b866c9](https://github.com/discordjs/discord.js/commit/0b866c9fb284971113e288e52327d4506db28011)) +- Add EnumResolvers (#7353) ([72767a1](https://github.com/discordjs/discord.js/commit/72767a1059526bdf617e80d5a9e5da1fbd2936d3)) +- **locales:** Update Discord API docs link (#7266) ([b640272](https://github.com/discordjs/discord.js/commit/b6402723c31bed3c49f8b8cde873b65b9f373fd7)) +- **StageInstance:** Deprecate discoverableDisabled (#7179) ([bd33ebb](https://github.com/discordjs/discord.js/commit/bd33ebb507eab36bc2219103dbd1e0217b9f38c0)) +- **shardingmanager:** Fix type of `execArgv` option (#7284) ([e65da44](https://github.com/discordjs/discord.js/commit/e65da44d9c564d1ffcb0f4df2bcdaf0ce0636f35)) +- **interaction:** Add locale list link (#7261) ([37ec0bd](https://github.com/discordjs/discord.js/commit/37ec0bda6df75fb1dc69b7a1eafbb8ea19e68457)) +- Fix a typo and use milliseconds instead of ms (#7251) ([0dd56af](https://github.com/discordjs/discord.js/commit/0dd56afe1cdf16f1e7d9afe1f8c29c31d1833a25)) +- Fix command interaction docs (#7212) ([137ea24](https://github.com/discordjs/discord.js/commit/137ea249df3aa6b8375ecb42aa456a6fdb811f19)) +- **TextBasedChannel:** Fixed syntax error in examples (#7163) ([b454740](https://github.com/discordjs/discord.js/commit/b454740ae87b6c3c13536181965519c7277e5840)) +- **TextBasedChannel:** Fix #createMessageComponentCollector description (#7168) ([d4e6e03](https://github.com/discordjs/discord.js/commit/d4e6e0370857dff00185d59faf8aaac12b343a7a)) +- Fixes the examples for kick and ban (#7170) ([db669b8](https://github.com/discordjs/discord.js/commit/db669b897132ec458d50ca6c1e3afa761e98ffc3)) +- **RoleManager:** Fix incorrect example (#7174) ([f79ea67](https://github.com/discordjs/discord.js/commit/f79ea67d3a9ba134a9acef0a443bd089c4e173a6)) + +## Features + +- **builder:** Add max min length in string option (#8214) ([96c8d21](https://github.com/discordjs/discord.js/commit/96c8d21f95eb366c46ae23505ba9054f44821b25)) +- **applicationCommand:** Add max min length in string option (#8215) ([94ee60d](https://github.com/discordjs/discord.js/commit/94ee60d3d438f6657bdef51471528769af09624c)) +- Add website documentation early mvp (#8183) ([d95197c](https://github.com/discordjs/discord.js/commit/d95197cc78593df4d0a8d1cc492b0e41b4ab58b8)) +- **BaseInteraction:** Add support for `app_permissions` (#8194) ([002d6a5](https://github.com/discordjs/discord.js/commit/002d6a5aede3d1c0e08bd58eeef38a3b9202f525)) +- **util:** ParseWebhookURL (#8166) ([c4653f9](https://github.com/discordjs/discord.js/commit/c4653f97b1529eb0b99fccdba67c37eb4f467ff9)) +- **AutocompleteInteraction:** Add `commandGuildId` (#8086) ([10a6c42](https://github.com/discordjs/discord.js/commit/10a6c4287dd45a30290814e50fa29a086f85da02)) +- **guild:** Add support for setting MFA level (#8024) ([c5176be](https://github.com/discordjs/discord.js/commit/c5176be14b697ff506eb973c4119644eab544304)) +- **vcs:** Add missing property and methods (#8002) ([0415300](https://github.com/discordjs/discord.js/commit/0415300243877ddbcb501c0a26b1ff65618a1da7)) +- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21)) +- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc)) +- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86)) +- Backport handle zombie connection (#7626) ([e1176fa](https://github.com/discordjs/discord.js/commit/e1176faa27898d4f127c293c099201cb294e10ee)) +- **CommandInteraction:** Add 'commandGuildId' (#8018) ([aa59a40](https://github.com/discordjs/discord.js/commit/aa59a409b36c7ef7018d1785d2dba4da17b57864)) +- Allow builders to accept rest params and arrays (#7874) ([ad75be9](https://github.com/discordjs/discord.js/commit/ad75be9a9cf90c8624495df99b75177e6c24022f)) +- **MessageReaction:** Add react method (#7810) ([a328778](https://github.com/discordjs/discord.js/commit/a3287782b57c28b94c390c24e7d5f2d8c303301f)) +- **Collector:** Add `ignore` event (#7644) ([5244fe3](https://github.com/discordjs/discord.js/commit/5244fe3c1cd400985b00e95d8e5ec73823cf4f25)) +- **GuildMemberManager:** Add `GuildMemberManager#fetchMe()` (#7526) ([349766d](https://github.com/discordjs/discord.js/commit/349766dd6925e2d5e5597cc78c73e46f17c56eab)) +- **guildChannelManager:** Add `videoQualityMode` option for `create()` (#7980) ([cdd2ba0](https://github.com/discordjs/discord.js/commit/cdd2ba036ab1559783eb067786c52aff61807557)) +- **EnumResolvers:** Remove Enumresolvers (#7876) ([76694c1](https://github.com/discordjs/discord.js/commit/76694c1497de1b083a792fd1fda20f0eace50c48)) +- Move `me` to `GuildMemberManager` manager (#7669) ([aed687b](https://github.com/discordjs/discord.js/commit/aed687b09f87862eb2f33fb9f95b2cbd0b770585)) +- **rest:** Use undici (#7747) ([d1ec8c3](https://github.com/discordjs/discord.js/commit/d1ec8c37ffb7fe3b63eaa8c382f22ca1fb348c9b)) +- **VoiceChannel:** Add support for text in voice (#6921) ([4ba0f56](https://github.com/discordjs/discord.js/commit/4ba0f56b6af64bac30eea807fb3e9f3c41c3c83c)) +- **SelectMenu:** Allow emojis in options and option constructors (#7797) ([f22245e](https://github.com/discordjs/discord.js/commit/f22245e9d072ac4ef63b0ae0d84d5ba94608ce22)) +- Allow `createMessageComponentCollector` without using `fetchReply` (#7623) ([a58556a](https://github.com/discordjs/discord.js/commit/a58556adc02b2b9239c8f277a4387c743c9d6f04)) +- Add guild directory support (#6788) ([b01f414](https://github.com/discordjs/discord.js/commit/b01f4147d4f3bca021bc269c9f06463f06e3db53)) +- **GuildBanManager:** Support pagination results (#7734) ([fc2a8bb](https://github.com/discordjs/discord.js/commit/fc2a8bb6750919ecd6ee7c872df05f4b677ff5d3)) +- **CommandInteraction:** Add support for localized slash commands (#7684) ([01a423d](https://github.com/discordjs/discord.js/commit/01a423d110cfcddb3d794fcc32579a1547dd472d)) +- Allow emoji strings to be passed through constructors (#7718) ([0faac04](https://github.com/discordjs/discord.js/commit/0faac04b69f1dda3dc860cd584af100e36a40917)) +- **StageInstanceManager:** Add `sendStartNotification` option to create (#7730) ([29f8807](https://github.com/discordjs/discord.js/commit/29f88079559cc02ccfef7a7c16458d481e573fb5)) +- Add `makeURLSearchParams` utility function (#7744) ([8eaec11](https://github.com/discordjs/discord.js/commit/8eaec114a98026024c21545988860c123948c55d)) +- **modal:** Add `awaitModalSubmit` (#7751) ([3037fca](https://github.com/discordjs/discord.js/commit/3037fca196a0f9238d53bb51394daf737bbf3742)) +- **Actions:** Add parent structure to events parameters (#7577) ([3f3e432](https://github.com/discordjs/discord.js/commit/3f3e4327c86da86734c19a96e97115bd505b4532)) +- Export `UnsafeModalBuilder` and `UnsafeTextInputBuilder` (#7628) ([6fec252](https://github.com/discordjs/discord.js/commit/6fec25239dfed46a30826d38dc97f3680f24ec65)) +- **VoiceChannel:** Support `video_quality_mode` (#7722) ([3b3dabf](https://github.com/discordjs/discord.js/commit/3b3dabf3da2e2f24b81967d68b581d7f7452273f)) +- Add API v10 support (#7477) ([72577c4](https://github.com/discordjs/discord.js/commit/72577c4bfd02524a27afb6ff4aebba9301a690d3)) +- **embed:** Remove Embed.setColor (#7662) ([9b0d8cb](https://github.com/discordjs/discord.js/commit/9b0d8cb2d8f7b55753de584eb3a3f347f87596c2)) +- **StageInstance:** Add support for associated guild event (#7576) ([3dff31f](https://github.com/discordjs/discord.js/commit/3dff31f63fe4afdcc818193d737e1917f1ac8105)) +- **VoiceState:** Add edit method (#7569) ([b162f27](https://github.com/discordjs/discord.js/commit/b162f27e46524bfc64515969d753c6e8f30e6c40)) +- **ModalSubmitInteraction:** Add boolean properties (#7596) ([8907390](https://github.com/discordjs/discord.js/commit/89073903a253d9408839573502c72cae93fe70b6)) +- Add Modals and Text Inputs (#7023) ([ed92015](https://github.com/discordjs/discord.js/commit/ed920156344233241a21b0c0b99736a3a855c23c)) +- **discord.js:** Partial transition to undici (#7482) ([5158332](https://github.com/discordjs/discord.js/commit/51583320d3b0f6452cd96bad1021f2a57e4cc6f6)) +- **message:** Add `reason` on pin and unpin (#7520) ([00728f7](https://github.com/discordjs/discord.js/commit/00728f72b36123b607502624b4b02a02ee524d4a)) +- Re-export AuditLogEvent enum (#7528) ([6a2fa70](https://github.com/discordjs/discord.js/commit/6a2fa70b8e79a460be38916eeb605976ad6fe68b)) +- **options:** Add support for custom JSON transformers (#7476) ([dee27db](https://github.com/discordjs/discord.js/commit/dee27db35af379b0835f9fd5cc19563f7bf3dfc0)) +- Add CategoryChannelChildManager (#7320) ([5cf5071](https://github.com/discordjs/discord.js/commit/5cf5071061760c2f9c1e36d7648aef544b03323a)) + - **Co-authored-by:** Antonio Román <kyradiscord@gmail.com> +- Attachment application command option type (#7200) ([0034396](https://github.com/discordjs/discord.js/commit/003439671d359dcfe481446ef12b90bd71c57835)) +- **builders:** Add attachment command option type (#7203) ([ae0f35f](https://github.com/discordjs/discord.js/commit/ae0f35f51d68dfa5a7dc43d161ef9365171debdb)) +- **scheduledevents:** Add image option (#7436) ([fbc71ef](https://github.com/discordjs/discord.js/commit/fbc71ef6b668c4b1e2b065d9b65541d9303db0a0)) +- Add methods to managers (#7300) ([dd751ae](https://github.com/discordjs/discord.js/commit/dd751ae19da196cc2f90ccd35c7d8e99878daaf9)) +- **channel:** Add .url getter (#7402) ([f59d630](https://github.com/discordjs/discord.js/commit/f59d6305cb0cd0d154a909f18be76407c4d452d3)) +- **components:** Add unsafe message component builders (#7387) ([6b6222b](https://github.com/discordjs/discord.js/commit/6b6222bf513d1ee8cd98fba0ad313def560b864f)) +- **thread:** Add `newlyCreated` to `threadCreate` event (#7386) ([51beda5](https://github.com/discordjs/discord.js/commit/51beda56f74e44ed013b5d25044b8d5fd1978b29)) +- **channel:** Add isDMBased typeguard (#7362) ([388f535](https://github.com/discordjs/discord.js/commit/388f53550cca7ded7350a050fda03c36e4c1fdf7)) +- **`Interaction`:** Add `.commandType` property to `CommandInteraction` and `AutocompleteInteraction` (#7357) ([567db60](https://github.com/discordjs/discord.js/commit/567db60475c8704661b2e788c9905ef364d6c00c)) +- **scheduledevent:** Add support for event cover images (#7337) ([355f579](https://github.com/discordjs/discord.js/commit/355f579771771a28a293c327a38574c8918d18f8)) +- **enumResolvers:** Strengthen typings (#7344) ([9a566e8](https://github.com/discordjs/discord.js/commit/9a566e8068f28fce87c07861ef1d2877c6ae105f)) +- Allow setting message flags when sending (#7312) ([706db92](https://github.com/discordjs/discord.js/commit/706db9228a91ef42e49d2ec749eac153b9ef75d0)) +- **minor:** Add application_id to Webhook (#7317) ([5ccdb0a](https://github.com/discordjs/discord.js/commit/5ccdb0ab266e4f74c331386ac2d6dd32bc225c62)) +- **threadchannel:** Add `createdTimestamp` field (#7306) ([9a16234](https://github.com/discordjs/discord.js/commit/9a1623425ae2d69f5c16f0096af4951ff5096e80)) +- **GuildPreview:** Add stickers (#7152) ([cf25de9](https://github.com/discordjs/discord.js/commit/cf25de9373df98b3c1cd0ca0a092d9dc8172929d)) +- Enum resolvers & internal enum string removal (#7290) ([213acd7](https://github.com/discordjs/discord.js/commit/213acd799738b888d550cdf3f08906764f8288e0)) +- **guildemojimanager:** Add `delete` and `edit` methods (#7286) ([9181a31](https://github.com/discordjs/discord.js/commit/9181a31e0ba330502052c94da544bb15c8b66f11)) +- **interaction:** Add `isRepliable` type guard (#7259) ([da05a88](https://github.com/discordjs/discord.js/commit/da05a8856b11cc1bf0df424c88a1cf9573e5b654)) +- **Channel:** Improve typeguards (#6957) ([37a22e0](https://github.com/discordjs/discord.js/commit/37a22e04c27724c2a65b05c701e3000ba3653ba1)) +- Add Locales to Interactions (#7131) ([9052e32](https://github.com/discordjs/discord.js/commit/9052e321d1c9c8841962d4e8dc5d9e060b104438)) +- **Permissions:** Remove deprecated thread-related permissions (#6755) ([ab3ff5a](https://github.com/discordjs/discord.js/commit/ab3ff5a262caf7d6225b8d6b54ab2c6b6613c0d0)) +- **VoiceRegion:** Remove the unsent vip field (#6759) ([caaef53](https://github.com/discordjs/discord.js/commit/caaef53dd97ecac9f714072ddba5ae9a99ab1027)) +- **richpresenceassets:** Add YouTube and custom image support (#7184) ([d06d70c](https://github.com/discordjs/discord.js/commit/d06d70ccf26c04c1122fac8430922588a489f95e)) +- **Collector:** Yield all collected values (#7073) ([2b480cb](https://github.com/discordjs/discord.js/commit/2b480cb14e6f52855efcb372da7fb455c15b13b1)) + +## Refactor + +- **Util:** Rename `fetchRecommendedShards` (#8298) ([cafde77](https://github.com/discordjs/discord.js/commit/cafde77d73452d729ba8e2cb1cac3f14235b889b)) +- **Embed:** Add all the types (#8254) ([64f8140](https://github.com/discordjs/discord.js/commit/64f814066cc4adebaca47eb8d7a2040a8df399ae)) +- **rest:** Add content-type(s) to uploads (#8290) ([103a358](https://github.com/discordjs/discord.js/commit/103a3584c95a7b7f57fa62d47b86520d5ec32303)) +- Make `GuildAuditLogsEntry.action` return an `AuditLogEvent` (#8256) ([f0b68d5](https://github.com/discordjs/discord.js/commit/f0b68d57368d7ac3db97925df68c11a945ccd84c)) +- **builder:** Remove `unsafe*Builder`s (#8074) ([a4d1862](https://github.com/discordjs/discord.js/commit/a4d18629828234f43f03d1bd4851d4b727c6903b)) +- Make `ShardEvents` the events of `Shard` (#8185) ([c5750d5](https://github.com/discordjs/discord.js/commit/c5750d59f529ab48a5bc88a73a1c449ef6ddbffd)) +- **Util:** Make single `replace` call in `cleanContent` (#8210) ([6b20645](https://github.com/discordjs/discord.js/commit/6b206457400ce31d566b02a0c135042afb540853)) +- **ApplicationCommandManager:** Use `makeURLSearchParams` (#8196) ([cb3dca4](https://github.com/discordjs/discord.js/commit/cb3dca4ae029724421f3d04a784ace0ae2de75e2)) +- Use `Base` prefix for channel and interaction base classes (#8099) ([e24970e](https://github.com/discordjs/discord.js/commit/e24970e3c3d24f71ba711e59666cd8a49a33e33b)) +- **Constants:** Remove leftover code (#8156) ([cd17aad](https://github.com/discordjs/discord.js/commit/cd17aad720430d23af51c364caeb8b22bf6cb6b5)) +- Errors (#8068) ([e68effa](https://github.com/discordjs/discord.js/commit/e68effa822f064a324ed5b92e797c9fc3ce5e211)) +- **ClientOptions:** Remove `$` prefix from `ws.properties` keys (#8094) ([90a98fe](https://github.com/discordjs/discord.js/commit/90a98fee16b7d1d06768461f4e85127c0edf8419)) +- Use `GuildFeature` enum (#8101) ([e5ec1c4](https://github.com/discordjs/discord.js/commit/e5ec1c4dbc3fa54b2c43d1fec24932d7363e17cb)) +- **util:** Make utility functions top level (#8052) ([e53d162](https://github.com/discordjs/discord.js/commit/e53d1621986035b0c92a1782f6e013d408480e00)) +- **ApplicationCommand:** Permissions v2 (#7857) ([c7391db](https://github.com/discordjs/discord.js/commit/c7391db11b3efd4b1a6904affb26887ad06d6db4)) +- ***:** Include name/reason/etc fields into options/data params (#8026) ([9c8b310](https://github.com/discordjs/discord.js/commit/9c8b3102ce00d1f2c1255c150fb3030f8b6dd026)) +- **ThreadMemberManager:** Consistent thread member fetching (#8021) ([da9107c](https://github.com/discordjs/discord.js/commit/da9107c007536952107bd92943b6c714538d5aeb)) +- **interactions:** Remove redundant interaction typeguards (#8027) ([f57d676](https://github.com/discordjs/discord.js/commit/f57d6768ad24f6e37dc598f9c93709449d3bc4dd)) +- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a)) +- **channel:** Remove redundant channel type guards (#8012) ([70c733b](https://github.com/discordjs/discord.js/commit/70c733bb9a5bde0f79e6bea0bdc416458bda4c06)) +- Always return `Message` instances in interactions (#7917) ([9720e55](https://github.com/discordjs/discord.js/commit/9720e555340431c3b3ad7bd670ad0ac7eee8865f)) +- **attachment:** Don't return attachment builders from API (#7852) ([dfadcbc](https://github.com/discordjs/discord.js/commit/dfadcbc2fd50be64c8a0c1cae3be10f83678c5ee)) +- Clean up modal submissions (#7994) ([643dab3](https://github.com/discordjs/discord.js/commit/643dab3b1b5305d002fcefed62755bbe11fc3267)) +- **ThreadChannel:** Remove `MAX` helper from threads (#7846) ([dfd9eb2](https://github.com/discordjs/discord.js/commit/dfd9eb20b2d3e0e7db26744b1f15134ac6eda139)) +- **Activity:** Remove undocumented properties (#7844) ([5ba7740](https://github.com/discordjs/discord.js/commit/5ba7740fcfefda1eeba81ace4e6351eac02522a4)) +- **MessageAttachment:** Use `Attachment` instead (#7691) ([ab4c608](https://github.com/discordjs/discord.js/commit/ab4c608b97ff319935e1a7f23564622bfd7ddd57)) +- **Util:** Remove splitting (#7780) ([54e5629](https://github.com/discordjs/discord.js/commit/54e56299865a6746744544ba25d5540a1166d27c)) +- Tidy up builders and components (#7711) ([96a0d83](https://github.com/discordjs/discord.js/commit/96a0d83a1366703ecae40b5e0d5171be9123d079)) +- Remove nickname parsing (#7736) ([78a3afc](https://github.com/discordjs/discord.js/commit/78a3afcd7fdac358e06764cc0d675e1215c785f3)) +- Remove store channels (#7634) ([aedddb8](https://github.com/discordjs/discord.js/commit/aedddb875e740e1f1bd77f06ce1b361fd3b7bc36)) +- **IntegrationApplication:** Remove `summary` (#7729) ([eb6b472](https://github.com/discordjs/discord.js/commit/eb6b472f72488cad7e96befccc00270cf6dc01b8)) +- **GuildAuditLogs:** Remove build (#7704) ([cedd053](https://github.com/discordjs/discord.js/commit/cedd0536baa1301984daf89dfda4e63a7be595a2)) +- **InteractionCollector:** Simplify constructor logic (#7667) ([07b23a9](https://github.com/discordjs/discord.js/commit/07b23a99c7088a7c740f23051f3f755f091519b0)) +- Remove undocumented checks (#7637) ([9a6e691](https://github.com/discordjs/discord.js/commit/9a6e691eaa6c3d133098b2734414590cb838de2e)) +- Allow builders to accept emoji strings (#7616) ([fb9a9c2](https://github.com/discordjs/discord.js/commit/fb9a9c221121ee1c7986f9c775b77b9691a0ae15)) +- Use `static` fields (#7701) ([e805777](https://github.com/discordjs/discord.js/commit/e805777a7a81d1dc7a2edd9741ecb04e685a3886)) +- **EmbedBuilder:** Allow hex strings in setColor (#7673) ([f472975](https://github.com/discordjs/discord.js/commit/f4729759f600372455f062c75859f084e23a5d78)) +- Don't return builders from API data (#7584) ([549716e](https://github.com/discordjs/discord.js/commit/549716e4fcec89ca81216a6d22aa8e623175e37a)) +- **embed:** Allow hex strings in `setColor()` (#7593) ([79d6c04](https://github.com/discordjs/discord.js/commit/79d6c0489c3d563fdd05de63c4fcf93a6deefce1)) +- **InteractionResponses:** Use ClientOptions.jsonTransformer (#7599) ([fac55bc](https://github.com/discordjs/discord.js/commit/fac55bcfd1e8b76aae1273415f74fa6de7aca66d)) +- Deprecate invite stage instance (#7437) ([d2bc9d4](https://github.com/discordjs/discord.js/commit/d2bc9d444f42a70a3c4cc4c68eb107bcaebec509)) +- **guild:** Move `premiumSubscriptionCount` to `AnonymousGuild` (#7451) ([6d3da22](https://github.com/discordjs/discord.js/commit/6d3da226d3c003d137639e719394a807330e4844)) +- **actions:** Use optional chaining (#7460) ([d1bb362](https://github.com/discordjs/discord.js/commit/d1bb36256f2f86022884e6ee9e05b0536cb6384d)) +- **guildbanmanager:** Rename days option to deleteMessageDays (#7447) ([0dfdb2c](https://github.com/discordjs/discord.js/commit/0dfdb2cf11e236e67dd34277108973b5b79790a8)) +- Make public builder props getters (#7422) ([e8252ed](https://github.com/discordjs/discord.js/commit/e8252ed3b981a4b7e4013f12efadd2f5d9318d3e)) +- Remove redundant API defaults (#7449) ([532846b](https://github.com/discordjs/discord.js/commit/532846b1f8260d85022a022d093553310052afc9)) +- Allow discord.js builders to accept camelCase (#7424) ([94bf727](https://github.com/discordjs/discord.js/commit/94bf727cc3a2f11c88e95cdb151b235f775cd1ca)) +- Replace `WSCodes`, `WSEvents`, and `InviteScopes` with `discord-api-types` equivalent (#7409) ([cc25455](https://github.com/discordjs/discord.js/commit/cc25455d2c75177e3eddc880b7fd53cb122387c4)) +- Make constants enums top level and `PascalCase` (#7379) ([d8184f9](https://github.com/discordjs/discord.js/commit/d8184f94dd08daab37195f52828e06af5ed1c1e0)) +- **`Bitfield`:** Use discord-api-types enums instead (#7313) ([fbb1d03](https://github.com/discordjs/discord.js/commit/fbb1d0328bcd517027ad2eedb8753d17489ed851)) +- Use `@discordjs/rest` (#7298) ([ec0fba1](https://github.com/discordjs/discord.js/commit/ec0fba1ed0d3c5b1bb18171ece6fe5ee42d48497)) +- Switch to /builders `Embed` (#7067) ([d2d3a80](https://github.com/discordjs/discord.js/commit/d2d3a80c556a104099a1ddb1b24f1b921c553257)) +- Remove transformPermissions (#7303) ([b4ed8fd](https://github.com/discordjs/discord.js/commit/b4ed8fd3ed953085cd908b2845d4384c8555d3a2)) +- Remove VoiceChannel#editable (#7291) ([164589c](https://github.com/discordjs/discord.js/commit/164589c5516a847457444d11098981d557b6778b)) +- Remove boolean option for `Webhook#fetchMessage` (#7293) ([347ff80](https://github.com/discordjs/discord.js/commit/347ff80bbc9bc5243b7f68ba5d745782eadeba21)) +- **subcommandgroup:** Required default to false (#7217) ([6112767](https://github.com/discordjs/discord.js/commit/6112767128a664f32205425f52ba52220d57834f)) +- **invite:** Make `channel` and `inviter` getters (#7278) ([18b0ed4](https://github.com/discordjs/discord.js/commit/18b0ed4cbe8285637a971c7c99ee49d18060a403)) +- Remove required from getMember (#7188) ([c90e47f](https://github.com/discordjs/discord.js/commit/c90e47f90403e5b1b3499b213dcdf2704fd96b66)) +- Remove djs components and use /builders components instead (#7252) ([101d7c5](https://github.com/discordjs/discord.js/commit/101d7c5ffa03edcf8cb8a0647b77d5c9a38e4bdd)) +- Default *URL methods to animated hash (#7149) ([7c07976](https://github.com/discordjs/discord.js/commit/7c07976018728154be0ce0314d3e8dfe8eb9ed5b)) +- Use setPosition inside edit (#7263) ([0b23b7f](https://github.com/discordjs/discord.js/commit/0b23b7f0394a20596c8d85b82870c3f35ea6b0e0)) +- Don't disable import order lint (#7262) ([0a5d5f3](https://github.com/discordjs/discord.js/commit/0a5d5f38c0b1a249fa2efe16f3b601c90622a4d5)) +- Remove discord.js enums and use discord-api-types enums instead (#7077) ([aa6d1c7](https://github.com/discordjs/discord.js/commit/aa6d1c74de01dd9a8f020c43fb2c193c4729df8d)) +- **application:** Remove fetchAssets (#7250) ([1479e40](https://github.com/discordjs/discord.js/commit/1479e40bcecc4c28ecb9f05fa4fbbdfe3bd387e1)) +- PresenceUpdate and demuxProbe (#7248) ([1745973](https://github.com/discordjs/discord.js/commit/174597302408f13c5bb685e2fb02ae2137cb481d)) +- **embeds:** Don't create new embed instances when unnecessary (#7227) ([822dc67](https://github.com/discordjs/discord.js/commit/822dc678da626de7b4fb22a747cd3cd2e8376732)) +- **GuildMember:** Throw better errors on #kickable and #bannable (#7137) ([4fd127e](https://github.com/discordjs/discord.js/commit/4fd127e79edfa1851f8a10242838f9d7aa68c8c3)) +- **SnowflakeUtil:** Switch to `@sapphire/snowflake` (#7079) ([e082dfb](https://github.com/discordjs/discord.js/commit/e082dfb1584926e4c05face5966d16e4a2921bc5)) +- **InteractionCreate:** Remove interaction event (#6326) ([ae876d9](https://github.com/discordjs/discord.js/commit/ae876d962453ccf843f8e6f70666a98a3173bb75)) +- **MessageCreate:** Remove message event (#6324) ([171e917](https://github.com/discordjs/discord.js/commit/171e917fb96b6bf39a6ad70e83be646f72fe451e)) +- **integration:** Turn undefined into null and consistency (#7209) ([13eb782](https://github.com/discordjs/discord.js/commit/13eb78256da901e6c3c405f546f36617ef5e8239)) +- Remove `deleted` field (#7092) ([cee7fd1](https://github.com/discordjs/discord.js/commit/cee7fd181c464e44eabf20b511d12589f2453722)) +- **Dates:** Save timestamps everywhere and use Date.parse (#7108) ([55e21f5](https://github.com/discordjs/discord.js/commit/55e21f53663a91863c63b6d9f3a8c35564664061)) +- **RoleManager:** Remove `comparePositions()` (#7201) ([fbbac27](https://github.com/discordjs/discord.js/commit/fbbac279789427b2c36869dc47b65fb08431e14d)) +- Better Command Terminology (#7197) ([b7856e7](https://github.com/discordjs/discord.js/commit/b7856e7809ff6fa21fe00286f885808535624f7c)) +- **Actions:** Remove deleted maps (#7076) ([5022b14](https://github.com/discordjs/discord.js/commit/5022b14da09e9b421f947e9bc385a0574cbf07d1)) +- **Client:** Remove applicationCommand events (#6492) ([6085b4f](https://github.com/discordjs/discord.js/commit/6085b4f72723d4ff82f7fea504241d14c94af21e)) +- Remove `Util.removeMentions()` (#6530) ([0c24cc8](https://github.com/discordjs/discord.js/commit/0c24cc8ec0d818315cc8f8bcf74fce060847ac79)) +- **Constants:** Change APPLICATION_COMMAND -> CHAT_INPUT_COMMAND (#7018) ([75616a3](https://github.com/discordjs/discord.js/commit/75616a305f9af33013486b13a872a39212101ce7)) +- **Guild:** Remove deprecated setXPositions methods (#6897) ([43e5e3c](https://github.com/discordjs/discord.js/commit/43e5e3c339a96fa895267d4538eee1d5e5843d05)) +- **UserFlags:** Update flag names (#6938) ([b246fc4](https://github.com/discordjs/discord.js/commit/b246fc4101b8e4957ffd1af8e2e4986a020ca211)) + +## Styling + +- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629)) + +## Typings + +- **GuildFeature:** Allow feature strings to be passed (#8264) ([b7d4e55](https://github.com/discordjs/discord.js/commit/b7d4e55419207d4e25f5c40cab221c7c04a617bf)) +- **CategoryChannelChildManager:** Fix Holds type (#8288) ([33a7a5c](https://github.com/discordjs/discord.js/commit/33a7a5cbdc00d2a5034dc1ec91fec5da7042f9d0)) +- Remove `MemberMention` (#8292) ([bf65b37](https://github.com/discordjs/discord.js/commit/bf65b37d1a9ea8417e26ad4afacea1eb45a0ff5a)) +- **GuildMemberManager:** Fix placement for `fetchMe()` (#8258) ([7525615](https://github.com/discordjs/discord.js/commit/75256153a9923d94ca709a37aaccc48dfb43c153)) +- Convert `Events` to an enum (#8246) ([feb3bdd](https://github.com/discordjs/discord.js/commit/feb3bdda0a3c3da80378c8cbcafca2968551eef9)) +- **GuildMemberManager:** Non-void return of `edit()` (#8186) ([c7a205f](https://github.com/discordjs/discord.js/commit/c7a205f7b992eea43af13a4638e2a03db7bc0d8a)) +- Add missing shard types (#8180) ([27d8deb](https://github.com/discordjs/discord.js/commit/27d8deb4716a87704370a95103b16fa1b763de18)) +- Implement `GuildChannelEditOptions` (#8184) ([b83e0c0](https://github.com/discordjs/discord.js/commit/b83e0c0caffc2b767aa1ba4412580970a6901899)) +- **Status:** Add missing members (#8179) ([8421f92](https://github.com/discordjs/discord.js/commit/8421f9203bd2d85ef8e64c3fb9a991c74223a75d)) +- **GuildScheduledEvent#scheduledStartAt:** Should be nullish (#8111) ([65dc8d6](https://github.com/discordjs/discord.js/commit/65dc8d677ee81469c0eeb4ecdd83fe2f68cc8982)) +- Fix modal builder constructor data type (#8143) ([7279f9c](https://github.com/discordjs/discord.js/commit/7279f9c31b14bc1e78c63b7298e80e37ca5dfe0c)) +- Use `ThreadAutoArchiveDuration` from discord-api-types (#8145) ([a3799f9](https://github.com/discordjs/discord.js/commit/a3799f9ebb027904830457119708d550e2009200)) +- **Shard#reconnecting:** Fix event name (#8118) ([95e6d6e](https://github.com/discordjs/discord.js/commit/95e6d6ede03c4fb92a8d8027a085e84b043fd895)) +- **ApplicationCommand:** Fix typo in setDMPermission (#8097) ([4df491c](https://github.com/discordjs/discord.js/commit/4df491ce8578a1b01ee8412a4df8137a302e7202)) +- Fix `setType()` parameter and `ChannelData.type` (#8089) ([b4e28a8](https://github.com/discordjs/discord.js/commit/b4e28a8ff6bf165c54a8726d3bc3a3cc0c1e469b)) +- Fix `ApplicationCommandPermissionsUpdate` event typings (#8071) ([9964454](https://github.com/discordjs/discord.js/commit/9964454c2944a0523399481a5f609144486e549b)) +- **AutocompleteOption:** Fix and improve types (#8069) ([476b7d5](https://github.com/discordjs/discord.js/commit/476b7d519c719152ea04e207f6dd09bb23e733db)) +- **ThreadMemberManager:** Fix return type of fetching members with no arguments (#8060) ([2392a6f](https://github.com/discordjs/discord.js/commit/2392a6f5de2efcf6b326173d26295c928b94adb6)) +- Remove isAutocomplete typeguard from typings (#8063) ([c0f079d](https://github.com/discordjs/discord.js/commit/c0f079d2325a636c83ac676c525bfa89ce308b3c)) +- **AttachmentBuilder:** Fix data type (#8016) ([7fa698d](https://github.com/discordjs/discord.js/commit/7fa698d23e548987762c4c66c96c510d9ea56eb4)) +- **modal:** Fix `showModal()` typings (#8014) ([0ccc243](https://github.com/discordjs/discord.js/commit/0ccc243c8ffbf852660c899cc2ad47bd5ebb65cb)) +- Fix some attachment related typings (#8013) ([6aa6232](https://github.com/discordjs/discord.js/commit/6aa623240ee94b117c7e69c1d09b50923a8f7a4c)) +- **AttachmentBuilder:** Remove name parameter from constructor (#8008) ([6266b0c](https://github.com/discordjs/discord.js/commit/6266b0c1e323f9522010f90f34ce6f17fcb6e769)) +- Add types to `EventEmitter` static methods (#7986) ([d60c464](https://github.com/discordjs/discord.js/commit/d60c464e618e4159d2656e7832798909832f33cd)) +- Nullify `guildScheduledEventUpdate`'s old parameter (#7955) ([fdeac9d](https://github.com/discordjs/discord.js/commit/fdeac9d9fba06c532eca296ddd8479047bc732bf)) +- Make `CacheType` generic more accurate for return values (#7868) ([e07b910](https://github.com/discordjs/discord.js/commit/e07b910e684bc3cf71fb93417951ad42351bace4)) +- **guildScheduledEvent:** Mark `entityMetadata` as nullable (#7908) ([64bdf53](https://github.com/discordjs/discord.js/commit/64bdf53116945ffb51764bb8ec539d530aefcfb1)) +- **discord.js:** Export missing enums (#7864) ([5eeef3f](https://github.com/discordjs/discord.js/commit/5eeef3f708eb900ec994d837fb4cd414a4f4b437)) +- Fix return type of `toString()` on channels (#7836) ([ece6289](https://github.com/discordjs/discord.js/commit/ece628986c7eb1a66f46076d8f8518c9ff00aaf3)) +- **Message#activity:** Make `partyId` optional and use enum for `type` (#7845) ([bfeaf85](https://github.com/discordjs/discord.js/commit/bfeaf856f76eb7cb756ac55aac13636ccdb345b6)) +- Cleanup *Data type definitions (#7716) ([585169f](https://github.com/discordjs/discord.js/commit/585169f2f097ffb1940d17f549e4290aa55acde2)) +- Fix BooleanCache never resolving to true (#7809) ([440ac24](https://github.com/discordjs/discord.js/commit/440ac243ca1d6f8cd04603e63e3f2f6ea1722ee8)) +- **CommandInteraction:** Add awaitModalSubmit (#7811) ([a6d9ce5](https://github.com/discordjs/discord.js/commit/a6d9ce57c6cae90d0afc60010cad44fdc2c2d06c)) +- **ThreadChannel:** Fix autoArchiveDuration types (#7816) ([0857476](https://github.com/discordjs/discord.js/commit/08574763eb665b5a43ccfb826929f1e3f0d1c3a7)) +- Add missing typing (#7781) ([f094e33](https://github.com/discordjs/discord.js/commit/f094e338617a1a3c9f48a325e4b8e9b5a405aa91)) +- **VoiceChannel:** Nullify property (#7793) ([446eb39](https://github.com/discordjs/discord.js/commit/446eb390ce58b7e7f60e297b25f53773a55f7fb9)) +- **ModalSubmitInteraction:** Message (#7705) ([b577bcc](https://github.com/discordjs/discord.js/commit/b577bcc1df5c6424fef9984e19a5f11c77371cf3)) +- **Embed:** Add missing getters and add video to EmbedData (#7728) ([fd1dc72](https://github.com/discordjs/discord.js/commit/fd1dc72c0a77dbe18753d8db22972dfa5fe4ab36)) +- **ModalSubmitInteraction:** Fix `components` type (#7732) ([6f4e97b](https://github.com/discordjs/discord.js/commit/6f4e97bfafe4a058f6ec85d321676401d701ee55)) +- **interactionCollector:** Filter should have a collected argument (#7753) ([e4f2705](https://github.com/discordjs/discord.js/commit/e4f27051ca921d299c302b600a8c2917e9356ef6)) +- Fix regressions (#7649) ([5748dbe](https://github.com/discordjs/discord.js/commit/5748dbe08783beb80c526de38ccd105eb0e82664)) +- **Constants:** Add `NonSystemMessageTypes` (#7678) ([9afc030](https://github.com/discordjs/discord.js/commit/9afc03054e4c8973702d6c18e618643f76382dd9)) +- Fix auto archive duration type (#7688) ([8e3b2d7](https://github.com/discordjs/discord.js/commit/8e3b2d7abd38136534969cf77c6a748ee3a20355)) +- **InteractionResponseFields:** Add webhook (#7597) ([daf2829](https://github.com/discordjs/discord.js/commit/daf2829cb58d1a44cb1f1ece21e428d1a23e99c9)) +- **Embed:** Add forgotten `footer` type (#7665) ([8fb9816](https://github.com/discordjs/discord.js/commit/8fb98165a9d098ab316475d6baacb015783eb638)) +- **ColorResolvable:** Simplify string types (#7643) ([2297c2b](https://github.com/discordjs/discord.js/commit/2297c2b9479ace16f5f7155479605a4ac2718e3d)) +- Allow component classes in action row data (#7614) ([230c0c4](https://github.com/discordjs/discord.js/commit/230c0c4cb137882ff7bab783a4aeaa83ae941de5)) +- **ActionRow:** Allow components to be passed to constructors (#7531) ([e71c76c](https://github.com/discordjs/discord.js/commit/e71c76c7f795837dbcc3576e507bd286640b4296)) +- **showModal:** Align types with the documentation (#7600) ([0d7e4ed](https://github.com/discordjs/discord.js/commit/0d7e4edd969513692c061c107be4bbe7e4b54321)) +- Modals type and doc fixes (#7608) ([93854a8](https://github.com/discordjs/discord.js/commit/93854a8013d07234cb849bfcbfa99f74a4c3cdb4)) +- **InteractionResponseFields:** Add boolean properties (#7565) ([53defb8](https://github.com/discordjs/discord.js/commit/53defb82e36108468e35077b887ee28b811891ab)) +- Allow raw components for reply and message options (#7573) ([2d4971b](https://github.com/discordjs/discord.js/commit/2d4971b032a01c05b55c93d6475e61b0d25d69d3)) +- Fix component *Data types (#7536) ([a8321d8](https://github.com/discordjs/discord.js/commit/a8321d8026df2e6a09d867939986bf77f894f3a8)) +- Use discord-api-types `Locale` (#7541) ([8346003](https://github.com/discordjs/discord.js/commit/83460037be840ba623f3b02a3e6f218943f9d2b7)) +- **anychannel:** Add PartialGroupDMChannel (#7472) ([cf66930](https://github.com/discordjs/discord.js/commit/cf669301c7be8eaecf91d7f764eccc67d7a5b4c6)) +- Remove `ApplicationCommandInteractionOptionResolver` (#7491) ([71f4fa8](https://github.com/discordjs/discord.js/commit/71f4fa82ed6206d6843345a5394119f2a728aa35)) +- **embed:** Fix timestamp allowed types (#7470) ([7959a68](https://github.com/discordjs/discord.js/commit/7959a68d8ec600af248f5506f39871cae7eeeb04)) +- Remove duplicate rate limit for thread creation (#7465) ([2d2de1d](https://github.com/discordjs/discord.js/commit/2d2de1d3fd15a098d69e09710e9a7a3352234fef)) +- Correct types for InteractionCollector guild and channel (#7452) ([6ce906a](https://github.com/discordjs/discord.js/commit/6ce906a02fcb051cb6df3e9f453ba9f53db03bd0)) +- Fix `GuildAuditLogsTypes` keys & typos (#7423) ([3d8c776](https://github.com/discordjs/discord.js/commit/3d8c77600be51a86a99b526078bb1b1fcb9a0811)) +- Remove duplicate `GuildChannelOverwriteOptions` interface (#7428) ([83458ff](https://github.com/discordjs/discord.js/commit/83458ff7c782b8efdaaac931d2dee1764dad25bf)) +- Use `GuildFeature` enum from `discord-api-types` (#7397) ([a7b80b9](https://github.com/discordjs/discord.js/commit/a7b80b9d9bf4902bd85b592986771eadf7a765dc)) +- Fix *BitField.Flags properties (#7363) ([e6a26d2](https://github.com/discordjs/discord.js/commit/e6a26d25b3cf8dfcc8aa8997b021f1774f3b754b)) +- Fix MessageMentions channel types (#7316) ([c05b388](https://github.com/discordjs/discord.js/commit/c05b38873bb3c37c6e4ebcb6b6373a8858cc03de)) +- Fix channel create overloads (#7294) ([1c6c944](https://github.com/discordjs/discord.js/commit/1c6c9449ad68601c6c98748d73be8114401d38ef)) +- Fix regressions and inconsistencies (#7260) ([26a9dc3](https://github.com/discordjs/discord.js/commit/26a9dc32062cd071917bbe7264050315b4d6dd3c)) +- **interaction:** Remove renamed typeguards (#7220) ([68b9564](https://github.com/discordjs/discord.js/commit/68b9564f1821726377a1e929a3ca1fc65b4ad598)) +- AssertType -> expectType ([3f36746](https://github.com/discordjs/discord.js/commit/3f36746561a40cd61a7cd2e054b7ef80d58fc707)) +- Fix cache types resolving to `never` (#7164) ([c978dbb](https://github.com/discordjs/discord.js/commit/c978dbb6233bcd85408caf0bca7619c9c5d508f0)) diff --git a/node_modules/discord.js/LICENSE b/node_modules/discord.js/LICENSE new file mode 100644 index 0000000..d21f37a --- /dev/null +++ b/node_modules/discord.js/LICENSE @@ -0,0 +1,191 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2021 Noel Buechler + Copyright 2015 Amish Shah + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/node_modules/discord.js/README.md b/node_modules/discord.js/README.md new file mode 100644 index 0000000..377d40c --- /dev/null +++ b/node_modules/discord.js/README.md @@ -0,0 +1,142 @@ +<div align="center"> + <br /> + <p> + <a href="https://discord.js.org"><img src="https://discord.js.org/static/logo.svg" width="546" alt="discord.js" /></a> + </p> + <br /> + <p> + <a href="https://discord.gg/djs"><img src="https://img.shields.io/discord/222078108977594368?color=5865F2&logo=discord&logoColor=white" alt="Discord server" /></a> + <a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/v/discord.js.svg?maxAge=3600" alt="npm version" /></a> + <a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/dt/discord.js.svg?maxAge=3600" alt="npm downloads" /></a> + <a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Tests status" /></a> + <a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2" alt="Code coverage" /></a> + </p> + <p> + <a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a> + <a href="https://www.cloudflare.com"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png" alt="Cloudflare Workers" height="44" /></a> + </p> +</div> + +## About + +discord.js is a powerful [Node.js](https://nodejs.org) module that allows you to easily interact with the +[Discord API](https://discord.com/developers/docs/intro). + +- Object-oriented +- Predictable abstractions +- Performant +- 100% coverage of the Discord API + +## Installation + +**Node.js 16.11.0 or newer is required.** + +```sh +npm install discord.js +yarn add discord.js +pnpm add discord.js +``` + +### Optional packages + +- [zlib-sync](https://www.npmjs.com/package/zlib-sync) for WebSocket data compression and inflation (`npm install zlib-sync`) +- [bufferutil](https://www.npmjs.com/package/bufferutil) for a much faster WebSocket connection (`npm install bufferutil`) +- [utf-8-validate](https://www.npmjs.com/package/utf-8-validate) in combination with `bufferutil` for much faster WebSocket processing (`npm install utf-8-validate`) +- [@discordjs/voice](https://www.npmjs.com/package/@discordjs/voice) for interacting with the Discord Voice API (`npm install @discordjs/voice`) + +## Example usage + +Install discord.js: + +```sh +npm install discord.js +yarn add discord.js +pnpm add discord.js +``` + +Register a slash command against the Discord API: + +```js +import { REST, Routes } from 'discord.js'; + +const commands = [ + { + name: 'ping', + description: 'Replies with Pong!', + }, +]; + +const rest = new REST({ version: '10' }).setToken(TOKEN); + +try { + console.log('Started refreshing application (/) commands.'); + + await rest.put(Routes.applicationCommands(CLIENT_ID), { body: commands }); + + console.log('Successfully reloaded application (/) commands.'); +} catch (error) { + console.error(error); +} +``` + +Afterwards we can create a quite simple example bot: + +```js +import { Client, GatewayIntentBits } from 'discord.js'; +const client = new Client({ intents: [GatewayIntentBits.Guilds] }); + +client.on('ready', () => { + console.log(`Logged in as ${client.user.tag}!`); +}); + +client.on('interactionCreate', async interaction => { + if (!interaction.isChatInputCommand()) return; + + if (interaction.commandName === 'ping') { + await interaction.reply('Pong!'); + } +}); + +client.login(TOKEN); +``` + +## Links + +- [Website][website] ([source][website-source]) +- [Documentation][documentation] +- [Guide][guide] ([source][guide-source]) + Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library. +- [discord.js Discord server][discord] +- [Discord API Discord server][discord-api] +- [GitHub][source] +- [npm][npm] +- [Related libraries][related-libs] + +### Extensions + +- [RPC][rpc] ([source][rpc-source]) + +## Contributing + +Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the +[documentation][documentation]. +See [the contribution guide][contributing] if you'd like to submit a PR. + +## Help + +If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord]. + +[website]: https://discord.js.org +[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website +[documentation]: https://discord.js.org/docs/packages/discord.js/stable +[guide]: https://discordjs.guide/ +[guide-source]: https://github.com/discordjs/guide +[guide-update]: https://discordjs.guide/additional-info/changes-in-v14.html +[discord]: https://discord.gg/djs +[discord-api]: https://discord.gg/discord-api +[source]: https://github.com/discordjs/discord.js/tree/main/packages/discord.js +[npm]: https://www.npmjs.com/package/discord.js +[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries +[rpc]: https://www.npmjs.com/package/discord-rpc +[rpc-source]: https://github.com/discordjs/RPC +[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md diff --git a/node_modules/discord.js/package.json b/node_modules/discord.js/package.json new file mode 100644 index 0000000..c2ddab1 --- /dev/null +++ b/node_modules/discord.js/package.json @@ -0,0 +1,85 @@ +{ + "name": "discord.js", + "version": "14.13.0", + "description": "A powerful library for interacting with the Discord API", + "scripts": { + "test": "yarn docs:test && yarn test:typescript", + "test:typescript": "tsc --noEmit && tsd", + "lint": "prettier --check . && tslint typings/index.d.ts && eslint src --format=pretty", + "format": "prettier --write . && eslint src --fix --format=pretty", + "fmt": "yarn format", + "docs": "docgen -i './src/*.js' './src/**/*.js' -c ./docs/index.json -r ../../ -o ./docs/docs.json", + "docs:test": "docgen -i './src/*.js' './src/**/*.js' -c ./docs/index.json -r ../../", + "prepack": "yarn lint && yarn test", + "changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/discord.js/*'", + "release": "cliff-jumper" + }, + "main": "./src/index.js", + "types": "./typings/index.d.ts", + "directories": { + "lib": "src", + "test": "test" + }, + "files": [ + "src", + "typings" + ], + "contributors": [ + "Crawl <icrawltogo@gmail.com>", + "Amish Shah <amishshah.2k@gmail.com>", + "Vlad Frangu <kingdgrizzle@gmail.com>", + "SpaceEEC <spaceeec@yahoo.com>", + "Aura Román <kyradiscord@gmail.com>" + ], + "license": "Apache-2.0", + "keywords": [ + "discord", + "api", + "bot", + "client", + "node", + "discordapp" + ], + "repository": { + "type": "git", + "url": "https://github.com/discordjs/discord.js.git", + "directory": "packages/discord.js" + }, + "bugs": { + "url": "https://github.com/discordjs/discord.js/issues" + }, + "homepage": "https://discord.js.org", + "dependencies": { + "@discordjs/builders": "^1.6.5", + "@discordjs/collection": "^1.5.3", + "@discordjs/formatters": "^0.3.2", + "@discordjs/rest": "^2.0.1", + "@discordjs/util": "^1.0.1", + "@discordjs/ws": "^1.0.1", + "@sapphire/snowflake": "^3.5.1", + "@types/ws": "^8.5.5", + "discord-api-types": "0.37.50", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.6.1", + "undici": "5.22.1", + "ws": "^8.13.0" + }, + "devDependencies": { + "@discordjs/docgen": "^0.12.1", + "@favware/cliff-jumper": "^2.1.1", + "@types/node": "16.18.40", + "dtslint": "^4.2.1", + "eslint": "^8.47.0", + "eslint-formatter-pretty": "^5.0.0", + "jest": "^29.6.2", + "prettier": "^2.8.8", + "tsd": "^0.28.1", + "tslint": "^6.1.3", + "turbo": "^1.10.12", + "typescript": "^5.1.6" + }, + "engines": { + "node": ">=16.11.0" + } +}
\ No newline at end of file diff --git a/node_modules/discord.js/src/client/BaseClient.js b/node_modules/discord.js/src/client/BaseClient.js new file mode 100644 index 0000000..631748c --- /dev/null +++ b/node_modules/discord.js/src/client/BaseClient.js @@ -0,0 +1,83 @@ +'use strict'; + +const EventEmitter = require('node:events'); +const { REST } = require('@discordjs/rest'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const Options = require('../util/Options'); +const { mergeDefault, flatten } = require('../util/Util'); + +/** + * The base class for all clients. + * @extends {EventEmitter} + */ +class BaseClient extends EventEmitter { + constructor(options = {}) { + super({ captureRejections: true }); + + if (typeof options !== 'object' || options === null) { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true); + } + + /** + * The options the client was instantiated with + * @type {ClientOptions} + */ + this.options = mergeDefault(Options.createDefault(), { + ...options, + rest: { + ...options.rest, + userAgentAppendix: options.rest?.userAgentAppendix + ? `${Options.userAgentAppendix} ${options.rest.userAgentAppendix}` + : undefined, + }, + }); + + /** + * The REST manager of the client + * @type {REST} + */ + this.rest = new REST(this.options.rest); + } + + /** + * Destroys all assets used by the base client. + * @returns {void} + */ + destroy() { + this.rest.clearHashSweeper(); + this.rest.clearHandlerSweeper(); + } + + /** + * Increments max listeners by one, if they are not zero. + * @private + */ + incrementMaxListeners() { + const maxListeners = this.getMaxListeners(); + if (maxListeners !== 0) { + this.setMaxListeners(maxListeners + 1); + } + } + + /** + * Decrements max listeners by one, if they are not zero. + * @private + */ + decrementMaxListeners() { + const maxListeners = this.getMaxListeners(); + if (maxListeners !== 0) { + this.setMaxListeners(maxListeners - 1); + } + } + + toJSON(...props) { + return flatten(this, ...props); + } +} + +module.exports = BaseClient; + +/** + * @external REST + * @see {@link https://discord.js.org/docs/packages/rest/stable/REST:Class} + */ diff --git a/node_modules/discord.js/src/client/Client.js b/node_modules/discord.js/src/client/Client.js new file mode 100644 index 0000000..80719e8 --- /dev/null +++ b/node_modules/discord.js/src/client/Client.js @@ -0,0 +1,608 @@ +'use strict'; + +const process = require('node:process'); +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { OAuth2Scopes, Routes } = require('discord-api-types/v10'); +const BaseClient = require('./BaseClient'); +const ActionsManager = require('./actions/ActionsManager'); +const ClientVoiceManager = require('./voice/ClientVoiceManager'); +const WebSocketManager = require('./websocket/WebSocketManager'); +const { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } = require('../errors'); +const BaseGuildEmojiManager = require('../managers/BaseGuildEmojiManager'); +const ChannelManager = require('../managers/ChannelManager'); +const GuildManager = require('../managers/GuildManager'); +const UserManager = require('../managers/UserManager'); +const ShardClientUtil = require('../sharding/ShardClientUtil'); +const ClientPresence = require('../structures/ClientPresence'); +const GuildPreview = require('../structures/GuildPreview'); +const GuildTemplate = require('../structures/GuildTemplate'); +const Invite = require('../structures/Invite'); +const { Sticker } = require('../structures/Sticker'); +const StickerPack = require('../structures/StickerPack'); +const VoiceRegion = require('../structures/VoiceRegion'); +const Webhook = require('../structures/Webhook'); +const Widget = require('../structures/Widget'); +const DataResolver = require('../util/DataResolver'); +const Events = require('../util/Events'); +const IntentsBitField = require('../util/IntentsBitField'); +const Options = require('../util/Options'); +const PermissionsBitField = require('../util/PermissionsBitField'); +const Status = require('../util/Status'); +const Sweepers = require('../util/Sweepers'); + +/** + * The main hub for interacting with the Discord API, and the starting point for any bot. + * @extends {BaseClient} + */ +class Client extends BaseClient { + /** + * @param {ClientOptions} options Options for the client + */ + constructor(options) { + super(options); + + const data = require('node:worker_threads').workerData ?? process.env; + const defaults = Options.createDefault(); + + if (this.options.shards === defaults.shards) { + if ('SHARDS' in data) { + this.options.shards = JSON.parse(data.SHARDS); + } + } + + if (this.options.shardCount === defaults.shardCount) { + if ('SHARD_COUNT' in data) { + this.options.shardCount = Number(data.SHARD_COUNT); + } else if (Array.isArray(this.options.shards)) { + this.options.shardCount = this.options.shards.length; + } + } + + const typeofShards = typeof this.options.shards; + + if (typeofShards === 'undefined' && typeof this.options.shardCount === 'number') { + this.options.shards = Array.from({ length: this.options.shardCount }, (_, i) => i); + } + + if (typeofShards === 'number') this.options.shards = [this.options.shards]; + + if (Array.isArray(this.options.shards)) { + this.options.shards = [ + ...new Set( + this.options.shards.filter(item => !isNaN(item) && item >= 0 && item < Infinity && item === (item | 0)), + ), + ]; + } + + this._validateOptions(); + + /** + * The WebSocket manager of the client + * @type {WebSocketManager} + */ + this.ws = new WebSocketManager(this); + + /** + * The action manager of the client + * @type {ActionsManager} + * @private + */ + this.actions = new ActionsManager(this); + + /** + * The voice manager of the client + * @type {ClientVoiceManager} + */ + this.voice = new ClientVoiceManager(this); + + /** + * Shard helpers for the client (only if the process was spawned from a {@link ShardingManager}) + * @type {?ShardClientUtil} + */ + this.shard = process.env.SHARDING_MANAGER + ? ShardClientUtil.singleton(this, process.env.SHARDING_MANAGER_MODE) + : null; + + /** + * All of the {@link User} objects that have been cached at any point, mapped by their ids + * @type {UserManager} + */ + this.users = new UserManager(this); + + /** + * All of the guilds the client is currently handling, mapped by their ids - + * as long as sharding isn't being used, this will be *every* guild the bot is a member of + * @type {GuildManager} + */ + this.guilds = new GuildManager(this); + + /** + * All of the {@link BaseChannel}s that the client is currently handling, mapped by their ids - + * as long as sharding isn't being used, this will be *every* channel in *every* guild the bot + * is a member of. Note that DM channels will not be initially cached, and thus not be present + * in the Manager without their explicit fetching or use. + * @type {ChannelManager} + */ + this.channels = new ChannelManager(this); + + /** + * The sweeping functions and their intervals used to periodically sweep caches + * @type {Sweepers} + */ + this.sweepers = new Sweepers(this, this.options.sweepers); + + /** + * The presence of the Client + * @private + * @type {ClientPresence} + */ + this.presence = new ClientPresence(this, this.options.presence); + + Object.defineProperty(this, 'token', { writable: true }); + if (!this.token && 'DISCORD_TOKEN' in process.env) { + /** + * Authorization token for the logged in bot. + * If present, this defaults to `process.env.DISCORD_TOKEN` when instantiating the client + * <warn>This should be kept private at all times.</warn> + * @type {?string} + */ + this.token = process.env.DISCORD_TOKEN; + } else { + this.token = null; + } + + /** + * User that the client is logged in as + * @type {?ClientUser} + */ + this.user = null; + + /** + * The application of this bot + * @type {?ClientApplication} + */ + this.application = null; + + /** + * Timestamp of the time the client was last {@link Status.Ready} at + * @type {?number} + */ + this.readyTimestamp = null; + } + + /** + * All custom emojis that the client has access to, mapped by their ids + * @type {BaseGuildEmojiManager} + * @readonly + */ + get emojis() { + const emojis = new BaseGuildEmojiManager(this); + for (const guild of this.guilds.cache.values()) { + if (guild.available) for (const emoji of guild.emojis.cache.values()) emojis.cache.set(emoji.id, emoji); + } + return emojis; + } + + /** + * Time at which the client was last regarded as being in the {@link Status.Ready} state + * (each time the client disconnects and successfully reconnects, this will be overwritten) + * @type {?Date} + * @readonly + */ + get readyAt() { + return this.readyTimestamp && new Date(this.readyTimestamp); + } + + /** + * How long it has been since the client last entered the {@link Status.Ready} state in milliseconds + * @type {?number} + * @readonly + */ + get uptime() { + return this.readyTimestamp && Date.now() - this.readyTimestamp; + } + + /** + * Logs the client in, establishing a WebSocket connection to Discord. + * @param {string} [token=this.token] Token of the account to log in with + * @returns {Promise<string>} Token of the account used + * @example + * client.login('my token'); + */ + async login(token = this.token) { + if (!token || typeof token !== 'string') throw new DiscordjsError(ErrorCodes.TokenInvalid); + this.token = token = token.replace(/^(Bot|Bearer)\s*/i, ''); + this.rest.setToken(token); + this.emit(Events.Debug, `Provided token: ${this._censoredToken}`); + + if (this.options.presence) { + this.options.ws.presence = this.presence._parse(this.options.presence); + } + + this.emit(Events.Debug, 'Preparing to connect to the gateway...'); + + try { + await this.ws.connect(); + return this.token; + } catch (error) { + await this.destroy(); + throw error; + } + } + + /** + * Returns whether the client has logged in, indicative of being able to access + * properties such as `user` and `application`. + * @returns {boolean} + */ + isReady() { + return this.ws.status === Status.Ready; + } + + /** + * Logs out, terminates the connection to Discord, and destroys the client. + * @returns {Promise<void>} + */ + async destroy() { + super.destroy(); + + this.sweepers.destroy(); + await this.ws.destroy(); + this.token = null; + this.rest.setToken(null); + } + + /** + * Options used for deleting a webhook. + * @typedef {Object} WebhookDeleteOptions + * @property {string} [token] Token of the webhook + * @property {string} [reason] The reason for deleting the webhook + */ + + /** + * Deletes a webhook. + * @param {Snowflake} id The webhook's id + * @param {WebhookDeleteOptions} [options] Options for deleting the webhook + * @returns {Promise<void>} + */ + async deleteWebhook(id, { token, reason } = {}) { + await this.rest.delete(Routes.webhook(id, token), { auth: !token, reason }); + } + + /** + * Options used when fetching an invite from Discord. + * @typedef {Object} ClientFetchInviteOptions + * @property {Snowflake} [guildScheduledEventId] The id of the guild scheduled event to include with + * the invite + */ + + /** + * Obtains an invite from Discord. + * @param {InviteResolvable} invite Invite code or URL + * @param {ClientFetchInviteOptions} [options] Options for fetching the invite + * @returns {Promise<Invite>} + * @example + * client.fetchInvite('https://discord.gg/djs') + * .then(invite => console.log(`Obtained invite with code: ${invite.code}`)) + * .catch(console.error); + */ + async fetchInvite(invite, options) { + const code = DataResolver.resolveInviteCode(invite); + const query = makeURLSearchParams({ + with_counts: true, + with_expiration: true, + guild_scheduled_event_id: options?.guildScheduledEventId, + }); + const data = await this.rest.get(Routes.invite(code), { query }); + return new Invite(this, data); + } + + /** + * Obtains a template from Discord. + * @param {GuildTemplateResolvable} template Template code or URL + * @returns {Promise<GuildTemplate>} + * @example + * client.fetchGuildTemplate('https://discord.new/FKvmczH2HyUf') + * .then(template => console.log(`Obtained template with code: ${template.code}`)) + * .catch(console.error); + */ + async fetchGuildTemplate(template) { + const code = DataResolver.resolveGuildTemplateCode(template); + const data = await this.rest.get(Routes.template(code)); + return new GuildTemplate(this, data); + } + + /** + * Obtains a webhook from Discord. + * @param {Snowflake} id The webhook's id + * @param {string} [token] Token for the webhook + * @returns {Promise<Webhook>} + * @example + * client.fetchWebhook('id', 'token') + * .then(webhook => console.log(`Obtained webhook with name: ${webhook.name}`)) + * .catch(console.error); + */ + async fetchWebhook(id, token) { + const data = await this.rest.get(Routes.webhook(id, token), { auth: token === undefined }); + return new Webhook(this, { token, ...data }); + } + + /** + * Obtains the available voice regions from Discord. + * @returns {Promise<Collection<string, VoiceRegion>>} + * @example + * client.fetchVoiceRegions() + * .then(regions => console.log(`Available regions are: ${regions.map(region => region.name).join(', ')}`)) + * .catch(console.error); + */ + async fetchVoiceRegions() { + const apiRegions = await this.rest.get(Routes.voiceRegions()); + const regions = new Collection(); + for (const region of apiRegions) regions.set(region.id, new VoiceRegion(region)); + return regions; + } + + /** + * Obtains a sticker from Discord. + * @param {Snowflake} id The sticker's id + * @returns {Promise<Sticker>} + * @example + * client.fetchSticker('id') + * .then(sticker => console.log(`Obtained sticker with name: ${sticker.name}`)) + * .catch(console.error); + */ + async fetchSticker(id) { + const data = await this.rest.get(Routes.sticker(id)); + return new Sticker(this, data); + } + + /** + * Obtains the list of sticker packs available to Nitro subscribers from Discord. + * @returns {Promise<Collection<Snowflake, StickerPack>>} + * @example + * client.fetchPremiumStickerPacks() + * .then(packs => console.log(`Available sticker packs are: ${packs.map(pack => pack.name).join(', ')}`)) + * .catch(console.error); + */ + async fetchPremiumStickerPacks() { + const data = await this.rest.get(Routes.nitroStickerPacks()); + return new Collection(data.sticker_packs.map(p => [p.id, new StickerPack(this, p)])); + } + + /** + * Obtains a guild preview from Discord, available for all guilds the bot is in and all Discoverable guilds. + * @param {GuildResolvable} guild The guild to fetch the preview for + * @returns {Promise<GuildPreview>} + */ + async fetchGuildPreview(guild) { + const id = this.guilds.resolveId(guild); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'guild', 'GuildResolvable'); + const data = await this.rest.get(Routes.guildPreview(id)); + return new GuildPreview(this, data); + } + + /** + * Obtains the widget data of a guild from Discord, available for guilds with the widget enabled. + * @param {GuildResolvable} guild The guild to fetch the widget data for + * @returns {Promise<Widget>} + */ + async fetchGuildWidget(guild) { + const id = this.guilds.resolveId(guild); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'guild', 'GuildResolvable'); + const data = await this.rest.get(Routes.guildWidgetJSON(id)); + return new Widget(this, data); + } + + /** + * Options for {@link Client#generateInvite}. + * @typedef {Object} InviteGenerationOptions + * @property {OAuth2Scopes[]} scopes Scopes that should be requested + * @property {PermissionResolvable} [permissions] Permissions to request + * @property {GuildResolvable} [guild] Guild to preselect + * @property {boolean} [disableGuildSelect] Whether to disable the guild selection + */ + + /** + * Generates a link that can be used to invite the bot to a guild. + * @param {InviteGenerationOptions} [options={}] Options for the invite + * @returns {string} + * @example + * const link = client.generateInvite({ + * scopes: [OAuth2Scopes.ApplicationsCommands], + * }); + * console.log(`Generated application invite link: ${link}`); + * @example + * const link = client.generateInvite({ + * permissions: [ + * PermissionFlagsBits.SendMessages, + * PermissionFlagsBits.ManageGuild, + * PermissionFlagsBits.MentionEveryone, + * ], + * scopes: [OAuth2Scopes.Bot], + * }); + * console.log(`Generated bot invite link: ${link}`); + */ + generateInvite(options = {}) { + if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true); + if (!this.application) throw new DiscordjsError(ErrorCodes.ClientNotReady, 'generate an invite link'); + + const { scopes } = options; + if (scopes === undefined) { + throw new DiscordjsTypeError(ErrorCodes.InvalidMissingScopes); + } + if (!Array.isArray(scopes)) { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'scopes', 'Array of Invite Scopes', true); + } + if (!scopes.some(scope => [OAuth2Scopes.Bot, OAuth2Scopes.ApplicationsCommands].includes(scope))) { + throw new DiscordjsTypeError(ErrorCodes.InvalidMissingScopes); + } + if (!scopes.includes(OAuth2Scopes.Bot) && options.permissions) { + throw new DiscordjsTypeError(ErrorCodes.InvalidScopesWithPermissions); + } + const validScopes = Object.values(OAuth2Scopes); + const invalidScope = scopes.find(scope => !validScopes.includes(scope)); + if (invalidScope) { + throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array', 'scopes', invalidScope); + } + + const query = makeURLSearchParams({ + client_id: this.application.id, + scope: scopes.join(' '), + disable_guild_select: options.disableGuildSelect, + }); + + if (options.permissions) { + const permissions = PermissionsBitField.resolve(options.permissions); + if (permissions) query.set('permissions', permissions.toString()); + } + + if (options.guild) { + const guildId = this.guilds.resolveId(options.guild); + if (!guildId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options.guild', 'GuildResolvable'); + query.set('guild_id', guildId); + } + + return `${this.options.rest.api}${Routes.oauth2Authorization()}?${query}`; + } + + toJSON() { + return super.toJSON({ + actions: false, + presence: false, + }); + } + + /** + * Partially censored client token for debug logging purposes. + * @type {?string} + * @readonly + * @private + */ + get _censoredToken() { + if (!this.token) return null; + + return this.token + .split('.') + .map((val, i) => (i > 1 ? val.replace(/./g, '*') : val)) + .join('.'); + } + + /** + * Calls {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval} on a script + * with the client as `this`. + * @param {string} script Script to eval + * @returns {*} + * @private + */ + _eval(script) { + return eval(script); + } + + /** + * Validates the client options. + * @param {ClientOptions} [options=this.options] Options to validate + * @private + */ + _validateOptions(options = this.options) { + if (options.intents === undefined) { + throw new DiscordjsTypeError(ErrorCodes.ClientMissingIntents); + } else { + options.intents = new IntentsBitField(options.intents).freeze(); + } + if (typeof options.shardCount !== 'number' || isNaN(options.shardCount) || options.shardCount < 1) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'shardCount', 'a number greater than or equal to 1'); + } + if (options.shards && !(options.shards === 'auto' || Array.isArray(options.shards))) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'shards', "'auto', a number or array of numbers"); + } + if (options.shards && !options.shards.length) throw new DiscordjsRangeError(ErrorCodes.ClientInvalidProvidedShards); + if (typeof options.makeCache !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'makeCache', 'a function'); + } + if (typeof options.sweepers !== 'object' || options.sweepers === null) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'sweepers', 'an object'); + } + if (!Array.isArray(options.partials)) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'partials', 'an Array'); + } + if (typeof options.waitGuildTimeout !== 'number' || isNaN(options.waitGuildTimeout)) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'waitGuildTimeout', 'a number'); + } + if (typeof options.failIfNotExists !== 'boolean') { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'failIfNotExists', 'a boolean'); + } + if ( + (typeof options.allowedMentions !== 'object' && options.allowedMentions !== undefined) || + options.allowedMentions === null + ) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'allowedMentions', 'an object'); + } + if (typeof options.presence !== 'object' || options.presence === null) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'presence', 'an object'); + } + if (typeof options.ws !== 'object' || options.ws === null) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'ws', 'an object'); + } + if (typeof options.rest !== 'object' || options.rest === null) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'rest', 'an object'); + } + if (typeof options.jsonTransformer !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'jsonTransformer', 'a function'); + } + } +} + +module.exports = Client; + +/** + * @class SnowflakeUtil + * @classdesc This class is an alias for {@link https://www.npmjs.com/package/@sapphire/snowflake @sapphire/snowflake}'s + * `DiscordSnowflake` class. + * + * Check their documentation + * {@link https://www.sapphirejs.dev/docs/Documentation/api-utilities/classes/sapphire_snowflake.Snowflake here} + * ({@link https://www.sapphirejs.dev/docs/Guide/utilities/snowflake guide}) + * to see what you can do. + * @hideconstructor + */ + +/** + * A {@link https://developer.twitter.com/en/docs/twitter-ids Twitter snowflake}, + * except the epoch is 2015-01-01T00:00:00.000Z. + * + * If we have a snowflake '266241948824764416' we can represent it as binary: + * ``` + * 64 22 17 12 0 + * 000000111011000111100001101001000101000000 00001 00000 000000000000 + * number of milliseconds since Discord epoch worker pid increment + * ``` + * @typedef {string} Snowflake + */ + +/** + * Emitted for general debugging information. + * @event Client#debug + * @param {string} info The debug information + */ + +/** + * Emitted for general warnings. + * @event Client#warn + * @param {string} info The warning + */ + +/** + * @external Collection + * @see {@link https://discord.js.org/docs/packages/collection/stable/Collection:Class} + */ + +/** + * @external ImageURLOptions + * @see {@link https://discord.js.org/docs/packages/rest/stable/ImageURLOptions:Interface} + */ + +/** + * @external BaseImageURLOptions + * @see {@link https://discord.js.org/docs/packages/rest/stable/BaseImageURLOptions:Interface} + */ diff --git a/node_modules/discord.js/src/client/WebhookClient.js b/node_modules/discord.js/src/client/WebhookClient.js new file mode 100644 index 0000000..5bb6412 --- /dev/null +++ b/node_modules/discord.js/src/client/WebhookClient.js @@ -0,0 +1,103 @@ +'use strict'; + +const BaseClient = require('./BaseClient'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const Webhook = require('../structures/Webhook'); +const { parseWebhookURL } = require('../util/Util'); + +/** + * The webhook client. + * @implements {Webhook} + * @extends {BaseClient} + */ +class WebhookClient extends BaseClient { + /** + * Represents the credentials used for a webhook in the form of its id and token. + * @typedef {Object} WebhookClientDataIdWithToken + * @property {Snowflake} id The webhook's id + * @property {string} token The webhook's token + */ + + /** + * Represents the credentials used for a webhook in the form of a URL. + * @typedef {Object} WebhookClientDataURL + * @property {string} url The full URL for the webhook + */ + + /** + * Represents the credentials used for a webhook. + * @typedef {WebhookClientDataIdWithToken|WebhookClientDataURL} WebhookClientData + */ + + /** + * Options for a webhook client. + * @typedef {Object} WebhookClientOptions + * @property {MessageMentionOptions} [allowedMentions] Default value for {@link BaseMessageOptions#allowedMentions} + * @property {RESTOptions} [rest] Options for the REST manager + */ + + /** + * @param {WebhookClientData} data The data of the webhook + * @param {WebhookClientOptions} [options] Options for the webhook client + */ + constructor(data, options) { + super(options); + Object.defineProperty(this, 'client', { value: this }); + let { id, token } = data; + + if ('url' in data) { + const parsed = parseWebhookURL(data.url); + if (!parsed) { + throw new DiscordjsError(ErrorCodes.WebhookURLInvalid); + } + + ({ id, token } = parsed); + } + + this.id = id; + Object.defineProperty(this, 'token', { value: token, writable: true, configurable: true }); + } + + /** + * The options the webhook client was instantiated with. + * @type {WebhookClientOptions} + * @name WebhookClient#options + */ + + // These are here only for documentation purposes - they are implemented by Webhook + /* eslint-disable no-empty-function, valid-jsdoc */ + /** + * Sends a message with this webhook. + * @param {string|MessagePayload|WebhookMessageCreateOptions} options The content for the reply + * @returns {Promise<APIMessage>} + */ + send() {} + + /** + * Gets a message that was sent by this webhook. + * @param {Snowflake} message The id of the message to fetch + * @param {WebhookFetchMessageOptions} [options={}] The options to provide to fetch the message. + * @returns {Promise<APIMessage>} Returns the message sent by this webhook + */ + fetchMessage() {} + + /** + * Edits a message that was sent by this webhook. + * @param {MessageResolvable} message The message to edit + * @param {string|MessagePayload|WebhookMessageEditOptions} options The options to provide + * @returns {Promise<APIMessage>} Returns the message edited by this webhook + */ + editMessage() {} + + sendSlackMessage() {} + edit() {} + delete() {} + deleteMessage() {} + get createdTimestamp() {} + get createdAt() {} + get url() {} +} + +Webhook.applyToClass(WebhookClient); + +module.exports = WebhookClient; diff --git a/node_modules/discord.js/src/client/actions/Action.js b/node_modules/discord.js/src/client/actions/Action.js new file mode 100644 index 0000000..6c04a64 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/Action.js @@ -0,0 +1,120 @@ +'use strict'; + +const Partials = require('../../util/Partials'); + +/* + +ABOUT ACTIONS + +Actions are similar to WebSocket Packet Handlers, but since introducing +the REST API methods, in order to prevent rewriting code to handle data, +"actions" have been introduced. They're basically what Packet Handlers +used to be but they're strictly for manipulating data and making sure +that WebSocket events don't clash with REST methods. + +*/ + +class GenericAction { + constructor(client) { + this.client = client; + } + + handle(data) { + return data; + } + + getPayload(data, manager, id, partialType, cache) { + return this.client.options.partials.includes(partialType) ? manager._add(data, cache) : manager.cache.get(id); + } + + getChannel(data) { + const payloadData = {}; + const id = data.channel_id ?? data.id; + + if ('recipients' in data) { + payloadData.recipients = data.recipients; + } else { + // Try to resolve the recipient, but do not add the client user. + const recipient = data.author ?? data.user ?? { id: data.user_id }; + if (recipient.id !== this.client.user.id) payloadData.recipients = [recipient]; + } + + if (id !== undefined) payloadData.id = id; + if ('guild_id' in data) payloadData.guild_id = data.guild_id; + if ('last_message_id' in data) payloadData.last_message_id = data.last_message_id; + + return ( + data[this.client.actions.injectedChannel] ?? + this.getPayload(payloadData, this.client.channels, id, Partials.Channel) + ); + } + + getMessage(data, channel, cache) { + const id = data.message_id ?? data.id; + return ( + data[this.client.actions.injectedMessage] ?? + this.getPayload( + { + id, + channel_id: channel.id, + guild_id: data.guild_id ?? channel.guild?.id, + }, + channel.messages, + id, + Partials.Message, + cache, + ) + ); + } + + getReaction(data, message, user) { + const id = data.emoji.id ?? decodeURIComponent(data.emoji.name); + return this.getPayload( + { + emoji: data.emoji, + count: message.partial ? null : 0, + me: user?.id === this.client.user.id, + }, + message.reactions, + id, + Partials.Reaction, + ); + } + + getMember(data, guild) { + return this.getPayload(data, guild.members, data.user.id, Partials.GuildMember); + } + + getUser(data) { + const id = data.user_id; + return data[this.client.actions.injectedUser] ?? this.getPayload({ id }, this.client.users, id, Partials.User); + } + + getUserFromMember(data) { + if (data.guild_id && data.member?.user) { + const guild = this.client.guilds.cache.get(data.guild_id); + if (guild) { + return guild.members._add(data.member).user; + } else { + return this.client.users._add(data.member.user); + } + } + return this.getUser(data); + } + + getScheduledEvent(data, guild) { + const id = data.guild_scheduled_event_id ?? data.id; + return this.getPayload( + { id, guild_id: data.guild_id ?? guild.id }, + guild.scheduledEvents, + id, + Partials.GuildScheduledEvent, + ); + } + + getThreadMember(id, manager) { + return this.getPayload({ user_id: id }, manager, id, Partials.ThreadMember, false); + } +} + +module.exports = GenericAction; diff --git a/node_modules/discord.js/src/client/actions/ActionsManager.js b/node_modules/discord.js/src/client/actions/ActionsManager.js new file mode 100644 index 0000000..301a6a9 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/ActionsManager.js @@ -0,0 +1,79 @@ +'use strict'; + +class ActionsManager { + // These symbols represent fully built data that we inject at times when calling actions manually. + // Action#getUser, for example, will return the injected data (which is assumed to be a built structure) + // instead of trying to make it from provided data + injectedUser = Symbol('djs.actions.injectedUser'); + injectedChannel = Symbol('djs.actions.injectedChannel'); + injectedMessage = Symbol('djs.actions.injectedMessage'); + + constructor(client) { + this.client = client; + + this.register(require('./ApplicationCommandPermissionsUpdate')); + this.register(require('./AutoModerationActionExecution')); + this.register(require('./AutoModerationRuleCreate')); + this.register(require('./AutoModerationRuleDelete')); + this.register(require('./AutoModerationRuleUpdate')); + this.register(require('./ChannelCreate')); + this.register(require('./ChannelDelete')); + this.register(require('./ChannelUpdate')); + this.register(require('./GuildAuditLogEntryCreate')); + this.register(require('./GuildBanAdd')); + this.register(require('./GuildBanRemove')); + this.register(require('./GuildChannelsPositionUpdate')); + this.register(require('./GuildDelete')); + this.register(require('./GuildEmojiCreate')); + this.register(require('./GuildEmojiDelete')); + this.register(require('./GuildEmojiUpdate')); + this.register(require('./GuildEmojisUpdate')); + this.register(require('./GuildIntegrationsUpdate')); + this.register(require('./GuildMemberRemove')); + this.register(require('./GuildMemberUpdate')); + this.register(require('./GuildRoleCreate')); + this.register(require('./GuildRoleDelete')); + this.register(require('./GuildRoleUpdate')); + this.register(require('./GuildRolesPositionUpdate')); + this.register(require('./GuildScheduledEventCreate')); + this.register(require('./GuildScheduledEventDelete')); + this.register(require('./GuildScheduledEventUpdate')); + this.register(require('./GuildScheduledEventUserAdd')); + this.register(require('./GuildScheduledEventUserRemove')); + this.register(require('./GuildStickerCreate')); + this.register(require('./GuildStickerDelete')); + this.register(require('./GuildStickerUpdate')); + this.register(require('./GuildStickersUpdate')); + this.register(require('./GuildUpdate')); + this.register(require('./InteractionCreate')); + this.register(require('./InviteCreate')); + this.register(require('./InviteDelete')); + this.register(require('./MessageCreate')); + this.register(require('./MessageDelete')); + this.register(require('./MessageDeleteBulk')); + this.register(require('./MessageReactionAdd')); + this.register(require('./MessageReactionRemove')); + this.register(require('./MessageReactionRemoveAll')); + this.register(require('./MessageReactionRemoveEmoji')); + this.register(require('./MessageUpdate')); + this.register(require('./PresenceUpdate')); + this.register(require('./StageInstanceCreate')); + this.register(require('./StageInstanceDelete')); + this.register(require('./StageInstanceUpdate')); + this.register(require('./ThreadCreate')); + this.register(require('./ThreadDelete')); + this.register(require('./ThreadListSync')); + this.register(require('./ThreadMemberUpdate')); + this.register(require('./ThreadMembersUpdate')); + this.register(require('./TypingStart')); + this.register(require('./UserUpdate')); + this.register(require('./VoiceStateUpdate')); + this.register(require('./WebhooksUpdate')); + } + + register(Action) { + this[Action.name.replace(/Action$/, '')] = new Action(this.client); + } +} + +module.exports = ActionsManager; diff --git a/node_modules/discord.js/src/client/actions/ApplicationCommandPermissionsUpdate.js b/node_modules/discord.js/src/client/actions/ApplicationCommandPermissionsUpdate.js new file mode 100644 index 0000000..f2bc214 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/ApplicationCommandPermissionsUpdate.js @@ -0,0 +1,34 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +/** + * The data received in the {@link Client#event:applicationCommandPermissionsUpdate} event + * @typedef {Object} ApplicationCommandPermissionsUpdateData + * @property {Snowflake} id The id of the command or global entity that was updated + * @property {Snowflake} guildId The id of the guild in which permissions were updated + * @property {Snowflake} applicationId The id of the application that owns the command or entity being updated + * @property {ApplicationCommandPermissions[]} permissions The updated permissions + */ + +class ApplicationCommandPermissionsUpdateAction extends Action { + handle(data) { + const client = this.client; + /** + * Emitted whenever permissions for an application command in a guild were updated. + * <warn>This includes permission updates for other applications in addition to the logged in client, + * check `data.applicationId` to verify which application the update is for</warn> + * @event Client#applicationCommandPermissionsUpdate + * @param {ApplicationCommandPermissionsUpdateData} data The updated permissions + */ + client.emit(Events.ApplicationCommandPermissionsUpdate, { + permissions: data.permissions, + id: data.id, + guildId: data.guild_id, + applicationId: data.application_id, + }); + } +} + +module.exports = ApplicationCommandPermissionsUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/AutoModerationActionExecution.js b/node_modules/discord.js/src/client/actions/AutoModerationActionExecution.js new file mode 100644 index 0000000..ad60116 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/AutoModerationActionExecution.js @@ -0,0 +1,26 @@ +'use strict'; + +const Action = require('./Action'); +const AutoModerationActionExecution = require('../../structures/AutoModerationActionExecution'); +const Events = require('../../util/Events'); + +class AutoModerationActionExecutionAction extends Action { + handle(data) { + const { client } = this; + const guild = client.guilds.cache.get(data.guild_id); + + if (guild) { + /** + * Emitted whenever an auto moderation rule is triggered. + * <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info> + * @event Client#autoModerationActionExecution + * @param {AutoModerationActionExecution} autoModerationActionExecution The data of the execution + */ + client.emit(Events.AutoModerationActionExecution, new AutoModerationActionExecution(data, guild)); + } + + return {}; + } +} + +module.exports = AutoModerationActionExecutionAction; diff --git a/node_modules/discord.js/src/client/actions/AutoModerationRuleCreate.js b/node_modules/discord.js/src/client/actions/AutoModerationRuleCreate.js new file mode 100644 index 0000000..775b1d3 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/AutoModerationRuleCreate.js @@ -0,0 +1,27 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class AutoModerationRuleCreateAction extends Action { + handle(data) { + const { client } = this; + const guild = client.guilds.cache.get(data.guild_id); + + if (guild) { + const autoModerationRule = guild.autoModerationRules._add(data); + + /** + * Emitted whenever an auto moderation rule is created. + * <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info> + * @event Client#autoModerationRuleCreate + * @param {AutoModerationRule} autoModerationRule The created auto moderation rule + */ + client.emit(Events.AutoModerationRuleCreate, autoModerationRule); + } + + return {}; + } +} + +module.exports = AutoModerationRuleCreateAction; diff --git a/node_modules/discord.js/src/client/actions/AutoModerationRuleDelete.js b/node_modules/discord.js/src/client/actions/AutoModerationRuleDelete.js new file mode 100644 index 0000000..641822c --- /dev/null +++ b/node_modules/discord.js/src/client/actions/AutoModerationRuleDelete.js @@ -0,0 +1,31 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class AutoModerationRuleDeleteAction extends Action { + handle(data) { + const { client } = this; + const guild = client.guilds.cache.get(data.guild_id); + + if (guild) { + const autoModerationRule = guild.autoModerationRules.cache.get(data.id); + + if (autoModerationRule) { + guild.autoModerationRules.cache.delete(autoModerationRule.id); + + /** + * Emitted whenever an auto moderation rule is deleted. + * <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info> + * @event Client#autoModerationRuleDelete + * @param {AutoModerationRule} autoModerationRule The deleted auto moderation rule + */ + client.emit(Events.AutoModerationRuleDelete, autoModerationRule); + } + } + + return {}; + } +} + +module.exports = AutoModerationRuleDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/AutoModerationRuleUpdate.js b/node_modules/discord.js/src/client/actions/AutoModerationRuleUpdate.js new file mode 100644 index 0000000..56e3956 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/AutoModerationRuleUpdate.js @@ -0,0 +1,29 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class AutoModerationRuleUpdateAction extends Action { + handle(data) { + const { client } = this; + const guild = client.guilds.cache.get(data.guild_id); + + if (guild) { + const oldAutoModerationRule = guild.autoModerationRules.cache.get(data.id)?._clone() ?? null; + const newAutoModerationRule = guild.autoModerationRules._add(data); + + /** + * Emitted whenever an auto moderation rule gets updated. + * <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info> + * @event Client#autoModerationRuleUpdate + * @param {?AutoModerationRule} oldAutoModerationRule The auto moderation rule before the update + * @param {AutoModerationRule} newAutoModerationRule The auto moderation rule after the update + */ + client.emit(Events.AutoModerationRuleUpdate, oldAutoModerationRule, newAutoModerationRule); + } + + return {}; + } +} + +module.exports = AutoModerationRuleUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/ChannelCreate.js b/node_modules/discord.js/src/client/actions/ChannelCreate.js new file mode 100644 index 0000000..fdf8ddd --- /dev/null +++ b/node_modules/discord.js/src/client/actions/ChannelCreate.js @@ -0,0 +1,23 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class ChannelCreateAction extends Action { + handle(data) { + const client = this.client; + const existing = client.channels.cache.has(data.id); + const channel = client.channels._add(data); + if (!existing && channel) { + /** + * Emitted whenever a guild channel is created. + * @event Client#channelCreate + * @param {GuildChannel} channel The channel that was created + */ + client.emit(Events.ChannelCreate, channel); + } + return { channel }; + } +} + +module.exports = ChannelCreateAction; diff --git a/node_modules/discord.js/src/client/actions/ChannelDelete.js b/node_modules/discord.js/src/client/actions/ChannelDelete.js new file mode 100644 index 0000000..acf03d9 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/ChannelDelete.js @@ -0,0 +1,23 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class ChannelDeleteAction extends Action { + handle(data) { + const client = this.client; + const channel = client.channels.cache.get(data.id); + + if (channel) { + client.channels._remove(channel.id); + /** + * Emitted whenever a channel is deleted. + * @event Client#channelDelete + * @param {DMChannel|GuildChannel} channel The channel that was deleted + */ + client.emit(Events.ChannelDelete, channel); + } + } +} + +module.exports = ChannelDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/ChannelUpdate.js b/node_modules/discord.js/src/client/actions/ChannelUpdate.js new file mode 100644 index 0000000..7ca331a --- /dev/null +++ b/node_modules/discord.js/src/client/actions/ChannelUpdate.js @@ -0,0 +1,42 @@ +'use strict'; + +const Action = require('./Action'); +const { createChannel } = require('../../util/Channels'); + +class ChannelUpdateAction extends Action { + handle(data) { + const client = this.client; + let channel = client.channels.cache.get(data.id); + + if (channel) { + const old = channel._update(data); + + if (channel.type !== data.type) { + const newChannel = createChannel(this.client, data, channel.guild); + + if (!newChannel) { + this.client.channels.cache.delete(channel.id); + return {}; + } + + if (channel.isTextBased() && newChannel.isTextBased()) { + for (const [id, message] of channel.messages.cache) newChannel.messages.cache.set(id, message); + } + + channel = newChannel; + this.client.channels.cache.set(channel.id, channel); + } + + return { + old, + updated: channel, + }; + } else { + client.channels._add(data); + } + + return {}; + } +} + +module.exports = ChannelUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildAuditLogEntryCreate.js b/node_modules/discord.js/src/client/actions/GuildAuditLogEntryCreate.js new file mode 100644 index 0000000..fa16de6 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildAuditLogEntryCreate.js @@ -0,0 +1,29 @@ +'use strict'; + +const Action = require('./Action'); +const GuildAuditLogsEntry = require('../../structures/GuildAuditLogsEntry'); +const Events = require('../../util/Events'); + +class GuildAuditLogEntryCreateAction extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + let auditLogEntry; + + if (guild) { + auditLogEntry = new GuildAuditLogsEntry(guild, data); + + /** + * Emitted whenever a guild audit log entry is created. + * @event Client#guildAuditLogEntryCreate + * @param {GuildAuditLogsEntry} auditLogEntry The entry that was created + * @param {Guild} guild The guild where the entry was created + */ + client.emit(Events.GuildAuditLogEntryCreate, auditLogEntry, guild); + } + + return { auditLogEntry }; + } +} + +module.exports = GuildAuditLogEntryCreateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildBanAdd.js b/node_modules/discord.js/src/client/actions/GuildBanAdd.js new file mode 100644 index 0000000..2ef4b11 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildBanAdd.js @@ -0,0 +1,20 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildBanAdd extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + + /** + * Emitted whenever a member is banned from a guild. + * @event Client#guildBanAdd + * @param {GuildBan} ban The ban that occurred + */ + if (guild) client.emit(Events.GuildBanAdd, guild.bans._add(data)); + } +} + +module.exports = GuildBanAdd; diff --git a/node_modules/discord.js/src/client/actions/GuildBanRemove.js b/node_modules/discord.js/src/client/actions/GuildBanRemove.js new file mode 100644 index 0000000..8048efd --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildBanRemove.js @@ -0,0 +1,25 @@ +'use strict'; + +const Action = require('./Action'); +const GuildBan = require('../../structures/GuildBan'); +const Events = require('../../util/Events'); + +class GuildBanRemove extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + + /** + * Emitted whenever a member is unbanned from a guild. + * @event Client#guildBanRemove + * @param {GuildBan} ban The ban that was removed + */ + if (guild) { + const ban = guild.bans.cache.get(data.user.id) ?? new GuildBan(client, data, guild); + guild.bans.cache.delete(ban.user.id); + client.emit(Events.GuildBanRemove, ban); + } + } +} + +module.exports = GuildBanRemove; diff --git a/node_modules/discord.js/src/client/actions/GuildChannelsPositionUpdate.js b/node_modules/discord.js/src/client/actions/GuildChannelsPositionUpdate.js new file mode 100644 index 0000000..a393167 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildChannelsPositionUpdate.js @@ -0,0 +1,21 @@ +'use strict'; + +const Action = require('./Action'); + +class GuildChannelsPositionUpdate extends Action { + handle(data) { + const client = this.client; + + const guild = client.guilds.cache.get(data.guild_id); + if (guild) { + for (const partialChannel of data.channels) { + const channel = guild.channels.cache.get(partialChannel.id); + if (channel) channel.rawPosition = partialChannel.position; + } + } + + return { guild }; + } +} + +module.exports = GuildChannelsPositionUpdate; diff --git a/node_modules/discord.js/src/client/actions/GuildDelete.js b/node_modules/discord.js/src/client/actions/GuildDelete.js new file mode 100644 index 0000000..eb0a44d --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildDelete.js @@ -0,0 +1,44 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildDeleteAction extends Action { + handle(data) { + const client = this.client; + + let guild = client.guilds.cache.get(data.id); + if (guild) { + if (data.unavailable) { + // Guild is unavailable + guild.available = false; + + /** + * Emitted whenever a guild becomes unavailable, likely due to a server outage. + * @event Client#guildUnavailable + * @param {Guild} guild The guild that has become unavailable + */ + client.emit(Events.GuildUnavailable, guild); + + // Stops the GuildDelete packet thinking a guild was actually deleted, + // handles emitting of event itself + return; + } + + for (const channel of guild.channels.cache.values()) this.client.channels._remove(channel.id); + client.voice.adapters.get(data.id)?.destroy(); + + // Delete guild + client.guilds.cache.delete(guild.id); + + /** + * Emitted whenever a guild kicks the client or the guild is deleted/left. + * @event Client#guildDelete + * @param {Guild} guild The guild that was deleted + */ + client.emit(Events.GuildDelete, guild); + } + } +} + +module.exports = GuildDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/GuildEmojiCreate.js b/node_modules/discord.js/src/client/actions/GuildEmojiCreate.js new file mode 100644 index 0000000..61858cf --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildEmojiCreate.js @@ -0,0 +1,20 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildEmojiCreateAction extends Action { + handle(guild, createdEmoji) { + const already = guild.emojis.cache.has(createdEmoji.id); + const emoji = guild.emojis._add(createdEmoji); + /** + * Emitted whenever a custom emoji is created in a guild. + * @event Client#emojiCreate + * @param {GuildEmoji} emoji The emoji that was created + */ + if (!already) this.client.emit(Events.GuildEmojiCreate, emoji); + return { emoji }; + } +} + +module.exports = GuildEmojiCreateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildEmojiDelete.js b/node_modules/discord.js/src/client/actions/GuildEmojiDelete.js new file mode 100644 index 0000000..e3373c2 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildEmojiDelete.js @@ -0,0 +1,19 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildEmojiDeleteAction extends Action { + handle(emoji) { + emoji.guild.emojis.cache.delete(emoji.id); + /** + * Emitted whenever a custom emoji is deleted in a guild. + * @event Client#emojiDelete + * @param {GuildEmoji} emoji The emoji that was deleted + */ + this.client.emit(Events.GuildEmojiDelete, emoji); + return { emoji }; + } +} + +module.exports = GuildEmojiDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/GuildEmojiUpdate.js b/node_modules/discord.js/src/client/actions/GuildEmojiUpdate.js new file mode 100644 index 0000000..6bf9657 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildEmojiUpdate.js @@ -0,0 +1,20 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildEmojiUpdateAction extends Action { + handle(current, data) { + const old = current._update(data); + /** + * Emitted whenever a custom emoji is updated in a guild. + * @event Client#emojiUpdate + * @param {GuildEmoji} oldEmoji The old emoji + * @param {GuildEmoji} newEmoji The new emoji + */ + this.client.emit(Events.GuildEmojiUpdate, old, current); + return { emoji: current }; + } +} + +module.exports = GuildEmojiUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildEmojisUpdate.js b/node_modules/discord.js/src/client/actions/GuildEmojisUpdate.js new file mode 100644 index 0000000..7829db1 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildEmojisUpdate.js @@ -0,0 +1,34 @@ +'use strict'; + +const Action = require('./Action'); + +class GuildEmojisUpdateAction extends Action { + handle(data) { + const guild = this.client.guilds.cache.get(data.guild_id); + if (!guild?.emojis) return; + + const deletions = new Map(guild.emojis.cache); + + for (const emoji of data.emojis) { + // Determine type of emoji event + const cachedEmoji = guild.emojis.cache.get(emoji.id); + if (cachedEmoji) { + deletions.delete(emoji.id); + if (!cachedEmoji.equals(emoji)) { + // Emoji updated + this.client.actions.GuildEmojiUpdate.handle(cachedEmoji, emoji); + } + } else { + // Emoji added + this.client.actions.GuildEmojiCreate.handle(guild, emoji); + } + } + + for (const emoji of deletions.values()) { + // Emoji deleted + this.client.actions.GuildEmojiDelete.handle(emoji); + } + } +} + +module.exports = GuildEmojisUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildIntegrationsUpdate.js b/node_modules/discord.js/src/client/actions/GuildIntegrationsUpdate.js new file mode 100644 index 0000000..28b9bbb --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildIntegrationsUpdate.js @@ -0,0 +1,19 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildIntegrationsUpdate extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + /** + * Emitted whenever a guild integration is updated + * @event Client#guildIntegrationsUpdate + * @param {Guild} guild The guild whose integrations were updated + */ + if (guild) client.emit(Events.GuildIntegrationsUpdate, guild); + } +} + +module.exports = GuildIntegrationsUpdate; diff --git a/node_modules/discord.js/src/client/actions/GuildMemberRemove.js b/node_modules/discord.js/src/client/actions/GuildMemberRemove.js new file mode 100644 index 0000000..45eb6c4 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildMemberRemove.js @@ -0,0 +1,31 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); +const Status = require('../../util/Status'); + +class GuildMemberRemoveAction extends Action { + handle(data, shard) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + let member = null; + if (guild) { + member = this.getMember({ user: data.user }, guild); + guild.memberCount--; + if (member) { + guild.members.cache.delete(member.id); + /** + * Emitted whenever a member leaves a guild, or is kicked. + * @event Client#guildMemberRemove + * @param {GuildMember} member The member that has left/been kicked from the guild + */ + if (shard.status === Status.Ready) client.emit(Events.GuildMemberRemove, member); + } + guild.presences.cache.delete(data.user.id); + guild.voiceStates.cache.delete(data.user.id); + } + return { guild, member }; + } +} + +module.exports = GuildMemberRemoveAction; diff --git a/node_modules/discord.js/src/client/actions/GuildMemberUpdate.js b/node_modules/discord.js/src/client/actions/GuildMemberUpdate.js new file mode 100644 index 0000000..491b361 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildMemberUpdate.js @@ -0,0 +1,44 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); +const Status = require('../../util/Status'); + +class GuildMemberUpdateAction extends Action { + handle(data, shard) { + const { client } = this; + if (data.user.username) { + const user = client.users.cache.get(data.user.id); + if (!user) { + client.users._add(data.user); + } else if (!user._equals(data.user)) { + client.actions.UserUpdate.handle(data.user); + } + } + + const guild = client.guilds.cache.get(data.guild_id); + if (guild) { + const member = this.getMember({ user: data.user }, guild); + if (member) { + const old = member._update(data); + /** + * Emitted whenever a guild member changes - i.e. new role, removed role, nickname. + * @event Client#guildMemberUpdate + * @param {GuildMember} oldMember The member before the update + * @param {GuildMember} newMember The member after the update + */ + if (shard.status === Status.Ready && !member.equals(old)) client.emit(Events.GuildMemberUpdate, old, member); + } else { + const newMember = guild.members._add(data); + /** + * Emitted whenever a member becomes available. + * @event Client#guildMemberAvailable + * @param {GuildMember} member The member that became available + */ + this.client.emit(Events.GuildMemberAvailable, newMember); + } + } + } +} + +module.exports = GuildMemberUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildRoleCreate.js b/node_modules/discord.js/src/client/actions/GuildRoleCreate.js new file mode 100644 index 0000000..461443b --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildRoleCreate.js @@ -0,0 +1,25 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildRoleCreate extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + let role; + if (guild) { + const already = guild.roles.cache.has(data.role.id); + role = guild.roles._add(data.role); + /** + * Emitted whenever a role is created. + * @event Client#roleCreate + * @param {Role} role The role that was created + */ + if (!already) client.emit(Events.GuildRoleCreate, role); + } + return { role }; + } +} + +module.exports = GuildRoleCreate; diff --git a/node_modules/discord.js/src/client/actions/GuildRoleDelete.js b/node_modules/discord.js/src/client/actions/GuildRoleDelete.js new file mode 100644 index 0000000..e043a1a --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildRoleDelete.js @@ -0,0 +1,29 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildRoleDeleteAction extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + let role; + + if (guild) { + role = guild.roles.cache.get(data.role_id); + if (role) { + guild.roles.cache.delete(data.role_id); + /** + * Emitted whenever a guild role is deleted. + * @event Client#roleDelete + * @param {Role} role The role that was deleted + */ + client.emit(Events.GuildRoleDelete, role); + } + } + + return { role }; + } +} + +module.exports = GuildRoleDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/GuildRoleUpdate.js b/node_modules/discord.js/src/client/actions/GuildRoleUpdate.js new file mode 100644 index 0000000..b0632c5 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildRoleUpdate.js @@ -0,0 +1,39 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildRoleUpdateAction extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + + if (guild) { + let old = null; + + const role = guild.roles.cache.get(data.role.id); + if (role) { + old = role._update(data.role); + /** + * Emitted whenever a guild role is updated. + * @event Client#roleUpdate + * @param {Role} oldRole The role before the update + * @param {Role} newRole The role after the update + */ + client.emit(Events.GuildRoleUpdate, old, role); + } + + return { + old, + updated: role, + }; + } + + return { + old: null, + updated: null, + }; + } +} + +module.exports = GuildRoleUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildRolesPositionUpdate.js b/node_modules/discord.js/src/client/actions/GuildRolesPositionUpdate.js new file mode 100644 index 0000000..d7abca9 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildRolesPositionUpdate.js @@ -0,0 +1,21 @@ +'use strict'; + +const Action = require('./Action'); + +class GuildRolesPositionUpdate extends Action { + handle(data) { + const client = this.client; + + const guild = client.guilds.cache.get(data.guild_id); + if (guild) { + for (const partialRole of data.roles) { + const role = guild.roles.cache.get(partialRole.id); + if (role) role.rawPosition = partialRole.position; + } + } + + return { guild }; + } +} + +module.exports = GuildRolesPositionUpdate; diff --git a/node_modules/discord.js/src/client/actions/GuildScheduledEventCreate.js b/node_modules/discord.js/src/client/actions/GuildScheduledEventCreate.js new file mode 100644 index 0000000..0a2fb9b --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildScheduledEventCreate.js @@ -0,0 +1,27 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildScheduledEventCreateAction extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + if (guild) { + const guildScheduledEvent = guild.scheduledEvents._add(data); + + /** + * Emitted whenever a guild scheduled event is created. + * @event Client#guildScheduledEventCreate + * @param {GuildScheduledEvent} guildScheduledEvent The created guild scheduled event + */ + client.emit(Events.GuildScheduledEventCreate, guildScheduledEvent); + + return { guildScheduledEvent }; + } + + return {}; + } +} + +module.exports = GuildScheduledEventCreateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildScheduledEventDelete.js b/node_modules/discord.js/src/client/actions/GuildScheduledEventDelete.js new file mode 100644 index 0000000..636bfc5 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildScheduledEventDelete.js @@ -0,0 +1,31 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildScheduledEventDeleteAction extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + + if (guild) { + const guildScheduledEvent = this.getScheduledEvent(data, guild); + if (guildScheduledEvent) { + guild.scheduledEvents.cache.delete(guildScheduledEvent.id); + + /** + * Emitted whenever a guild scheduled event is deleted. + * @event Client#guildScheduledEventDelete + * @param {GuildScheduledEvent} guildScheduledEvent The deleted guild scheduled event + */ + client.emit(Events.GuildScheduledEventDelete, guildScheduledEvent); + + return { guildScheduledEvent }; + } + } + + return {}; + } +} + +module.exports = GuildScheduledEventDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/GuildScheduledEventUpdate.js b/node_modules/discord.js/src/client/actions/GuildScheduledEventUpdate.js new file mode 100644 index 0000000..7cabd85 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildScheduledEventUpdate.js @@ -0,0 +1,30 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildScheduledEventUpdateAction extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + + if (guild) { + const oldGuildScheduledEvent = guild.scheduledEvents.cache.get(data.id)?._clone() ?? null; + const newGuildScheduledEvent = guild.scheduledEvents._add(data); + + /** + * Emitted whenever a guild scheduled event gets updated. + * @event Client#guildScheduledEventUpdate + * @param {?GuildScheduledEvent} oldGuildScheduledEvent The guild scheduled event object before the update + * @param {GuildScheduledEvent} newGuildScheduledEvent The guild scheduled event object after the update + */ + client.emit(Events.GuildScheduledEventUpdate, oldGuildScheduledEvent, newGuildScheduledEvent); + + return { oldGuildScheduledEvent, newGuildScheduledEvent }; + } + + return {}; + } +} + +module.exports = GuildScheduledEventUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildScheduledEventUserAdd.js b/node_modules/discord.js/src/client/actions/GuildScheduledEventUserAdd.js new file mode 100644 index 0000000..03520db --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildScheduledEventUserAdd.js @@ -0,0 +1,32 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildScheduledEventUserAddAction extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + + if (guild) { + const guildScheduledEvent = this.getScheduledEvent(data, guild); + const user = this.getUser(data); + + if (guildScheduledEvent && user) { + /** + * Emitted whenever a user subscribes to a guild scheduled event + * @event Client#guildScheduledEventUserAdd + * @param {GuildScheduledEvent} guildScheduledEvent The guild scheduled event + * @param {User} user The user who subscribed + */ + client.emit(Events.GuildScheduledEventUserAdd, guildScheduledEvent, user); + + return { guildScheduledEvent, user }; + } + } + + return {}; + } +} + +module.exports = GuildScheduledEventUserAddAction; diff --git a/node_modules/discord.js/src/client/actions/GuildScheduledEventUserRemove.js b/node_modules/discord.js/src/client/actions/GuildScheduledEventUserRemove.js new file mode 100644 index 0000000..2a04849 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildScheduledEventUserRemove.js @@ -0,0 +1,32 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildScheduledEventUserRemoveAction extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + + if (guild) { + const guildScheduledEvent = this.getScheduledEvent(data, guild); + const user = this.getUser(data); + + if (guildScheduledEvent && user) { + /** + * Emitted whenever a user unsubscribes from a guild scheduled event + * @event Client#guildScheduledEventUserRemove + * @param {GuildScheduledEvent} guildScheduledEvent The guild scheduled event + * @param {User} user The user who unsubscribed + */ + client.emit(Events.GuildScheduledEventUserRemove, guildScheduledEvent, user); + + return { guildScheduledEvent, user }; + } + } + + return {}; + } +} + +module.exports = GuildScheduledEventUserRemoveAction; diff --git a/node_modules/discord.js/src/client/actions/GuildStickerCreate.js b/node_modules/discord.js/src/client/actions/GuildStickerCreate.js new file mode 100644 index 0000000..7d81de9 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildStickerCreate.js @@ -0,0 +1,20 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildStickerCreateAction extends Action { + handle(guild, createdSticker) { + const already = guild.stickers.cache.has(createdSticker.id); + const sticker = guild.stickers._add(createdSticker); + /** + * Emitted whenever a custom sticker is created in a guild. + * @event Client#stickerCreate + * @param {Sticker} sticker The sticker that was created + */ + if (!already) this.client.emit(Events.GuildStickerCreate, sticker); + return { sticker }; + } +} + +module.exports = GuildStickerCreateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildStickerDelete.js b/node_modules/discord.js/src/client/actions/GuildStickerDelete.js new file mode 100644 index 0000000..7fd6b57 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildStickerDelete.js @@ -0,0 +1,19 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildStickerDeleteAction extends Action { + handle(sticker) { + sticker.guild.stickers.cache.delete(sticker.id); + /** + * Emitted whenever a custom sticker is deleted in a guild. + * @event Client#stickerDelete + * @param {Sticker} sticker The sticker that was deleted + */ + this.client.emit(Events.GuildStickerDelete, sticker); + return { sticker }; + } +} + +module.exports = GuildStickerDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/GuildStickerUpdate.js b/node_modules/discord.js/src/client/actions/GuildStickerUpdate.js new file mode 100644 index 0000000..5561c7e --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildStickerUpdate.js @@ -0,0 +1,20 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildStickerUpdateAction extends Action { + handle(current, data) { + const old = current._update(data); + /** + * Emitted whenever a custom sticker is updated in a guild. + * @event Client#stickerUpdate + * @param {Sticker} oldSticker The old sticker + * @param {Sticker} newSticker The new sticker + */ + this.client.emit(Events.GuildStickerUpdate, old, current); + return { sticker: current }; + } +} + +module.exports = GuildStickerUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildStickersUpdate.js b/node_modules/discord.js/src/client/actions/GuildStickersUpdate.js new file mode 100644 index 0000000..ccf1d63 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildStickersUpdate.js @@ -0,0 +1,34 @@ +'use strict'; + +const Action = require('./Action'); + +class GuildStickersUpdateAction extends Action { + handle(data) { + const guild = this.client.guilds.cache.get(data.guild_id); + if (!guild?.stickers) return; + + const deletions = new Map(guild.stickers.cache); + + for (const sticker of data.stickers) { + // Determine type of sticker event + const cachedSticker = guild.stickers.cache.get(sticker.id); + if (cachedSticker) { + deletions.delete(sticker.id); + if (!cachedSticker.equals(sticker)) { + // Sticker updated + this.client.actions.GuildStickerUpdate.handle(cachedSticker, sticker); + } + } else { + // Sticker added + this.client.actions.GuildStickerCreate.handle(guild, sticker); + } + } + + for (const sticker of deletions.values()) { + // Sticker deleted + this.client.actions.GuildStickerDelete.handle(sticker); + } + } +} + +module.exports = GuildStickersUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/GuildUpdate.js b/node_modules/discord.js/src/client/actions/GuildUpdate.js new file mode 100644 index 0000000..ef1f51b --- /dev/null +++ b/node_modules/discord.js/src/client/actions/GuildUpdate.js @@ -0,0 +1,33 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class GuildUpdateAction extends Action { + handle(data) { + const client = this.client; + + const guild = client.guilds.cache.get(data.id); + if (guild) { + const old = guild._update(data); + /** + * Emitted whenever a guild is updated - e.g. name change. + * @event Client#guildUpdate + * @param {Guild} oldGuild The guild before the update + * @param {Guild} newGuild The guild after the update + */ + client.emit(Events.GuildUpdate, old, guild); + return { + old, + updated: guild, + }; + } + + return { + old: null, + updated: null, + }; + } +} + +module.exports = GuildUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/InteractionCreate.js b/node_modules/discord.js/src/client/actions/InteractionCreate.js new file mode 100644 index 0000000..434fb0c --- /dev/null +++ b/node_modules/discord.js/src/client/actions/InteractionCreate.js @@ -0,0 +1,101 @@ +'use strict'; + +const { InteractionType, ComponentType, ApplicationCommandType } = require('discord-api-types/v10'); +const Action = require('./Action'); +const AutocompleteInteraction = require('../../structures/AutocompleteInteraction'); +const ButtonInteraction = require('../../structures/ButtonInteraction'); +const ChannelSelectMenuInteraction = require('../../structures/ChannelSelectMenuInteraction'); +const ChatInputCommandInteraction = require('../../structures/ChatInputCommandInteraction'); +const MentionableSelectMenuInteraction = require('../../structures/MentionableSelectMenuInteraction'); +const MessageContextMenuCommandInteraction = require('../../structures/MessageContextMenuCommandInteraction'); +const ModalSubmitInteraction = require('../../structures/ModalSubmitInteraction'); +const RoleSelectMenuInteraction = require('../../structures/RoleSelectMenuInteraction'); +const StringSelectMenuInteraction = require('../../structures/StringSelectMenuInteraction'); +const UserContextMenuCommandInteraction = require('../../structures/UserContextMenuCommandInteraction'); +const UserSelectMenuInteraction = require('../../structures/UserSelectMenuInteraction'); +const Events = require('../../util/Events'); + +class InteractionCreateAction extends Action { + handle(data) { + const client = this.client; + + // Resolve and cache partial channels for Interaction#channel getter + const channel = data.channel && this.getChannel(data.channel); + + // Do not emit this for interactions that cache messages that are non-text-based. + let InteractionClass; + + switch (data.type) { + case InteractionType.ApplicationCommand: + switch (data.data.type) { + case ApplicationCommandType.ChatInput: + InteractionClass = ChatInputCommandInteraction; + break; + case ApplicationCommandType.User: + InteractionClass = UserContextMenuCommandInteraction; + break; + case ApplicationCommandType.Message: + if (channel && !channel.isTextBased()) return; + InteractionClass = MessageContextMenuCommandInteraction; + break; + default: + client.emit( + Events.Debug, + `[INTERACTION] Received application command interaction with unknown type: ${data.data.type}`, + ); + return; + } + break; + case InteractionType.MessageComponent: + if (channel && !channel.isTextBased()) return; + + switch (data.data.component_type) { + case ComponentType.Button: + InteractionClass = ButtonInteraction; + break; + case ComponentType.StringSelect: + InteractionClass = StringSelectMenuInteraction; + break; + case ComponentType.UserSelect: + InteractionClass = UserSelectMenuInteraction; + break; + case ComponentType.RoleSelect: + InteractionClass = RoleSelectMenuInteraction; + break; + case ComponentType.MentionableSelect: + InteractionClass = MentionableSelectMenuInteraction; + break; + case ComponentType.ChannelSelect: + InteractionClass = ChannelSelectMenuInteraction; + break; + default: + client.emit( + Events.Debug, + `[INTERACTION] Received component interaction with unknown type: ${data.data.component_type}`, + ); + return; + } + break; + case InteractionType.ApplicationCommandAutocomplete: + InteractionClass = AutocompleteInteraction; + break; + case InteractionType.ModalSubmit: + InteractionClass = ModalSubmitInteraction; + break; + default: + client.emit(Events.Debug, `[INTERACTION] Received interaction with unknown type: ${data.type}`); + return; + } + + const interaction = new InteractionClass(client, data); + + /** + * Emitted when an interaction is created. + * @event Client#interactionCreate + * @param {BaseInteraction} interaction The interaction which was created + */ + client.emit(Events.InteractionCreate, interaction); + } +} + +module.exports = InteractionCreateAction; diff --git a/node_modules/discord.js/src/client/actions/InviteCreate.js b/node_modules/discord.js/src/client/actions/InviteCreate.js new file mode 100644 index 0000000..dc03f07 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/InviteCreate.js @@ -0,0 +1,27 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class InviteCreateAction extends Action { + handle(data) { + const client = this.client; + const channel = client.channels.cache.get(data.channel_id); + const guild = client.guilds.cache.get(data.guild_id); + if (!channel) return false; + + const inviteData = Object.assign(data, { channel, guild }); + const invite = guild.invites._add(inviteData); + + /** + * Emitted when an invite is created. + * <info>This event requires the {@link PermissionFlagsBits.ManageChannels} permission for the channel.</info> + * @event Client#inviteCreate + * @param {Invite} invite The invite that was created + */ + client.emit(Events.InviteCreate, invite); + return { invite }; + } +} + +module.exports = InviteCreateAction; diff --git a/node_modules/discord.js/src/client/actions/InviteDelete.js b/node_modules/discord.js/src/client/actions/InviteDelete.js new file mode 100644 index 0000000..58be00c --- /dev/null +++ b/node_modules/discord.js/src/client/actions/InviteDelete.js @@ -0,0 +1,29 @@ +'use strict'; + +const Action = require('./Action'); +const Invite = require('../../structures/Invite'); +const Events = require('../../util/Events'); + +class InviteDeleteAction extends Action { + handle(data) { + const client = this.client; + const channel = client.channels.cache.get(data.channel_id); + const guild = client.guilds.cache.get(data.guild_id); + if (!channel) return false; + + const inviteData = Object.assign(data, { channel, guild }); + const invite = new Invite(client, inviteData); + guild.invites.cache.delete(invite.code); + + /** + * Emitted when an invite is deleted. + * <info>This event requires the {@link PermissionFlagsBits.ManageChannels} permission for the channel.</info> + * @event Client#inviteDelete + * @param {Invite} invite The invite that was deleted + */ + client.emit(Events.InviteDelete, invite); + return { invite }; + } +} + +module.exports = InviteDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/MessageCreate.js b/node_modules/discord.js/src/client/actions/MessageCreate.js new file mode 100644 index 0000000..8e011fc --- /dev/null +++ b/node_modules/discord.js/src/client/actions/MessageCreate.js @@ -0,0 +1,37 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class MessageCreateAction extends Action { + handle(data) { + const client = this.client; + const channel = this.getChannel(data); + if (channel) { + if (!channel.isTextBased()) return {}; + + if (channel.isThread()) { + channel.messageCount++; + channel.totalMessageSent++; + } + + const existing = channel.messages.cache.get(data.id); + if (existing) return { message: existing }; + const message = channel.messages._add(data); + channel.lastMessageId = data.id; + + /** + * Emitted whenever a message is created. + * @event Client#messageCreate + * @param {Message} message The created message + */ + client.emit(Events.MessageCreate, message); + + return { message }; + } + + return {}; + } +} + +module.exports = MessageCreateAction; diff --git a/node_modules/discord.js/src/client/actions/MessageDelete.js b/node_modules/discord.js/src/client/actions/MessageDelete.js new file mode 100644 index 0000000..f0c74d7 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/MessageDelete.js @@ -0,0 +1,32 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class MessageDeleteAction extends Action { + handle(data) { + const client = this.client; + const channel = this.getChannel(data); + let message; + if (channel) { + if (!channel.isTextBased()) return {}; + + if (channel.isThread()) channel.messageCount--; + + message = this.getMessage(data, channel); + if (message) { + channel.messages.cache.delete(message.id); + /** + * Emitted whenever a message is deleted. + * @event Client#messageDelete + * @param {Message} message The deleted message + */ + client.emit(Events.MessageDelete, message); + } + } + + return { message }; + } +} + +module.exports = MessageDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/MessageDeleteBulk.js b/node_modules/discord.js/src/client/actions/MessageDeleteBulk.js new file mode 100644 index 0000000..5f61d19 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/MessageDeleteBulk.js @@ -0,0 +1,47 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class MessageDeleteBulkAction extends Action { + handle(data) { + const client = this.client; + const channel = client.channels.cache.get(data.channel_id); + + if (channel) { + if (!channel.isTextBased()) return {}; + + if (channel.isThread()) channel.messageCount -= data.ids.length; + + const ids = data.ids; + const messages = new Collection(); + for (const id of ids) { + const message = this.getMessage( + { + id, + guild_id: data.guild_id, + }, + channel, + false, + ); + if (message) { + messages.set(message.id, message); + channel.messages.cache.delete(id); + } + } + + /** + * Emitted whenever messages are deleted in bulk. + * @event Client#messageDeleteBulk + * @param {Collection<Snowflake, Message>} messages The deleted messages, mapped by their id + * @param {GuildTextBasedChannel} channel The channel that the messages were deleted in + */ + if (messages.size > 0) client.emit(Events.MessageBulkDelete, messages, channel); + return { messages }; + } + return {}; + } +} + +module.exports = MessageDeleteBulkAction; diff --git a/node_modules/discord.js/src/client/actions/MessageReactionAdd.js b/node_modules/discord.js/src/client/actions/MessageReactionAdd.js new file mode 100644 index 0000000..ea97bd6 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/MessageReactionAdd.js @@ -0,0 +1,55 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); +const Partials = require('../../util/Partials'); + +/* +{ user_id: 'id', + message_id: 'id', + emoji: { name: '�', id: null }, + channel_id: 'id', + // If originating from a guild + guild_id: 'id', + member: { ..., user: { ... } } } +*/ + +class MessageReactionAdd extends Action { + handle(data, fromStructure = false) { + if (!data.emoji) return false; + + const user = this.getUserFromMember(data); + if (!user) return false; + + // Verify channel + const channel = this.getChannel(data); + if (!channel?.isTextBased()) return false; + + // Verify message + const message = this.getMessage(data, channel); + if (!message) return false; + + // Verify reaction + const includePartial = this.client.options.partials.includes(Partials.Reaction); + if (message.partial && !includePartial) return false; + const reaction = message.reactions._add({ + emoji: data.emoji, + count: message.partial ? null : 0, + me: user.id === this.client.user.id, + }); + if (!reaction) return false; + reaction._add(user); + if (fromStructure) return { message, reaction, user }; + /** + * Emitted whenever a reaction is added to a cached message. + * @event Client#messageReactionAdd + * @param {MessageReaction} messageReaction The reaction object + * @param {User} user The user that applied the guild or reaction emoji + */ + this.client.emit(Events.MessageReactionAdd, reaction, user); + + return { message, reaction, user }; + } +} + +module.exports = MessageReactionAdd; diff --git a/node_modules/discord.js/src/client/actions/MessageReactionRemove.js b/node_modules/discord.js/src/client/actions/MessageReactionRemove.js new file mode 100644 index 0000000..9ca3a8e --- /dev/null +++ b/node_modules/discord.js/src/client/actions/MessageReactionRemove.js @@ -0,0 +1,45 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +/* +{ user_id: 'id', + message_id: 'id', + emoji: { name: '�', id: null }, + channel_id: 'id', + guild_id: 'id' } +*/ + +class MessageReactionRemove extends Action { + handle(data) { + if (!data.emoji) return false; + + const user = this.getUser(data); + if (!user) return false; + + // Verify channel + const channel = this.getChannel(data); + if (!channel?.isTextBased()) return false; + + // Verify message + const message = this.getMessage(data, channel); + if (!message) return false; + + // Verify reaction + const reaction = this.getReaction(data, message, user); + if (!reaction) return false; + reaction._remove(user); + /** + * Emitted whenever a reaction is removed from a cached message. + * @event Client#messageReactionRemove + * @param {MessageReaction} messageReaction The reaction object + * @param {User} user The user whose emoji or reaction emoji was removed + */ + this.client.emit(Events.MessageReactionRemove, reaction, user); + + return { message, reaction, user }; + } +} + +module.exports = MessageReactionRemove; diff --git a/node_modules/discord.js/src/client/actions/MessageReactionRemoveAll.js b/node_modules/discord.js/src/client/actions/MessageReactionRemoveAll.js new file mode 100644 index 0000000..b1c023f --- /dev/null +++ b/node_modules/discord.js/src/client/actions/MessageReactionRemoveAll.js @@ -0,0 +1,33 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class MessageReactionRemoveAll extends Action { + handle(data) { + // Verify channel + const channel = this.getChannel(data); + if (!channel?.isTextBased()) return false; + + // Verify message + const message = this.getMessage(data, channel); + if (!message) return false; + + // Copy removed reactions to emit for the event. + const removed = message.reactions.cache.clone(); + + message.reactions.cache.clear(); + this.client.emit(Events.MessageReactionRemoveAll, message, removed); + + return { message }; + } +} + +/** + * Emitted whenever all reactions are removed from a cached message. + * @event Client#messageReactionRemoveAll + * @param {Message} message The message the reactions were removed from + * @param {Collection<string|Snowflake, MessageReaction>} reactions The cached message reactions that were removed. + */ + +module.exports = MessageReactionRemoveAll; diff --git a/node_modules/discord.js/src/client/actions/MessageReactionRemoveEmoji.js b/node_modules/discord.js/src/client/actions/MessageReactionRemoveEmoji.js new file mode 100644 index 0000000..3290214 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/MessageReactionRemoveEmoji.js @@ -0,0 +1,28 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class MessageReactionRemoveEmoji extends Action { + handle(data) { + const channel = this.getChannel(data); + if (!channel?.isTextBased()) return false; + + const message = this.getMessage(data, channel); + if (!message) return false; + + const reaction = this.getReaction(data, message); + if (!reaction) return false; + if (!message.partial) message.reactions.cache.delete(reaction.emoji.id ?? reaction.emoji.name); + + /** + * Emitted when a bot removes an emoji reaction from a cached message. + * @event Client#messageReactionRemoveEmoji + * @param {MessageReaction} reaction The reaction that was removed + */ + this.client.emit(Events.MessageReactionRemoveEmoji, reaction); + return { reaction }; + } +} + +module.exports = MessageReactionRemoveEmoji; diff --git a/node_modules/discord.js/src/client/actions/MessageUpdate.js b/node_modules/discord.js/src/client/actions/MessageUpdate.js new file mode 100644 index 0000000..fe757c0 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/MessageUpdate.js @@ -0,0 +1,26 @@ +'use strict'; + +const Action = require('./Action'); + +class MessageUpdateAction extends Action { + handle(data) { + const channel = this.getChannel(data); + if (channel) { + if (!channel.isTextBased()) return {}; + + const { id, channel_id, guild_id, author, timestamp, type } = data; + const message = this.getMessage({ id, channel_id, guild_id, author, timestamp, type }, channel); + if (message) { + const old = message._update(data); + return { + old, + updated: message, + }; + } + } + + return {}; + } +} + +module.exports = MessageUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/PresenceUpdate.js b/node_modules/discord.js/src/client/actions/PresenceUpdate.js new file mode 100644 index 0000000..0b4aaab --- /dev/null +++ b/node_modules/discord.js/src/client/actions/PresenceUpdate.js @@ -0,0 +1,42 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class PresenceUpdateAction extends Action { + handle(data) { + let user = this.client.users.cache.get(data.user.id); + if (!user && data.user.username) user = this.client.users._add(data.user); + if (!user) return; + + if (data.user.username) { + if (!user._equals(data.user)) this.client.actions.UserUpdate.handle(data.user); + } + + const guild = this.client.guilds.cache.get(data.guild_id); + if (!guild) return; + + const oldPresence = guild.presences.cache.get(user.id)?._clone() ?? null; + let member = guild.members.cache.get(user.id); + if (!member && data.status !== 'offline') { + member = guild.members._add({ + user, + deaf: false, + mute: false, + }); + this.client.emit(Events.GuildMemberAvailable, member); + } + const newPresence = guild.presences._add(Object.assign(data, { guild })); + if (this.client.listenerCount(Events.PresenceUpdate) && !newPresence.equals(oldPresence)) { + /** + * Emitted whenever a guild member's presence (e.g. status, activity) is changed. + * @event Client#presenceUpdate + * @param {?Presence} oldPresence The presence before the update, if one at all + * @param {Presence} newPresence The presence after the update + */ + this.client.emit(Events.PresenceUpdate, oldPresence, newPresence); + } + } +} + +module.exports = PresenceUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/StageInstanceCreate.js b/node_modules/discord.js/src/client/actions/StageInstanceCreate.js new file mode 100644 index 0000000..4edd530 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/StageInstanceCreate.js @@ -0,0 +1,28 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class StageInstanceCreateAction extends Action { + handle(data) { + const client = this.client; + const channel = this.getChannel(data); + + if (channel) { + const stageInstance = channel.guild.stageInstances._add(data); + + /** + * Emitted whenever a stage instance is created. + * @event Client#stageInstanceCreate + * @param {StageInstance} stageInstance The created stage instance + */ + client.emit(Events.StageInstanceCreate, stageInstance); + + return { stageInstance }; + } + + return {}; + } +} + +module.exports = StageInstanceCreateAction; diff --git a/node_modules/discord.js/src/client/actions/StageInstanceDelete.js b/node_modules/discord.js/src/client/actions/StageInstanceDelete.js new file mode 100644 index 0000000..0d5da38 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/StageInstanceDelete.js @@ -0,0 +1,31 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class StageInstanceDeleteAction extends Action { + handle(data) { + const client = this.client; + const channel = this.getChannel(data); + + if (channel) { + const stageInstance = channel.guild.stageInstances._add(data); + if (stageInstance) { + channel.guild.stageInstances.cache.delete(stageInstance.id); + + /** + * Emitted whenever a stage instance is deleted. + * @event Client#stageInstanceDelete + * @param {StageInstance} stageInstance The deleted stage instance + */ + client.emit(Events.StageInstanceDelete, stageInstance); + + return { stageInstance }; + } + } + + return {}; + } +} + +module.exports = StageInstanceDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/StageInstanceUpdate.js b/node_modules/discord.js/src/client/actions/StageInstanceUpdate.js new file mode 100644 index 0000000..008a53c --- /dev/null +++ b/node_modules/discord.js/src/client/actions/StageInstanceUpdate.js @@ -0,0 +1,30 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class StageInstanceUpdateAction extends Action { + handle(data) { + const client = this.client; + const channel = this.getChannel(data); + + if (channel) { + const oldStageInstance = channel.guild.stageInstances.cache.get(data.id)?._clone() ?? null; + const newStageInstance = channel.guild.stageInstances._add(data); + + /** + * Emitted whenever a stage instance gets updated - e.g. change in topic or privacy level + * @event Client#stageInstanceUpdate + * @param {?StageInstance} oldStageInstance The stage instance before the update + * @param {StageInstance} newStageInstance The stage instance after the update + */ + client.emit(Events.StageInstanceUpdate, oldStageInstance, newStageInstance); + + return { oldStageInstance, newStageInstance }; + } + + return {}; + } +} + +module.exports = StageInstanceUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/ThreadCreate.js b/node_modules/discord.js/src/client/actions/ThreadCreate.js new file mode 100644 index 0000000..a8ff6c6 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/ThreadCreate.js @@ -0,0 +1,24 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class ThreadCreateAction extends Action { + handle(data) { + const client = this.client; + const existing = client.channels.cache.has(data.id); + const thread = client.channels._add(data); + if (!existing && thread) { + /** + * Emitted whenever a thread is created or when the client user is added to a thread. + * @event Client#threadCreate + * @param {ThreadChannel} thread The thread that was created + * @param {boolean} newlyCreated Whether the thread was newly created + */ + client.emit(Events.ThreadCreate, thread, data.newly_created ?? false); + } + return { thread }; + } +} + +module.exports = ThreadCreateAction; diff --git a/node_modules/discord.js/src/client/actions/ThreadDelete.js b/node_modules/discord.js/src/client/actions/ThreadDelete.js new file mode 100644 index 0000000..3ec81a4 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/ThreadDelete.js @@ -0,0 +1,26 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class ThreadDeleteAction extends Action { + handle(data) { + const client = this.client; + const thread = client.channels.cache.get(data.id); + + if (thread) { + client.channels._remove(thread.id); + + /** + * Emitted whenever a thread is deleted. + * @event Client#threadDelete + * @param {ThreadChannel} thread The thread that was deleted + */ + client.emit(Events.ThreadDelete, thread); + } + + return { thread }; + } +} + +module.exports = ThreadDeleteAction; diff --git a/node_modules/discord.js/src/client/actions/ThreadListSync.js b/node_modules/discord.js/src/client/actions/ThreadListSync.js new file mode 100644 index 0000000..b16fb85 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/ThreadListSync.js @@ -0,0 +1,60 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class ThreadListSyncAction extends Action { + handle(data) { + const client = this.client; + + const guild = client.guilds.cache.get(data.guild_id); + if (!guild) return {}; + + if (data.channel_ids) { + for (const id of data.channel_ids) { + const channel = client.channels.resolve(id); + if (channel) this.removeStale(channel); + } + } else { + for (const channel of guild.channels.cache.values()) { + this.removeStale(channel); + } + } + + const syncedThreads = data.threads.reduce((coll, rawThread) => { + const thread = client.channels._add(rawThread); + return coll.set(thread.id, thread); + }, new Collection()); + + for (const rawMember of Object.values(data.members)) { + // Discord sends the thread id as id in this object + const thread = client.channels.cache.get(rawMember.id); + if (thread) { + thread.members._add(rawMember); + } + } + + /** + * Emitted whenever the client user gains access to a text or news channel that contains threads + * @event Client#threadListSync + * @param {Collection<Snowflake, ThreadChannel>} threads The threads that were synced + * @param {Guild} guild The guild that the threads were synced in + */ + client.emit(Events.ThreadListSync, syncedThreads, guild); + + return { + syncedThreads, + }; + } + + removeStale(channel) { + channel.threads?.cache.forEach(thread => { + if (!thread.archived) { + this.client.channels._remove(thread.id); + } + }); + } +} + +module.exports = ThreadListSyncAction; diff --git a/node_modules/discord.js/src/client/actions/ThreadMemberUpdate.js b/node_modules/discord.js/src/client/actions/ThreadMemberUpdate.js new file mode 100644 index 0000000..0b17f70 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/ThreadMemberUpdate.js @@ -0,0 +1,30 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class ThreadMemberUpdateAction extends Action { + handle(data) { + const client = this.client; + // Discord sends the thread id as id in this object + const thread = client.channels.cache.get(data.id); + if (thread) { + const member = thread.members.cache.get(data.user_id); + if (!member) { + const newMember = thread.members._add(data); + return { newMember }; + } + const old = member._update(data); + /** + * Emitted whenever the client user's thread member is updated. + * @event Client#threadMemberUpdate + * @param {ThreadMember} oldMember The member before the update + * @param {ThreadMember} newMember The member after the update + */ + client.emit(Events.ThreadMemberUpdate, old, member); + } + return {}; + } +} + +module.exports = ThreadMemberUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/ThreadMembersUpdate.js b/node_modules/discord.js/src/client/actions/ThreadMembersUpdate.js new file mode 100644 index 0000000..c1781b9 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/ThreadMembersUpdate.js @@ -0,0 +1,47 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class ThreadMembersUpdateAction extends Action { + handle(data) { + const client = this.client; + const thread = client.channels.cache.get(data.id); + if (thread) { + thread.memberCount = data.member_count; + const addedMembers = new Collection(); + const removedMembers = new Collection(); + + data.added_members?.reduce( + (_addedMembers, addedMember) => _addedMembers.set(addedMember.user_id, thread.members._add(addedMember)), + addedMembers, + ); + + data.removed_member_ids?.reduce((removedMembersIds, removedMembersId) => { + const threadMember = this.getThreadMember(removedMembersId, thread.members); + if (threadMember) removedMembersIds.set(threadMember.id, threadMember); + thread.members.cache.delete(removedMembersId); + return removedMembersIds; + }, removedMembers); + + if (addedMembers.size === 0 && removedMembers.size === 0) { + // Uncached thread member(s) left. + return {}; + } + + /** + * Emitted whenever members are added or removed from a thread. + * <info>This event requires the {@link GatewayIntentBits.GuildMembers} privileged gateway intent.</info> + * @event Client#threadMembersUpdate + * @param {Collection<Snowflake, ThreadMember>} addedMembers The members that were added + * @param {Collection<Snowflake, ThreadMember>} removedMembers The members that were removed + * @param {ThreadChannel} thread The thread where members got updated + */ + client.emit(Events.ThreadMembersUpdate, addedMembers, removedMembers, thread); + } + return {}; + } +} + +module.exports = ThreadMembersUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/TypingStart.js b/node_modules/discord.js/src/client/actions/TypingStart.js new file mode 100644 index 0000000..4e79920 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/TypingStart.js @@ -0,0 +1,29 @@ +'use strict'; + +const Action = require('./Action'); +const Typing = require('../../structures/Typing'); +const Events = require('../../util/Events'); + +class TypingStart extends Action { + handle(data) { + const channel = this.getChannel(data); + if (!channel) return; + + if (!channel.isTextBased()) { + this.client.emit(Events.Warn, `Discord sent a typing packet to a ${channel.type} channel ${channel.id}`); + return; + } + + const user = this.getUserFromMember(data); + if (user) { + /** + * Emitted whenever a user starts typing in a channel. + * @event Client#typingStart + * @param {Typing} typing The typing state + */ + this.client.emit(Events.TypingStart, new Typing(channel, user, data)); + } + } +} + +module.exports = TypingStart; diff --git a/node_modules/discord.js/src/client/actions/UserUpdate.js b/node_modules/discord.js/src/client/actions/UserUpdate.js new file mode 100644 index 0000000..923ddf5 --- /dev/null +++ b/node_modules/discord.js/src/client/actions/UserUpdate.js @@ -0,0 +1,36 @@ +'use strict'; + +const Action = require('./Action'); +const Events = require('../../util/Events'); + +class UserUpdateAction extends Action { + handle(data) { + const client = this.client; + + const newUser = data.id === client.user.id ? client.user : client.users.cache.get(data.id); + const oldUser = newUser._update(data); + + if (!oldUser.equals(newUser)) { + /** + * Emitted whenever a user's details (e.g. username) are changed. + * Triggered by the Discord gateway events {@link Events.UserUpdate}, + * {@link Events.GuildMemberUpdate}, and {@link Events.PresenceUpdate}. + * @event Client#userUpdate + * @param {User} oldUser The user before the update + * @param {User} newUser The user after the update + */ + client.emit(Events.UserUpdate, oldUser, newUser); + return { + old: oldUser, + updated: newUser, + }; + } + + return { + old: null, + updated: null, + }; + } +} + +module.exports = UserUpdateAction; diff --git a/node_modules/discord.js/src/client/actions/VoiceStateUpdate.js b/node_modules/discord.js/src/client/actions/VoiceStateUpdate.js new file mode 100644 index 0000000..fc7400f --- /dev/null +++ b/node_modules/discord.js/src/client/actions/VoiceStateUpdate.js @@ -0,0 +1,43 @@ +'use strict'; + +const Action = require('./Action'); +const VoiceState = require('../../structures/VoiceState'); +const Events = require('../../util/Events'); + +class VoiceStateUpdate extends Action { + handle(data) { + const client = this.client; + const guild = client.guilds.cache.get(data.guild_id); + if (guild) { + // Update the state + const oldState = + guild.voiceStates.cache.get(data.user_id)?._clone() ?? new VoiceState(guild, { user_id: data.user_id }); + + const newState = guild.voiceStates._add(data); + + // Get the member + let member = guild.members.cache.get(data.user_id); + if (member && data.member) { + member._patch(data.member); + } else if (data.member?.user && data.member.joined_at) { + member = guild.members._add(data.member); + } + + // Emit event + if (member?.user.id === client.user.id) { + client.emit('debug', `[VOICE] received voice state update: ${JSON.stringify(data)}`); + client.voice.onVoiceStateUpdate(data); + } + + /** + * Emitted whenever a member changes voice state - e.g. joins/leaves a channel, mutes/unmutes. + * @event Client#voiceStateUpdate + * @param {VoiceState} oldState The voice state before the update + * @param {VoiceState} newState The voice state after the update + */ + client.emit(Events.VoiceStateUpdate, oldState, newState); + } + } +} + +module.exports = VoiceStateUpdate; diff --git a/node_modules/discord.js/src/client/actions/WebhooksUpdate.js b/node_modules/discord.js/src/client/actions/WebhooksUpdate.js new file mode 100644 index 0000000..2bf41ba --- /dev/null +++ b/node_modules/discord.js/src/client/actions/WebhooksUpdate.js @@ -0,0 +1,37 @@ +'use strict'; + +const process = require('node:process'); +const Action = require('./Action'); + +let deprecationEmitted = false; + +class WebhooksUpdate extends Action { + handle(data) { + const client = this.client; + const channel = client.channels.cache.get(data.channel_id); + if (!channel) return; + + // TODO: change to Events.WebhooksUpdate in the next major version + /** + * Emitted whenever a channel has its webhooks changed. + * @event Client#webhooksUpdate + * @param {TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel} channel + * The channel that had a webhook update + */ + client.emit('webhooksUpdate', channel); + + /** + * Emitted whenever a channel has its webhooks changed. + * @event Client#webhookUpdate + * @param {TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel} channel + * The channel that had a webhook update + * @deprecated Use {@link Client#event:webhooksUpdate} instead. + */ + if (client.emit('webhookUpdate', channel) && !deprecationEmitted) { + deprecationEmitted = true; + process.emitWarning('The webhookUpdate event is deprecated. Use webhooksUpdate instead.', 'DeprecationWarning'); + } + } +} + +module.exports = WebhooksUpdate; diff --git a/node_modules/discord.js/src/client/voice/ClientVoiceManager.js b/node_modules/discord.js/src/client/voice/ClientVoiceManager.js new file mode 100644 index 0000000..192e700 --- /dev/null +++ b/node_modules/discord.js/src/client/voice/ClientVoiceManager.js @@ -0,0 +1,44 @@ +'use strict'; + +const Events = require('../../util/Events'); + +/** + * Manages voice connections for the client + */ +class ClientVoiceManager { + constructor(client) { + /** + * The client that instantiated this voice manager + * @type {Client} + * @readonly + * @name ClientVoiceManager#client + */ + Object.defineProperty(this, 'client', { value: client }); + + /** + * Maps guild ids to voice adapters created for use with @discordjs/voice. + * @type {Map<Snowflake, Object>} + */ + this.adapters = new Map(); + + client.on(Events.ShardDisconnect, (_, shardId) => { + for (const [guildId, adapter] of this.adapters.entries()) { + if (client.guilds.cache.get(guildId)?.shardId === shardId) { + adapter.destroy(); + } + } + }); + } + + onVoiceServer(payload) { + this.adapters.get(payload.guild_id)?.onVoiceServerUpdate(payload); + } + + onVoiceStateUpdate(payload) { + if (payload.guild_id && payload.session_id && payload.user_id === this.client.user?.id) { + this.adapters.get(payload.guild_id)?.onVoiceStateUpdate(payload); + } + } +} + +module.exports = ClientVoiceManager; diff --git a/node_modules/discord.js/src/client/websocket/WebSocketManager.js b/node_modules/discord.js/src/client/websocket/WebSocketManager.js new file mode 100644 index 0000000..f62610b --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/WebSocketManager.js @@ -0,0 +1,394 @@ +'use strict'; + +const EventEmitter = require('node:events'); +const process = require('node:process'); +const { setImmediate } = require('node:timers'); +const { Collection } = require('@discordjs/collection'); +const { + WebSocketManager: WSWebSocketManager, + WebSocketShardEvents: WSWebSocketShardEvents, + CompressionMethod, + CloseCodes, +} = require('@discordjs/ws'); +const { GatewayCloseCodes, GatewayDispatchEvents } = require('discord-api-types/v10'); +const WebSocketShard = require('./WebSocketShard'); +const PacketHandlers = require('./handlers'); +const { DiscordjsError, ErrorCodes } = require('../../errors'); +const Events = require('../../util/Events'); +const Status = require('../../util/Status'); +const WebSocketShardEvents = require('../../util/WebSocketShardEvents'); + +let zlib; + +try { + zlib = require('zlib-sync'); +} catch {} // eslint-disable-line no-empty + +const BeforeReadyWhitelist = [ + GatewayDispatchEvents.Ready, + GatewayDispatchEvents.Resumed, + GatewayDispatchEvents.GuildCreate, + GatewayDispatchEvents.GuildDelete, + GatewayDispatchEvents.GuildMembersChunk, + GatewayDispatchEvents.GuildMemberAdd, + GatewayDispatchEvents.GuildMemberRemove, +]; + +const WaitingForGuildEvents = [GatewayDispatchEvents.GuildCreate, GatewayDispatchEvents.GuildDelete]; + +const UNRESUMABLE_CLOSE_CODES = [ + CloseCodes.Normal, + GatewayCloseCodes.AlreadyAuthenticated, + GatewayCloseCodes.InvalidSeq, +]; + +const reasonIsDeprecated = 'the reason property is deprecated, use the code property to determine the reason'; +let deprecationEmittedForInvalidSessionEvent = false; +let deprecationEmittedForDestroyedEvent = false; + +/** + * The WebSocket manager for this client. + * <info>This class forwards raw dispatch events, + * read more about it here {@link https://discord.com/developers/docs/topics/gateway}</info> + * @extends {EventEmitter} + */ +class WebSocketManager extends EventEmitter { + constructor(client) { + super(); + + /** + * The client that instantiated this WebSocketManager + * @type {Client} + * @readonly + * @name WebSocketManager#client + */ + Object.defineProperty(this, 'client', { value: client }); + + /** + * The gateway this manager uses + * @type {?string} + */ + this.gateway = null; + + /** + * A collection of all shards this manager handles + * @type {Collection<number, WebSocketShard>} + */ + this.shards = new Collection(); + + /** + * An array of queued events before this WebSocketManager became ready + * @type {Object[]} + * @private + * @name WebSocketManager#packetQueue + */ + Object.defineProperty(this, 'packetQueue', { value: [] }); + + /** + * The current status of this WebSocketManager + * @type {Status} + */ + this.status = Status.Idle; + + /** + * If this manager was destroyed. It will prevent shards from reconnecting + * @type {boolean} + * @private + */ + this.destroyed = false; + + /** + * The internal WebSocketManager from `@discordjs/ws`. + * @type {WSWebSocketManager} + * @private + */ + this._ws = null; + } + + /** + * The average ping of all WebSocketShards + * @type {number} + * @readonly + */ + get ping() { + const sum = this.shards.reduce((a, b) => a + b.ping, 0); + return sum / this.shards.size; + } + + /** + * Emits a debug message. + * @param {string} message The debug message + * @param {?number} [shardId] The id of the shard that emitted this message, if any + * @private + */ + debug(message, shardId) { + this.client.emit( + Events.Debug, + `[WS => ${typeof shardId === 'number' ? `Shard ${shardId}` : 'Manager'}] ${message}`, + ); + } + + /** + * Connects this manager to the gateway. + * @private + */ + async connect() { + const invalidToken = new DiscordjsError(ErrorCodes.TokenInvalid); + const { shards, shardCount, intents, ws } = this.client.options; + if (this._ws && this._ws.options.token !== this.client.token) { + await this._ws.destroy({ code: CloseCodes.Normal, reason: 'Login with differing token requested' }); + this._ws = null; + } + if (!this._ws) { + const wsOptions = { + intents: intents.bitfield, + rest: this.client.rest, + token: this.client.token, + largeThreshold: ws.large_threshold, + version: ws.version, + shardIds: shards === 'auto' ? null : shards, + shardCount: shards === 'auto' ? null : shardCount, + initialPresence: ws.presence, + retrieveSessionInfo: shardId => this.shards.get(shardId).sessionInfo, + updateSessionInfo: (shardId, sessionInfo) => { + this.shards.get(shardId).sessionInfo = sessionInfo; + }, + compression: zlib ? CompressionMethod.ZlibStream : null, + }; + if (ws.buildIdentifyThrottler) wsOptions.buildIdentifyThrottler = ws.buildIdentifyThrottler; + if (ws.buildStrategy) wsOptions.buildStrategy = ws.buildStrategy; + this._ws = new WSWebSocketManager(wsOptions); + this.attachEvents(); + } + + const { + url: gatewayURL, + shards: recommendedShards, + session_start_limit: sessionStartLimit, + } = await this._ws.fetchGatewayInformation().catch(error => { + throw error.status === 401 ? invalidToken : error; + }); + + const { total, remaining } = sessionStartLimit; + + this.debug(`Fetched Gateway Information + URL: ${gatewayURL} + Recommended Shards: ${recommendedShards}`); + + this.debug(`Session Limit Information + Total: ${total} + Remaining: ${remaining}`); + + this.gateway = `${gatewayURL}/`; + + this.client.options.shardCount = await this._ws.getShardCount(); + this.client.options.shards = await this._ws.getShardIds(); + this.totalShards = this.client.options.shards.length; + for (const id of this.client.options.shards) { + if (!this.shards.has(id)) { + const shard = new WebSocketShard(this, id); + this.shards.set(id, shard); + + shard.on(WebSocketShardEvents.AllReady, unavailableGuilds => { + /** + * Emitted when a shard turns ready. + * @event Client#shardReady + * @param {number} id The shard id that turned ready + * @param {?Set<Snowflake>} unavailableGuilds Set of unavailable guild ids, if any + */ + this.client.emit(Events.ShardReady, shard.id, unavailableGuilds); + + this.checkShardsReady(); + }); + shard.status = Status.Connecting; + } + } + + await this._ws.connect(); + + this.shards.forEach(shard => { + if (shard.listenerCount(WebSocketShardEvents.InvalidSession) > 0 && !deprecationEmittedForInvalidSessionEvent) { + process.emitWarning( + 'The WebSocketShard#invalidSession event is deprecated and will never emit.', + 'DeprecationWarning', + ); + + deprecationEmittedForInvalidSessionEvent = true; + } + if (shard.listenerCount(WebSocketShardEvents.Destroyed) > 0 && !deprecationEmittedForDestroyedEvent) { + process.emitWarning( + 'The WebSocketShard#destroyed event is deprecated and will never emit.', + 'DeprecationWarning', + ); + + deprecationEmittedForDestroyedEvent = true; + } + }); + } + + /** + * Attaches event handlers to the internal WebSocketShardManager from `@discordjs/ws`. + * @private + */ + attachEvents() { + this._ws.on(WSWebSocketShardEvents.Debug, ({ message, shardId }) => this.debug(message, shardId)); + this._ws.on(WSWebSocketShardEvents.Dispatch, ({ data, shardId }) => { + this.client.emit(Events.Raw, data, shardId); + this.emit(data.t, data.d, shardId); + const shard = this.shards.get(shardId); + this.handlePacket(data, shard); + if (shard.status === Status.WaitingForGuilds && WaitingForGuildEvents.includes(data.t)) { + shard.gotGuild(data.d.id); + } + }); + + this._ws.on(WSWebSocketShardEvents.Ready, ({ data, shardId }) => { + this.shards.get(shardId).onReadyPacket(data); + }); + + this._ws.on(WSWebSocketShardEvents.Closed, ({ code, shardId }) => { + const shard = this.shards.get(shardId); + shard.emit(WebSocketShardEvents.Close, { code, reason: reasonIsDeprecated, wasClean: true }); + if (UNRESUMABLE_CLOSE_CODES.includes(code) && this.destroyed) { + shard.status = Status.Disconnected; + /** + * Emitted when a shard's WebSocket disconnects and will no longer reconnect. + * @event Client#shardDisconnect + * @param {CloseEvent} event The WebSocket close event + * @param {number} id The shard id that disconnected + */ + this.client.emit(Events.ShardDisconnect, { code, reason: reasonIsDeprecated, wasClean: true }, shardId); + this.debug(GatewayCloseCodes[code], shardId); + return; + } + + this.shards.get(shardId).status = Status.Connecting; + /** + * Emitted when a shard is attempting to reconnect or re-identify. + * @event Client#shardReconnecting + * @param {number} id The shard id that is attempting to reconnect + */ + this.client.emit(Events.ShardReconnecting, shardId); + }); + this._ws.on(WSWebSocketShardEvents.Hello, ({ shardId }) => { + const shard = this.shards.get(shardId); + if (shard.sessionInfo) { + shard.closeSequence = shard.sessionInfo.sequence; + shard.status = Status.Resuming; + } else { + shard.status = Status.Identifying; + } + }); + + this._ws.on(WSWebSocketShardEvents.Resumed, ({ shardId }) => { + const shard = this.shards.get(shardId); + shard.status = Status.Ready; + /** + * Emitted when the shard resumes successfully + * @event WebSocketShard#resumed + */ + shard.emit(WebSocketShardEvents.Resumed); + }); + + this._ws.on(WSWebSocketShardEvents.HeartbeatComplete, ({ heartbeatAt, latency, shardId }) => { + this.debug(`Heartbeat acknowledged, latency of ${latency}ms.`, shardId); + const shard = this.shards.get(shardId); + shard.lastPingTimestamp = heartbeatAt; + shard.ping = latency; + }); + + this._ws.on(WSWebSocketShardEvents.Error, ({ error, shardId }) => { + /** + * Emitted whenever a shard's WebSocket encounters a connection error. + * @event Client#shardError + * @param {Error} error The encountered error + * @param {number} shardId The shard that encountered this error + */ + this.client.emit(Events.ShardError, error, shardId); + }); + } + + /** + * Broadcasts a packet to every shard this manager handles. + * @param {Object} packet The packet to send + * @private + */ + broadcast(packet) { + for (const shardId of this.shards.keys()) this._ws.send(shardId, packet); + } + + /** + * Destroys this manager and all its shards. + * @private + */ + async destroy() { + if (this.destroyed) return; + // TODO: Make a util for getting a stack + this.debug(`Manager was destroyed. Called by:\n${new Error().stack}`); + this.destroyed = true; + await this._ws?.destroy({ code: CloseCodes.Normal }); + } + + /** + * Processes a packet and queues it if this WebSocketManager is not ready. + * @param {Object} [packet] The packet to be handled + * @param {WebSocketShard} [shard] The shard that will handle this packet + * @returns {boolean} + * @private + */ + handlePacket(packet, shard) { + if (packet && this.status !== Status.Ready) { + if (!BeforeReadyWhitelist.includes(packet.t)) { + this.packetQueue.push({ packet, shard }); + return false; + } + } + + if (this.packetQueue.length) { + const item = this.packetQueue.shift(); + setImmediate(() => { + this.handlePacket(item.packet, item.shard); + }).unref(); + } + + if (packet && PacketHandlers[packet.t]) { + PacketHandlers[packet.t](this.client, packet, shard); + } + + return true; + } + + /** + * Checks whether the client is ready to be marked as ready. + * @private + */ + checkShardsReady() { + if (this.status === Status.Ready) return; + if (this.shards.size !== this.totalShards || this.shards.some(s => s.status !== Status.Ready)) { + return; + } + + this.triggerClientReady(); + } + + /** + * Causes the client to be marked as ready and emits the ready event. + * @private + */ + triggerClientReady() { + this.status = Status.Ready; + + this.client.readyTimestamp = Date.now(); + + /** + * Emitted when the client becomes ready to start working. + * @event Client#ready + * @param {Client} client The client + */ + this.client.emit(Events.ClientReady, this.client); + + this.handlePacket(); + } +} + +module.exports = WebSocketManager; diff --git a/node_modules/discord.js/src/client/websocket/WebSocketShard.js b/node_modules/discord.js/src/client/websocket/WebSocketShard.js new file mode 100644 index 0000000..05bc225 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/WebSocketShard.js @@ -0,0 +1,231 @@ +'use strict'; + +const EventEmitter = require('node:events'); +const process = require('node:process'); +const { setTimeout, clearTimeout } = require('node:timers'); +const { GatewayIntentBits } = require('discord-api-types/v10'); +const Status = require('../../util/Status'); +const WebSocketShardEvents = require('../../util/WebSocketShardEvents'); + +let deprecationEmittedForImportant = false; +/** + * Represents a Shard's WebSocket connection + * @extends {EventEmitter} + */ +class WebSocketShard extends EventEmitter { + constructor(manager, id) { + super(); + + /** + * The WebSocketManager of the shard + * @type {WebSocketManager} + */ + this.manager = manager; + + /** + * The shard's id + * @type {number} + */ + this.id = id; + + /** + * The current status of the shard + * @type {Status} + */ + this.status = Status.Idle; + + /** + * The sequence of the shard after close + * @type {number} + * @private + */ + this.closeSequence = 0; + + /** + * The previous heartbeat ping of the shard + * @type {number} + */ + this.ping = -1; + + /** + * The last time a ping was sent (a timestamp) + * @type {number} + */ + this.lastPingTimestamp = -1; + + /** + * A set of guild ids this shard expects to receive + * @name WebSocketShard#expectedGuilds + * @type {?Set<string>} + * @private + */ + Object.defineProperty(this, 'expectedGuilds', { value: null, writable: true }); + + /** + * The ready timeout + * @name WebSocketShard#readyTimeout + * @type {?NodeJS.Timeout} + * @private + */ + Object.defineProperty(this, 'readyTimeout', { value: null, writable: true }); + + /** + * @external SessionInfo + * @see {@link https://discord.js.org/docs/packages/ws/stable/SessionInfo:Interface} + */ + + /** + * The session info used by `@discordjs/ws` package. + * @name WebSocketShard#sessionInfo + * @type {?SessionInfo} + * @private + */ + Object.defineProperty(this, 'sessionInfo', { value: null, writable: true }); + } + + /** + * Emits a debug event. + * @param {string} message The debug message + * @private + */ + debug(message) { + this.manager.debug(message, this.id); + } + + /** + * @external CloseEvent + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent} + */ + + /** + * This method is responsible to emit close event for this shard. + * This method helps the shard reconnect. + * @param {CloseEvent} [event] Close event that was received + * @deprecated + */ + emitClose( + event = { + code: 1011, + reason: 'INTERNAL_ERROR', + wasClean: false, + }, + ) { + this.debug(`[CLOSE] + Event Code: ${event.code} + Clean : ${event.wasClean} + Reason : ${event.reason ?? 'No reason received'}`); + /** + * Emitted when a shard's WebSocket closes. + * @private + * @event WebSocketShard#close + * @param {CloseEvent} event The received event + */ + this.emit(WebSocketShardEvents.Close, event); + } + + /** + * Called when the shard receives the READY payload. + * @param {Object} packet The received packet + * @private + */ + onReadyPacket(packet) { + if (!packet) { + this.debug(`Received broken packet: '${packet}'.`); + return; + } + + /** + * Emitted when the shard receives the READY payload and is now waiting for guilds + * @event WebSocketShard#ready + */ + this.emit(WebSocketShardEvents.Ready); + + this.expectedGuilds = new Set(packet.guilds.map(d => d.id)); + this.status = Status.WaitingForGuilds; + } + + /** + * Called when a GuildCreate or GuildDelete for this shard was sent after READY payload was received, + * but before we emitted the READY event. + * @param {Snowflake} guildId the id of the Guild sent in the payload + * @private + */ + gotGuild(guildId) { + this.expectedGuilds.delete(guildId); + this.checkReady(); + } + + /** + * Checks if the shard can be marked as ready + * @private + */ + checkReady() { + // Step 0. Clear the ready timeout, if it exists + if (this.readyTimeout) { + clearTimeout(this.readyTimeout); + this.readyTimeout = null; + } + // Step 1. If we don't have any other guilds pending, we are ready + if (!this.expectedGuilds.size) { + this.debug('Shard received all its guilds. Marking as fully ready.'); + this.status = Status.Ready; + + /** + * Emitted when the shard is fully ready. + * This event is emitted if: + * * all guilds were received by this shard + * * the ready timeout expired, and some guilds are unavailable + * @event WebSocketShard#allReady + * @param {?Set<string>} unavailableGuilds Set of unavailable guilds, if any + */ + this.emit(WebSocketShardEvents.AllReady); + return; + } + const hasGuildsIntent = this.manager.client.options.intents.has(GatewayIntentBits.Guilds); + // Step 2. Create a timeout that will mark the shard as ready if there are still unavailable guilds + // * The timeout is 15 seconds by default + // * This can be optionally changed in the client options via the `waitGuildTimeout` option + // * a timeout time of zero will skip this timeout, which potentially could cause the Client to miss guilds. + + const { waitGuildTimeout } = this.manager.client.options; + + this.readyTimeout = setTimeout( + () => { + this.debug( + `Shard ${hasGuildsIntent ? 'did' : 'will'} not receive any more guild packets` + + `${hasGuildsIntent ? ` in ${waitGuildTimeout} ms` : ''}.\nUnavailable guild count: ${ + this.expectedGuilds.size + }`, + ); + + this.readyTimeout = null; + this.status = Status.Ready; + + this.emit(WebSocketShardEvents.AllReady, this.expectedGuilds); + }, + hasGuildsIntent ? waitGuildTimeout : 0, + ).unref(); + } + + /** + * Adds a packet to the queue to be sent to the gateway. + * <warn>If you use this method, make sure you understand that you need to provide + * a full [Payload](https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-commands). + * Do not use this method if you don't know what you're doing.</warn> + * @param {Object} data The full packet to send + * @param {boolean} [important=false] If this packet should be added first in queue + * <warn>This parameter is **deprecated**. Important payloads are determined by their opcode instead.</warn> + */ + send(data, important = false) { + if (important && !deprecationEmittedForImportant) { + process.emitWarning( + 'Sending important payloads explicitly is deprecated. They are determined by their opcode implicitly now.', + 'DeprecationWarning', + ); + deprecationEmittedForImportant = true; + } + this.manager._ws.send(this.id, data); + } +} + +module.exports = WebSocketShard; diff --git a/node_modules/discord.js/src/client/websocket/handlers/APPLICATION_COMMAND_PERMISSIONS_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/APPLICATION_COMMAND_PERMISSIONS_UPDATE.js new file mode 100644 index 0000000..73d4ec4 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/APPLICATION_COMMAND_PERMISSIONS_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.ApplicationCommandPermissionsUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js b/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js new file mode 100644 index 0000000..22463b6 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.AutoModerationActionExecution.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js new file mode 100644 index 0000000..af64b9c --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.AutoModerationRuleCreate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js b/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js new file mode 100644 index 0000000..56ec504 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.AutoModerationRuleDelete.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js new file mode 100644 index 0000000..3caf6ba --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.AutoModerationRuleUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_CREATE.js new file mode 100644 index 0000000..d6d560d --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_CREATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.ChannelCreate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_DELETE.js b/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_DELETE.js new file mode 100644 index 0000000..cb9f3d8 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_DELETE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.ChannelDelete.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js new file mode 100644 index 0000000..c46e527 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js @@ -0,0 +1,22 @@ +'use strict'; + +const Events = require('../../../util/Events'); + +module.exports = (client, { d: data }) => { + const channel = client.channels.cache.get(data.channel_id); + const time = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null; + + if (channel) { + // Discord sends null for last_pin_timestamp if the last pinned message was removed + channel.lastPinTimestamp = time; + + /** + * Emitted whenever the pins of a channel are updated. Due to the nature of the WebSocket event, + * not much information can be provided easily here - you need to manually check the pins yourself. + * @event Client#channelPinsUpdate + * @param {TextBasedChannels} channel The channel that the pins update occurred in + * @param {Date} time The time of the pins update + */ + client.emit(Events.ChannelPinsUpdate, channel, time); + } +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_UPDATE.js new file mode 100644 index 0000000..8f35121 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/CHANNEL_UPDATE.js @@ -0,0 +1,16 @@ +'use strict'; + +const Events = require('../../../util/Events'); + +module.exports = (client, packet) => { + const { old, updated } = client.actions.ChannelUpdate.handle(packet.d); + if (old && updated) { + /** + * Emitted whenever a channel is updated - e.g. name change, topic change, channel type change. + * @event Client#channelUpdate + * @param {DMChannel|GuildChannel} oldChannel The channel before the update + * @param {DMChannel|GuildChannel} newChannel The channel after the update + */ + client.emit(Events.ChannelUpdate, old, updated); + } +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_AUDIT_LOG_ENTRY_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_AUDIT_LOG_ENTRY_CREATE.js new file mode 100644 index 0000000..8623141 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_AUDIT_LOG_ENTRY_CREATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildAuditLogEntryCreate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_BAN_ADD.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_BAN_ADD.js new file mode 100644 index 0000000..d8dc0f9 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_BAN_ADD.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildBanAdd.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_BAN_REMOVE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_BAN_REMOVE.js new file mode 100644 index 0000000..8389e46 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_BAN_REMOVE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildBanRemove.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_CREATE.js new file mode 100644 index 0000000..141f0ab --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_CREATE.js @@ -0,0 +1,33 @@ +'use strict'; + +const Events = require('../../../util/Events'); +const Status = require('../../../util/Status'); + +module.exports = (client, { d: data }, shard) => { + let guild = client.guilds.cache.get(data.id); + if (guild) { + if (!guild.available && !data.unavailable) { + // A newly available guild + guild._patch(data); + + /** + * Emitted whenever a guild becomes available. + * @event Client#guildAvailable + * @param {Guild} guild The guild that became available + */ + client.emit(Events.GuildAvailable, guild); + } + } else { + // A new guild + data.shardId = shard.id; + guild = client.guilds._add(data); + if (client.ws.status === Status.Ready) { + /** + * Emitted whenever the client joins a guild. + * @event Client#guildCreate + * @param {Guild} guild The created guild + */ + client.emit(Events.GuildCreate, guild); + } + } +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_DELETE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_DELETE.js new file mode 100644 index 0000000..27a3256 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_DELETE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildDelete.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_EMOJIS_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_EMOJIS_UPDATE.js new file mode 100644 index 0000000..e23b671 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_EMOJIS_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildEmojisUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_INTEGRATIONS_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_INTEGRATIONS_UPDATE.js new file mode 100644 index 0000000..e90a72c --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_INTEGRATIONS_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildIntegrationsUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js new file mode 100644 index 0000000..2f61a1e --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js @@ -0,0 +1,39 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Events = require('../../../util/Events'); + +module.exports = (client, { d: data }) => { + const guild = client.guilds.cache.get(data.guild_id); + if (!guild) return; + const members = new Collection(); + + for (const member of data.members) members.set(member.user.id, guild.members._add(member)); + if (data.presences) { + for (const presence of data.presences) guild.presences._add(Object.assign(presence, { guild })); + } + + /** + * Represents the properties of a guild members chunk + * @typedef {Object} GuildMembersChunk + * @property {number} index Index of the received chunk + * @property {number} count Number of chunks the client should receive + * @property {Array<*>} notFound An array of whatever could not be found + * when using {@link GatewayOpcodes.RequestGuildMembers} + * @property {?string} nonce Nonce for this chunk + */ + + /** + * Emitted whenever a chunk of guild members is received (all members come from the same guild). + * @event Client#guildMembersChunk + * @param {Collection<Snowflake, GuildMember>} members The members in the chunk + * @param {Guild} guild The guild related to the member chunk + * @param {GuildMembersChunk} chunk Properties of the received chunk + */ + client.emit(Events.GuildMembersChunk, members, guild, { + index: data.chunk_index, + count: data.chunk_count, + notFound: data.not_found, + nonce: data.nonce, + }); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBER_ADD.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBER_ADD.js new file mode 100644 index 0000000..fece5d7 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBER_ADD.js @@ -0,0 +1,20 @@ +'use strict'; + +const Events = require('../../../util/Events'); +const Status = require('../../../util/Status'); + +module.exports = (client, { d: data }, shard) => { + const guild = client.guilds.cache.get(data.guild_id); + if (guild) { + guild.memberCount++; + const member = guild.members._add(data); + if (shard.status === Status.Ready) { + /** + * Emitted whenever a user joins a guild. + * @event Client#guildMemberAdd + * @param {GuildMember} member The member that has joined a guild + */ + client.emit(Events.GuildMemberAdd, member); + } + } +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBER_REMOVE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBER_REMOVE.js new file mode 100644 index 0000000..72432af --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBER_REMOVE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet, shard) => { + client.actions.GuildMemberRemove.handle(packet.d, shard); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js new file mode 100644 index 0000000..cafc6bd --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet, shard) => { + client.actions.GuildMemberUpdate.handle(packet.d, shard); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_ROLE_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_ROLE_CREATE.js new file mode 100644 index 0000000..da9e7bc --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_ROLE_CREATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildRoleCreate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_ROLE_DELETE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_ROLE_DELETE.js new file mode 100644 index 0000000..cdc6353 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_ROLE_DELETE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildRoleDelete.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_ROLE_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_ROLE_UPDATE.js new file mode 100644 index 0000000..3a9b62e --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_ROLE_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildRoleUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_CREATE.js new file mode 100644 index 0000000..04ff2df --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_CREATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildScheduledEventCreate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_DELETE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_DELETE.js new file mode 100644 index 0000000..b660c09 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_DELETE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildScheduledEventDelete.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_UPDATE.js new file mode 100644 index 0000000..0064708 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildScheduledEventUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_ADD.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_ADD.js new file mode 100644 index 0000000..d5adca2 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_ADD.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildScheduledEventUserAdd.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_REMOVE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_REMOVE.js new file mode 100644 index 0000000..114df68 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_REMOVE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildScheduledEventUserRemove.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_STICKERS_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_STICKERS_UPDATE.js new file mode 100644 index 0000000..e3aba61 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_STICKERS_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildStickersUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/GUILD_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/GUILD_UPDATE.js new file mode 100644 index 0000000..fd0012a --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/GUILD_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.GuildUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/INTERACTION_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/INTERACTION_CREATE.js new file mode 100644 index 0000000..5bf30fc --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/INTERACTION_CREATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.InteractionCreate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/INVITE_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/INVITE_CREATE.js new file mode 100644 index 0000000..50a2e72 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/INVITE_CREATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.InviteCreate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/INVITE_DELETE.js b/node_modules/discord.js/src/client/websocket/handlers/INVITE_DELETE.js new file mode 100644 index 0000000..5971852 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/INVITE_DELETE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.InviteDelete.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_CREATE.js new file mode 100644 index 0000000..c9b79a8 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_CREATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.MessageCreate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_DELETE.js b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_DELETE.js new file mode 100644 index 0000000..85ae2bc --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_DELETE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.MessageDelete.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_DELETE_BULK.js b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_DELETE_BULK.js new file mode 100644 index 0000000..fbcf80f --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_DELETE_BULK.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.MessageDeleteBulk.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_ADD.js b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_ADD.js new file mode 100644 index 0000000..e219b4a --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_ADD.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.MessageReactionAdd.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE.js b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE.js new file mode 100644 index 0000000..2980e69 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.MessageReactionRemove.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_ALL.js b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_ALL.js new file mode 100644 index 0000000..ead80f7 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_ALL.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.MessageReactionRemoveAll.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_EMOJI.js b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_EMOJI.js new file mode 100644 index 0000000..579444c --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_EMOJI.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.MessageReactionRemoveEmoji.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_UPDATE.js new file mode 100644 index 0000000..c2a470b --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_UPDATE.js @@ -0,0 +1,16 @@ +'use strict'; + +const Events = require('../../../util/Events'); + +module.exports = (client, packet) => { + const { old, updated } = client.actions.MessageUpdate.handle(packet.d); + if (old && updated) { + /** + * Emitted whenever a message is updated - e.g. embed or content change. + * @event Client#messageUpdate + * @param {Message} oldMessage The message before the update + * @param {Message} newMessage The message after the update + */ + client.emit(Events.MessageUpdate, old, updated); + } +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/PRESENCE_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/PRESENCE_UPDATE.js new file mode 100644 index 0000000..bde3629 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/PRESENCE_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.PresenceUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/READY.js b/node_modules/discord.js/src/client/websocket/handlers/READY.js new file mode 100644 index 0000000..82da01c --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/READY.js @@ -0,0 +1,27 @@ +'use strict'; + +const ClientApplication = require('../../../structures/ClientApplication'); +let ClientUser; + +module.exports = (client, { d: data }, shard) => { + if (client.user) { + client.user._patch(data.user); + } else { + ClientUser ??= require('../../../structures/ClientUser'); + client.user = new ClientUser(client, data.user); + client.users.cache.set(client.user.id, client.user); + } + + for (const guild of data.guilds) { + guild.shardId = shard.id; + client.guilds._add(guild); + } + + if (client.application) { + client.application._patch(data.application); + } else { + client.application = new ClientApplication(client, data.application); + } + + shard.checkReady(); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/RESUMED.js b/node_modules/discord.js/src/client/websocket/handlers/RESUMED.js new file mode 100644 index 0000000..27ed7dd --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/RESUMED.js @@ -0,0 +1,14 @@ +'use strict'; + +const Events = require('../../../util/Events'); + +module.exports = (client, packet, shard) => { + const replayed = shard.sessionInfo.sequence - shard.closeSequence; + /** + * Emitted when a shard resumes successfully. + * @event Client#shardResume + * @param {number} id The shard id that resumed + * @param {number} replayedEvents The amount of replayed events + */ + client.emit(Events.ShardResume, shard.id, replayed); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_CREATE.js new file mode 100644 index 0000000..77ae2ff --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_CREATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.StageInstanceCreate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_DELETE.js b/node_modules/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_DELETE.js new file mode 100644 index 0000000..e2bb627 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_DELETE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.StageInstanceDelete.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_UPDATE.js new file mode 100644 index 0000000..fabc84a --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.StageInstanceUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/THREAD_CREATE.js b/node_modules/discord.js/src/client/websocket/handlers/THREAD_CREATE.js new file mode 100644 index 0000000..d92cab0 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/THREAD_CREATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.ThreadCreate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/THREAD_DELETE.js b/node_modules/discord.js/src/client/websocket/handlers/THREAD_DELETE.js new file mode 100644 index 0000000..1140a08 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/THREAD_DELETE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.ThreadDelete.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/THREAD_LIST_SYNC.js b/node_modules/discord.js/src/client/websocket/handlers/THREAD_LIST_SYNC.js new file mode 100644 index 0000000..17b173a --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/THREAD_LIST_SYNC.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.ThreadListSync.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/THREAD_MEMBERS_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/THREAD_MEMBERS_UPDATE.js new file mode 100644 index 0000000..f3c7a73 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/THREAD_MEMBERS_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.ThreadMembersUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/THREAD_MEMBER_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/THREAD_MEMBER_UPDATE.js new file mode 100644 index 0000000..a111b0a --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/THREAD_MEMBER_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.ThreadMemberUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/THREAD_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/THREAD_UPDATE.js new file mode 100644 index 0000000..481dcd4 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/THREAD_UPDATE.js @@ -0,0 +1,16 @@ +'use strict'; + +const Events = require('../../../util/Events'); + +module.exports = (client, packet) => { + const { old, updated } = client.actions.ChannelUpdate.handle(packet.d); + if (old && updated) { + /** + * Emitted whenever a thread is updated - e.g. name change, archive state change, locked state change. + * @event Client#threadUpdate + * @param {ThreadChannel} oldThread The thread before the update + * @param {ThreadChannel} newThread The thread after the update + */ + client.emit(Events.ThreadUpdate, old, updated); + } +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/TYPING_START.js b/node_modules/discord.js/src/client/websocket/handlers/TYPING_START.js new file mode 100644 index 0000000..9a56a54 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/TYPING_START.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.TypingStart.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/USER_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/USER_UPDATE.js new file mode 100644 index 0000000..a02bf58 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/USER_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.UserUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/VOICE_SERVER_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/VOICE_SERVER_UPDATE.js new file mode 100644 index 0000000..f9cf534 --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/VOICE_SERVER_UPDATE.js @@ -0,0 +1,6 @@ +'use strict'; + +module.exports = (client, packet) => { + client.emit('debug', `[VOICE] received voice server: ${JSON.stringify(packet)}`); + client.voice.onVoiceServer(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/VOICE_STATE_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/VOICE_STATE_UPDATE.js new file mode 100644 index 0000000..dbff6ea --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/VOICE_STATE_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.VoiceStateUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/WEBHOOKS_UPDATE.js b/node_modules/discord.js/src/client/websocket/handlers/WEBHOOKS_UPDATE.js new file mode 100644 index 0000000..46cacee --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/WEBHOOKS_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = (client, packet) => { + client.actions.WebhooksUpdate.handle(packet.d); +}; diff --git a/node_modules/discord.js/src/client/websocket/handlers/index.js b/node_modules/discord.js/src/client/websocket/handlers/index.js new file mode 100644 index 0000000..f175dbe --- /dev/null +++ b/node_modules/discord.js/src/client/websocket/handlers/index.js @@ -0,0 +1,64 @@ +'use strict'; + +const handlers = Object.fromEntries([ + ['APPLICATION_COMMAND_PERMISSIONS_UPDATE', require('./APPLICATION_COMMAND_PERMISSIONS_UPDATE')], + ['AUTO_MODERATION_ACTION_EXECUTION', require('./AUTO_MODERATION_ACTION_EXECUTION')], + ['AUTO_MODERATION_RULE_CREATE', require('./AUTO_MODERATION_RULE_CREATE')], + ['AUTO_MODERATION_RULE_DELETE', require('./AUTO_MODERATION_RULE_DELETE')], + ['AUTO_MODERATION_RULE_UPDATE', require('./AUTO_MODERATION_RULE_UPDATE')], + ['CHANNEL_CREATE', require('./CHANNEL_CREATE')], + ['CHANNEL_DELETE', require('./CHANNEL_DELETE')], + ['CHANNEL_PINS_UPDATE', require('./CHANNEL_PINS_UPDATE')], + ['CHANNEL_UPDATE', require('./CHANNEL_UPDATE')], + ['GUILD_AUDIT_LOG_ENTRY_CREATE', require('./GUILD_AUDIT_LOG_ENTRY_CREATE')], + ['GUILD_BAN_ADD', require('./GUILD_BAN_ADD')], + ['GUILD_BAN_REMOVE', require('./GUILD_BAN_REMOVE')], + ['GUILD_CREATE', require('./GUILD_CREATE')], + ['GUILD_DELETE', require('./GUILD_DELETE')], + ['GUILD_EMOJIS_UPDATE', require('./GUILD_EMOJIS_UPDATE')], + ['GUILD_INTEGRATIONS_UPDATE', require('./GUILD_INTEGRATIONS_UPDATE')], + ['GUILD_MEMBERS_CHUNK', require('./GUILD_MEMBERS_CHUNK')], + ['GUILD_MEMBER_ADD', require('./GUILD_MEMBER_ADD')], + ['GUILD_MEMBER_REMOVE', require('./GUILD_MEMBER_REMOVE')], + ['GUILD_MEMBER_UPDATE', require('./GUILD_MEMBER_UPDATE')], + ['GUILD_ROLE_CREATE', require('./GUILD_ROLE_CREATE')], + ['GUILD_ROLE_DELETE', require('./GUILD_ROLE_DELETE')], + ['GUILD_ROLE_UPDATE', require('./GUILD_ROLE_UPDATE')], + ['GUILD_SCHEDULED_EVENT_CREATE', require('./GUILD_SCHEDULED_EVENT_CREATE')], + ['GUILD_SCHEDULED_EVENT_DELETE', require('./GUILD_SCHEDULED_EVENT_DELETE')], + ['GUILD_SCHEDULED_EVENT_UPDATE', require('./GUILD_SCHEDULED_EVENT_UPDATE')], + ['GUILD_SCHEDULED_EVENT_USER_ADD', require('./GUILD_SCHEDULED_EVENT_USER_ADD')], + ['GUILD_SCHEDULED_EVENT_USER_REMOVE', require('./GUILD_SCHEDULED_EVENT_USER_REMOVE')], + ['GUILD_STICKERS_UPDATE', require('./GUILD_STICKERS_UPDATE')], + ['GUILD_UPDATE', require('./GUILD_UPDATE')], + ['INTERACTION_CREATE', require('./INTERACTION_CREATE')], + ['INVITE_CREATE', require('./INVITE_CREATE')], + ['INVITE_DELETE', require('./INVITE_DELETE')], + ['MESSAGE_CREATE', require('./MESSAGE_CREATE')], + ['MESSAGE_DELETE', require('./MESSAGE_DELETE')], + ['MESSAGE_DELETE_BULK', require('./MESSAGE_DELETE_BULK')], + ['MESSAGE_REACTION_ADD', require('./MESSAGE_REACTION_ADD')], + ['MESSAGE_REACTION_REMOVE', require('./MESSAGE_REACTION_REMOVE')], + ['MESSAGE_REACTION_REMOVE_ALL', require('./MESSAGE_REACTION_REMOVE_ALL')], + ['MESSAGE_REACTION_REMOVE_EMOJI', require('./MESSAGE_REACTION_REMOVE_EMOJI')], + ['MESSAGE_UPDATE', require('./MESSAGE_UPDATE')], + ['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')], + ['READY', require('./READY')], + ['RESUMED', require('./RESUMED')], + ['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')], + ['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')], + ['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')], + ['THREAD_CREATE', require('./THREAD_CREATE')], + ['THREAD_DELETE', require('./THREAD_DELETE')], + ['THREAD_LIST_SYNC', require('./THREAD_LIST_SYNC')], + ['THREAD_MEMBERS_UPDATE', require('./THREAD_MEMBERS_UPDATE')], + ['THREAD_MEMBER_UPDATE', require('./THREAD_MEMBER_UPDATE')], + ['THREAD_UPDATE', require('./THREAD_UPDATE')], + ['TYPING_START', require('./TYPING_START')], + ['USER_UPDATE', require('./USER_UPDATE')], + ['VOICE_SERVER_UPDATE', require('./VOICE_SERVER_UPDATE')], + ['VOICE_STATE_UPDATE', require('./VOICE_STATE_UPDATE')], + ['WEBHOOKS_UPDATE', require('./WEBHOOKS_UPDATE')], +]); + +module.exports = handlers; diff --git a/node_modules/discord.js/src/errors/DJSError.js b/node_modules/discord.js/src/errors/DJSError.js new file mode 100644 index 0000000..88e0e72 --- /dev/null +++ b/node_modules/discord.js/src/errors/DJSError.js @@ -0,0 +1,48 @@ +'use strict'; + +// Heavily inspired by node's `internal/errors` module +const ErrorCodes = require('./ErrorCodes'); +const Messages = require('./Messages'); + +/** + * Extend an error of some sort into a DiscordjsError. + * @param {Error} Base Base error to extend + * @returns {DiscordjsError} + * @ignore + */ +function makeDiscordjsError(Base) { + return class DiscordjsError extends Base { + constructor(code, ...args) { + super(message(code, args)); + this.code = code; + Error.captureStackTrace?.(this, DiscordjsError); + } + + get name() { + return `${super.name} [${this.code}]`; + } + }; +} + +/** + * Format the message for an error. + * @param {string} code The error code + * @param {Array<*>} args Arguments to pass for util format or as function args + * @returns {string} Formatted string + * @ignore + */ +function message(code, args) { + if (!(code in ErrorCodes)) throw new Error('Error code must be a valid DiscordjsErrorCodes'); + const msg = Messages[code]; + if (!msg) throw new Error(`No message associated with error code: ${code}.`); + if (typeof msg === 'function') return msg(...args); + if (!args?.length) return msg; + args.unshift(msg); + return String(...args); +} + +module.exports = { + DiscordjsError: makeDiscordjsError(Error), + DiscordjsTypeError: makeDiscordjsError(TypeError), + DiscordjsRangeError: makeDiscordjsError(RangeError), +}; diff --git a/node_modules/discord.js/src/errors/ErrorCodes.js b/node_modules/discord.js/src/errors/ErrorCodes.js new file mode 100644 index 0000000..9cd2f4d --- /dev/null +++ b/node_modules/discord.js/src/errors/ErrorCodes.js @@ -0,0 +1,319 @@ +'use strict'; + +/** + * @typedef {Object} DiscordjsErrorCodes + + * @property {'ClientInvalidOption'} ClientInvalidOption + * @property {'ClientInvalidProvidedShards'} ClientInvalidProvidedShards + * @property {'ClientMissingIntents'} ClientMissingIntents + * @property {'ClientNotReady'} ClientNotReady + + * @property {'TokenInvalid'} TokenInvalid + * @property {'TokenMissing'} TokenMissing + * @property {'ApplicationCommandPermissionsTokenMissing'} ApplicationCommandPermissionsTokenMissing + + * @property {'WSCloseRequested'} WSCloseRequested + * <warn>This property is deprecated.</warn> + * @property {'WSConnectionExists'} WSConnectionExists + * <warn>This property is deprecated.</warn> + * @property {'WSNotOpen'} WSNotOpen + * <warn>This property is deprecated.</warn> + * @property {'ManagerDestroyed'} ManagerDestroyed + + * @property {'BitFieldInvalid'} BitFieldInvalid + + * @property {'ShardingInvalid'} ShardingInvalid + * <warn>This property is deprecated.</warn> + * @property {'ShardingRequired'} ShardingRequired + * <warn>This property is deprecated.</warn> + * @property {'InvalidIntents'} InvalidIntents + * <warn>This property is deprecated.</warn> + * @property {'DisallowedIntents'} DisallowedIntents + * <warn>This property is deprecated.</warn> + * @property {'ShardingNoShards'} ShardingNoShards + * @property {'ShardingInProcess'} ShardingInProcess + * @property {'ShardingInvalidEvalBroadcast'} ShardingInvalidEvalBroadcast + * @property {'ShardingShardNotFound'} ShardingShardNotFound + * @property {'ShardingAlreadySpawned'} ShardingAlreadySpawned + * @property {'ShardingProcessExists'} ShardingProcessExists + * @property {'ShardingWorkerExists'} ShardingWorkerExists + * @property {'ShardingReadyTimeout'} ShardingReadyTimeout + * @property {'ShardingReadyDisconnected'} ShardingReadyDisconnected + * @property {'ShardingReadyDied'} ShardingReadyDied + * @property {'ShardingNoChildExists'} ShardingNoChildExists + * @property {'ShardingShardMiscalculation'} ShardingShardMiscalculation + + * @property {'ColorRange'} ColorRange + * @property {'ColorConvert'} ColorConvert + + * @property {'InviteOptionsMissingChannel'} InviteOptionsMissingChannel + + * @property {'ButtonLabel'} ButtonLabel + * @property {'ButtonURL'} ButtonURL + * @property {'ButtonCustomId'} ButtonCustomId + + * @property {'SelectMenuCustomId'} SelectMenuCustomId + * @property {'SelectMenuPlaceholder'} SelectMenuPlaceholder + * @property {'SelectOptionLabel'} SelectOptionLabel + * @property {'SelectOptionValue'} SelectOptionValue + * @property {'SelectOptionDescription'} SelectOptionDescription + + * @property {'InteractionCollectorError'} InteractionCollectorError + + * @property {'FileNotFound'} FileNotFound + + * @property {'UserBannerNotFetched'} UserBannerNotFetched + * @property {'UserNoDMChannel'} UserNoDMChannel + + * @property {'VoiceNotStageChannel'} VoiceNotStageChannel + + * @property {'VoiceStateNotOwn'} VoiceStateNotOwn + * @property {'VoiceStateInvalidType'} VoiceStateInvalidType + + * @property {'ReqResourceType'} ReqResourceType + + * @property {'ImageFormat'} ImageFormat + * @property {'ImageSize'} ImageSize + + * @property {'MessageBulkDeleteType'} MessageBulkDeleteType + * @property {'MessageNonceType'} MessageNonceType + * @property {'MessageContentType'} MessageContentType + + * @property {'SplitMaxLen'} SplitMaxLen + + * @property {'BanResolveId'} BanResolveId + * @property {'FetchBanResolveId'} FetchBanResolveId + + * @property {'PruneDaysType'} PruneDaysType + + * @property {'GuildChannelResolve'} GuildChannelResolve + * @property {'GuildVoiceChannelResolve'} GuildVoiceChannelResolve + * @property {'GuildChannelOrphan'} GuildChannelOrphan + * @property {'GuildChannelUnowned'} GuildChannelUnowned + * @property {'GuildOwned'} GuildOwned + * @property {'GuildMembersTimeout'} GuildMembersTimeout + * @property {'GuildUncachedMe'} GuildUncachedMe + * @property {'ChannelNotCached'} ChannelNotCached + * @property {'StageChannelResolve'} StageChannelResolve + * @property {'GuildScheduledEventResolve'} GuildScheduledEventResolve + * @property {'FetchOwnerId'} FetchOwnerId + + * @property {'InvalidType'} InvalidType + * @property {'InvalidElement'} InvalidElement + + * @property {'MessageThreadParent'} MessageThreadParent + * @property {'MessageExistingThread'} MessageExistingThread + * @property {'ThreadInvitableType'} ThreadInvitableType + + * @property {'WebhookMessage'} WebhookMessage + * @property {'WebhookTokenUnavailable'} WebhookTokenUnavailable + * @property {'WebhookURLInvalid'} WebhookURLInvalid + * @property {'WebhookApplication'} WebhookApplication + * @property {'MessageReferenceMissing'} MessageReferenceMissing + + * @property {'EmojiType'} EmojiType + * @property {'EmojiManaged'} EmojiManaged + * @property {'MissingManageGuildExpressionsPermission'} MissingManageGuildExpressionsPermission + * @property {'MissingManageEmojisAndStickersPermission'} MissingManageEmojisAndStickersPermission + * <warn>This property is deprecated. Use `MissingManageGuildExpressionsPermission` instead.</warn> + * + * @property {'NotGuildSticker'} NotGuildSticker + + * @property {'ReactionResolveUser'} ReactionResolveUser + + * @property {'VanityURL'} VanityURL + + * @property {'InviteResolveCode'} InviteResolveCode + + * @property {'InviteNotFound'} InviteNotFound + + * @property {'DeleteGroupDMChannel'} DeleteGroupDMChannel + * @property {'FetchGroupDMChannel'} FetchGroupDMChannel + + * @property {'MemberFetchNonceLength'} MemberFetchNonceLength + + * @property {'GlobalCommandPermissions'} GlobalCommandPermissions + * @property {'GuildUncachedEntityResolve'} GuildUncachedEntityResolve + + * @property {'InteractionAlreadyReplied'} InteractionAlreadyReplied + * @property {'InteractionNotReplied'} InteractionNotReplied + * @property {'InteractionEphemeralReplied'} InteractionEphemeralReplied + * <warn>This property is deprecated.</warn> + + * @property {'CommandInteractionOptionNotFound'} CommandInteractionOptionNotFound + * @property {'CommandInteractionOptionType'} CommandInteractionOptionType + * @property {'CommandInteractionOptionEmpty'} CommandInteractionOptionEmpty + * @property {'CommandInteractionOptionNoSubcommand'} CommandInteractionOptionNoSubcommand + * @property {'CommandInteractionOptionNoSubcommandGroup'} CommandInteractionOptionNoSubcommandGroup + * @property {'CommandInteractionOptionInvalidChannelType'} CommandInteractionOptionInvalidChannelType + * @property {'AutocompleteInteractionOptionNoFocusedOption'} AutocompleteInteractionOptionNoFocusedOption + + * @property {'ModalSubmitInteractionFieldNotFound'} ModalSubmitInteractionFieldNotFound + * @property {'ModalSubmitInteractionFieldType'} ModalSubmitInteractionFieldType + + * @property {'InvalidMissingScopes'} InvalidMissingScopes + * @property {'InvalidScopesWithPermissions'} InvalidScopesWithPermissions + + * @property {'NotImplemented'} NotImplemented + + * @property {'GuildForumMessageRequired'} GuildForumMessageRequired + + * @property {'SweepFilterReturn'} SweepFilterReturn + */ + +const keys = [ + 'ClientInvalidOption', + 'ClientInvalidProvidedShards', + 'ClientMissingIntents', + 'ClientNotReady', + + 'TokenInvalid', + 'TokenMissing', + 'ApplicationCommandPermissionsTokenMissing', + + 'WSCloseRequested', + 'WSConnectionExists', + 'WSNotOpen', + 'ManagerDestroyed', + + 'BitFieldInvalid', + + 'ShardingInvalid', + 'ShardingRequired', + 'InvalidIntents', + 'DisallowedIntents', + 'ShardingNoShards', + 'ShardingInProcess', + 'ShardingInvalidEvalBroadcast', + 'ShardingShardNotFound', + 'ShardingAlreadySpawned', + 'ShardingProcessExists', + 'ShardingWorkerExists', + 'ShardingReadyTimeout', + 'ShardingReadyDisconnected', + 'ShardingReadyDied', + 'ShardingNoChildExists', + 'ShardingShardMiscalculation', + + 'ColorRange', + 'ColorConvert', + + 'InviteOptionsMissingChannel', + + 'ButtonLabel', + 'ButtonURL', + 'ButtonCustomId', + + 'SelectMenuCustomId', + 'SelectMenuPlaceholder', + 'SelectOptionLabel', + 'SelectOptionValue', + 'SelectOptionDescription', + + 'InteractionCollectorError', + + 'FileNotFound', + + 'UserBannerNotFetched', + 'UserNoDMChannel', + + 'VoiceNotStageChannel', + + 'VoiceStateNotOwn', + 'VoiceStateInvalidType', + + 'ReqResourceType', + + 'ImageFormat', + 'ImageSize', + + 'MessageBulkDeleteType', + 'MessageNonceType', + 'MessageContentType', + + 'SplitMaxLen', + + 'BanResolveId', + 'FetchBanResolveId', + + 'PruneDaysType', + + 'GuildChannelResolve', + 'GuildVoiceChannelResolve', + 'GuildChannelOrphan', + 'GuildChannelUnowned', + 'GuildOwned', + 'GuildMembersTimeout', + 'GuildUncachedMe', + 'ChannelNotCached', + 'StageChannelResolve', + 'GuildScheduledEventResolve', + 'FetchOwnerId', + + 'InvalidType', + 'InvalidElement', + + 'MessageThreadParent', + 'MessageExistingThread', + 'ThreadInvitableType', + + 'WebhookMessage', + 'WebhookTokenUnavailable', + 'WebhookURLInvalid', + 'WebhookApplication', + 'MessageReferenceMissing', + + 'EmojiType', + 'EmojiManaged', + 'MissingManageGuildExpressionsPermission', + 'MissingManageEmojisAndStickersPermission', + + 'NotGuildSticker', + + 'ReactionResolveUser', + + 'VanityURL', + + 'InviteResolveCode', + + 'InviteNotFound', + + 'DeleteGroupDMChannel', + 'FetchGroupDMChannel', + + 'MemberFetchNonceLength', + + 'GlobalCommandPermissions', + 'GuildUncachedEntityResolve', + + 'InteractionAlreadyReplied', + 'InteractionNotReplied', + 'InteractionEphemeralReplied', + + 'CommandInteractionOptionNotFound', + 'CommandInteractionOptionType', + 'CommandInteractionOptionEmpty', + 'CommandInteractionOptionNoSubcommand', + 'CommandInteractionOptionNoSubcommandGroup', + 'CommandInteractionOptionInvalidChannelType', + 'AutocompleteInteractionOptionNoFocusedOption', + + 'ModalSubmitInteractionFieldNotFound', + 'ModalSubmitInteractionFieldType', + + 'InvalidMissingScopes', + 'InvalidScopesWithPermissions', + + 'NotImplemented', + + 'SweepFilterReturn', + + 'GuildForumMessageRequired', +]; + +// JSDoc for IntelliSense purposes +/** + * @type {DiscordjsErrorCodes} + * @ignore + */ +module.exports = Object.fromEntries(keys.map(key => [key, key])); diff --git a/node_modules/discord.js/src/errors/Messages.js b/node_modules/discord.js/src/errors/Messages.js new file mode 100644 index 0000000..550219f --- /dev/null +++ b/node_modules/discord.js/src/errors/Messages.js @@ -0,0 +1,170 @@ +'use strict'; + +const DjsErrorCodes = require('./ErrorCodes'); + +const Messages = { + [DjsErrorCodes.ClientInvalidOption]: (prop, must) => `The ${prop} option must be ${must}`, + [DjsErrorCodes.ClientInvalidProvidedShards]: 'None of the provided shards were valid.', + [DjsErrorCodes.ClientMissingIntents]: 'Valid intents must be provided for the Client.', + [DjsErrorCodes.ClientNotReady]: action => `The client needs to be logged in to ${action}.`, + + [DjsErrorCodes.TokenInvalid]: 'An invalid token was provided.', + [DjsErrorCodes.TokenMissing]: 'Request to use token, but token was unavailable to the client.', + [DjsErrorCodes.ApplicationCommandPermissionsTokenMissing]: + 'Editing application command permissions requires an OAuth2 bearer token, but none was provided.', + + [DjsErrorCodes.WSCloseRequested]: 'WebSocket closed due to user request.', + [DjsErrorCodes.WSConnectionExists]: 'There is already an existing WebSocket connection.', + [DjsErrorCodes.WSNotOpen]: (data = 'data') => `WebSocket not open to send ${data}`, + [DjsErrorCodes.ManagerDestroyed]: 'Manager was destroyed.', + + [DjsErrorCodes.BitFieldInvalid]: bit => `Invalid bitfield flag or number: ${bit}.`, + + [DjsErrorCodes.ShardingInvalid]: 'Invalid shard settings were provided.', + [DjsErrorCodes.ShardingRequired]: 'This session would have handled too many guilds - Sharding is required.', + [DjsErrorCodes.InvalidIntents]: 'Invalid intent provided for WebSocket intents.', + [DjsErrorCodes.DisallowedIntents]: 'Privileged intent provided is not enabled or whitelisted.', + [DjsErrorCodes.ShardingNoShards]: 'No shards have been spawned.', + [DjsErrorCodes.ShardingInProcess]: 'Shards are still being spawned.', + [DjsErrorCodes.ShardingInvalidEvalBroadcast]: 'Script to evaluate must be a function', + [DjsErrorCodes.ShardingShardNotFound]: id => `Shard ${id} could not be found.`, + [DjsErrorCodes.ShardingAlreadySpawned]: count => `Already spawned ${count} shards.`, + [DjsErrorCodes.ShardingProcessExists]: id => `Shard ${id} already has an active process.`, + [DjsErrorCodes.ShardingWorkerExists]: id => `Shard ${id} already has an active worker.`, + [DjsErrorCodes.ShardingReadyTimeout]: id => `Shard ${id}'s Client took too long to become ready.`, + [DjsErrorCodes.ShardingReadyDisconnected]: id => `Shard ${id}'s Client disconnected before becoming ready.`, + [DjsErrorCodes.ShardingReadyDied]: id => `Shard ${id}'s process exited before its Client became ready.`, + [DjsErrorCodes.ShardingNoChildExists]: id => `Shard ${id} has no active process or worker.`, + [DjsErrorCodes.ShardingShardMiscalculation]: (shard, guild, count) => + `Calculated invalid shard ${shard} for guild ${guild} with ${count} shards.`, + + [DjsErrorCodes.ColorRange]: 'Color must be within the range 0 - 16777215 (0xFFFFFF).', + [DjsErrorCodes.ColorConvert]: 'Unable to convert color to a number.', + + [DjsErrorCodes.InviteOptionsMissingChannel]: + 'A valid guild channel must be provided when GuildScheduledEvent is EXTERNAL.', + + [DjsErrorCodes.ButtonLabel]: 'MessageButton label must be a string', + [DjsErrorCodes.ButtonURL]: 'MessageButton URL must be a string', + [DjsErrorCodes.ButtonCustomId]: 'MessageButton customId must be a string', + + [DjsErrorCodes.SelectMenuCustomId]: 'MessageSelectMenu customId must be a string', + [DjsErrorCodes.SelectMenuPlaceholder]: 'MessageSelectMenu placeholder must be a string', + [DjsErrorCodes.SelectOptionLabel]: 'MessageSelectOption label must be a string', + [DjsErrorCodes.SelectOptionValue]: 'MessageSelectOption value must be a string', + [DjsErrorCodes.SelectOptionDescription]: 'MessageSelectOption description must be a string', + + [DjsErrorCodes.InteractionCollectorError]: reason => + `Collector received no interactions before ending with reason: ${reason}`, + + [DjsErrorCodes.FileNotFound]: file => `File could not be found: ${file}`, + + [DjsErrorCodes.UserBannerNotFetched]: "You must fetch this user's banner before trying to generate its URL!", + [DjsErrorCodes.UserNoDMChannel]: 'No DM Channel exists!', + + [DjsErrorCodes.VoiceNotStageChannel]: 'You are only allowed to do this in stage channels.', + + [DjsErrorCodes.VoiceStateNotOwn]: + 'You cannot self-deafen/mute/request to speak on VoiceStates that do not belong to the ClientUser.', + [DjsErrorCodes.VoiceStateInvalidType]: name => `${name} must be a boolean.`, + + [DjsErrorCodes.ReqResourceType]: 'The resource must be a string, Buffer or a valid file stream.', + + [DjsErrorCodes.ImageFormat]: format => `Invalid image format: ${format}`, + [DjsErrorCodes.ImageSize]: size => `Invalid image size: ${size}`, + + [DjsErrorCodes.MessageBulkDeleteType]: 'The messages must be an Array, Collection, or number.', + [DjsErrorCodes.MessageNonceType]: 'Message nonce must be an integer or a string.', + [DjsErrorCodes.MessageContentType]: 'Message content must be a string.', + + [DjsErrorCodes.SplitMaxLen]: 'Chunk exceeds the max length and contains no split characters.', + + [DjsErrorCodes.BanResolveId]: (ban = false) => `Couldn't resolve the user id to ${ban ? 'ban' : 'unban'}.`, + [DjsErrorCodes.FetchBanResolveId]: "Couldn't resolve the user id to fetch the ban.", + + [DjsErrorCodes.PruneDaysType]: 'Days must be a number', + + [DjsErrorCodes.GuildChannelResolve]: 'Could not resolve channel to a guild channel.', + [DjsErrorCodes.GuildVoiceChannelResolve]: 'Could not resolve channel to a guild voice channel.', + [DjsErrorCodes.GuildChannelOrphan]: 'Could not find a parent to this guild channel.', + [DjsErrorCodes.GuildChannelUnowned]: "The fetched channel does not belong to this manager's guild.", + [DjsErrorCodes.GuildOwned]: 'Guild is owned by the client.', + [DjsErrorCodes.GuildMembersTimeout]: "Members didn't arrive in time.", + [DjsErrorCodes.GuildUncachedMe]: 'The client user as a member of this guild is uncached.', + [DjsErrorCodes.ChannelNotCached]: 'Could not find the channel where this message came from in the cache!', + [DjsErrorCodes.StageChannelResolve]: 'Could not resolve channel to a stage channel.', + [DjsErrorCodes.GuildScheduledEventResolve]: 'Could not resolve the guild scheduled event.', + [DjsErrorCodes.FetchOwnerId]: "Couldn't resolve the guild ownerId to fetch the member.", + + [DjsErrorCodes.InvalidType]: (name, expected, an = false) => `Supplied ${name} is not a${an ? 'n' : ''} ${expected}.`, + [DjsErrorCodes.InvalidElement]: (type, name, elem) => `Supplied ${type} ${name} includes an invalid element: ${elem}`, + + [DjsErrorCodes.MessageThreadParent]: 'The message was not sent in a guild text or news channel', + [DjsErrorCodes.MessageExistingThread]: 'The message already has a thread', + [DjsErrorCodes.ThreadInvitableType]: type => `Invitable cannot be edited on ${type}`, + + [DjsErrorCodes.WebhookMessage]: 'The message was not sent by a webhook.', + [DjsErrorCodes.WebhookTokenUnavailable]: 'This action requires a webhook token, but none is available.', + [DjsErrorCodes.WebhookURLInvalid]: 'The provided webhook URL is not valid.', + [DjsErrorCodes.WebhookApplication]: 'This message webhook belongs to an application and cannot be fetched.', + [DjsErrorCodes.MessageReferenceMissing]: 'The message does not reference another message', + + [DjsErrorCodes.EmojiType]: 'Emoji must be a string or GuildEmoji/ReactionEmoji', + [DjsErrorCodes.EmojiManaged]: 'Emoji is managed and has no Author.', + [DjsErrorCodes.MissingManageGuildExpressionsPermission]: guild => + `Client must have Manage Guild Expressions permission in guild ${guild} to see emoji authors.`, + [DjsErrorCodes.MissingManageEmojisAndStickersPermission]: guild => + `Client must have Manage Emojis and Stickers permission in guild ${guild} to see emoji authors.`, + + [DjsErrorCodes.NotGuildSticker]: 'Sticker is a standard (non-guild) sticker and has no author.', + + [DjsErrorCodes.ReactionResolveUser]: "Couldn't resolve the user id to remove from the reaction.", + + [DjsErrorCodes.VanityURL]: 'This guild does not have the vanity URL feature enabled.', + + [DjsErrorCodes.InviteResolveCode]: 'Could not resolve the code to fetch the invite.', + + [DjsErrorCodes.InviteNotFound]: 'Could not find the requested invite.', + + [DjsErrorCodes.DeleteGroupDMChannel]: "Bots don't have access to Group DM Channels and cannot delete them", + [DjsErrorCodes.FetchGroupDMChannel]: "Bots don't have access to Group DM Channels and cannot fetch them", + + [DjsErrorCodes.MemberFetchNonceLength]: 'Nonce length must not exceed 32 characters.', + + [DjsErrorCodes.GlobalCommandPermissions]: + 'Permissions for global commands may only be fetched or modified by providing a GuildResolvable ' + + "or from a guild's application command manager.", + [DjsErrorCodes.GuildUncachedEntityResolve]: type => + `Cannot resolve ${type} from an arbitrary guild, provide an id instead`, + + [DjsErrorCodes.InteractionAlreadyReplied]: 'The reply to this interaction has already been sent or deferred.', + [DjsErrorCodes.InteractionNotReplied]: 'The reply to this interaction has not been sent or deferred.', + [DjsErrorCodes.InteractionEphemeralReplied]: 'Ephemeral responses cannot be deleted.', + + [DjsErrorCodes.CommandInteractionOptionNotFound]: name => `Required option "${name}" not found.`, + [DjsErrorCodes.CommandInteractionOptionType]: (name, type, expected) => + `Option "${name}" is of type: ${type}; expected ${expected}.`, + [DjsErrorCodes.CommandInteractionOptionEmpty]: (name, type) => + `Required option "${name}" is of type: ${type}; expected a non-empty value.`, + [DjsErrorCodes.CommandInteractionOptionNoSubcommand]: 'No subcommand specified for interaction.', + [DjsErrorCodes.CommandInteractionOptionNoSubcommandGroup]: 'No subcommand group specified for interaction.', + [DjsErrorCodes.CommandInteractionOptionInvalidChannelType]: (name, type, expected) => + `The type of channel of the option "${name}" is: ${type}; expected ${expected}.`, + [DjsErrorCodes.AutocompleteInteractionOptionNoFocusedOption]: 'No focused option for autocomplete interaction.', + + [DjsErrorCodes.ModalSubmitInteractionFieldNotFound]: customId => + `Required field with custom id "${customId}" not found.`, + [DjsErrorCodes.ModalSubmitInteractionFieldType]: (customId, type, expected) => + `Field with custom id "${customId}" is of type: ${type}; expected ${expected}.`, + + [DjsErrorCodes.InvalidMissingScopes]: 'At least one valid scope must be provided for the invite', + [DjsErrorCodes.InvalidScopesWithPermissions]: 'Permissions cannot be set without the bot scope.', + + [DjsErrorCodes.NotImplemented]: (what, name) => `Method ${what} not implemented on ${name}.`, + + [DjsErrorCodes.SweepFilterReturn]: 'The return value of the sweepFilter function was not false or a Function', + + [DjsErrorCodes.GuildForumMessageRequired]: 'You must provide a message to create a guild forum thread', +}; + +module.exports = Messages; diff --git a/node_modules/discord.js/src/errors/index.js b/node_modules/discord.js/src/errors/index.js new file mode 100644 index 0000000..78dc5c6 --- /dev/null +++ b/node_modules/discord.js/src/errors/index.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = require('./DJSError'); +module.exports.ErrorCodes = require('./ErrorCodes'); +module.exports.Messages = require('./Messages'); diff --git a/node_modules/discord.js/src/index.js b/node_modules/discord.js/src/index.js new file mode 100644 index 0000000..5021331 --- /dev/null +++ b/node_modules/discord.js/src/index.js @@ -0,0 +1,220 @@ +'use strict'; + +const { __exportStar } = require('tslib'); + +// "Root" classes (starting points) +exports.BaseClient = require('./client/BaseClient'); +exports.Client = require('./client/Client'); +exports.Shard = require('./sharding/Shard'); +exports.ShardClientUtil = require('./sharding/ShardClientUtil'); +exports.ShardingManager = require('./sharding/ShardingManager'); +exports.WebhookClient = require('./client/WebhookClient'); + +// Errors +exports.DiscordjsError = require('./errors/DJSError').DiscordjsError; +exports.DiscordjsTypeError = require('./errors/DJSError').DiscordjsTypeError; +exports.DiscordjsRangeError = require('./errors/DJSError').DiscordjsRangeError; +exports.DiscordjsErrorCodes = require('./errors/ErrorCodes'); + +// Utilities +exports.ActivityFlagsBitField = require('./util/ActivityFlagsBitField'); +exports.ApplicationFlagsBitField = require('./util/ApplicationFlagsBitField'); +exports.AttachmentFlagsBitField = require('./util/AttachmentFlagsBitField'); +exports.BaseManager = require('./managers/BaseManager'); +exports.BitField = require('./util/BitField'); +exports.ChannelFlagsBitField = require('./util/ChannelFlagsBitField'); +exports.Collection = require('@discordjs/collection').Collection; +exports.Constants = require('./util/Constants'); +exports.Colors = require('./util/Colors'); +exports.DataResolver = require('./util/DataResolver'); +exports.Events = require('./util/Events'); +exports.Formatters = require('./util/Formatters'); +exports.GuildMemberFlagsBitField = require('./util/GuildMemberFlagsBitField').GuildMemberFlagsBitField; +exports.IntentsBitField = require('./util/IntentsBitField'); +exports.LimitedCollection = require('./util/LimitedCollection'); +exports.MessageFlagsBitField = require('./util/MessageFlagsBitField'); +exports.Options = require('./util/Options'); +exports.Partials = require('./util/Partials'); +exports.PermissionsBitField = require('./util/PermissionsBitField'); +exports.RoleFlagsBitField = require('./util/RoleFlagsBitField'); +exports.ShardEvents = require('./util/ShardEvents'); +exports.Status = require('./util/Status'); +exports.SnowflakeUtil = require('@sapphire/snowflake').DiscordSnowflake; +exports.Sweepers = require('./util/Sweepers'); +exports.SystemChannelFlagsBitField = require('./util/SystemChannelFlagsBitField'); +exports.ThreadMemberFlagsBitField = require('./util/ThreadMemberFlagsBitField'); +exports.UserFlagsBitField = require('./util/UserFlagsBitField'); +__exportStar(require('./util/Util.js'), exports); +exports.WebSocketShardEvents = require('./util/WebSocketShardEvents'); +exports.version = require('../package.json').version; + +// Managers +exports.ApplicationCommandManager = require('./managers/ApplicationCommandManager'); +exports.ApplicationCommandPermissionsManager = require('./managers/ApplicationCommandPermissionsManager'); +exports.AutoModerationRuleManager = require('./managers/AutoModerationRuleManager'); +exports.BaseGuildEmojiManager = require('./managers/BaseGuildEmojiManager'); +exports.CachedManager = require('./managers/CachedManager'); +exports.ChannelManager = require('./managers/ChannelManager'); +exports.ClientVoiceManager = require('./client/voice/ClientVoiceManager'); +exports.DataManager = require('./managers/DataManager'); +exports.DMMessageManager = require('./managers/DMMessageManager'); +exports.GuildApplicationCommandManager = require('./managers/GuildApplicationCommandManager'); +exports.GuildBanManager = require('./managers/GuildBanManager'); +exports.GuildChannelManager = require('./managers/GuildChannelManager'); +exports.GuildEmojiManager = require('./managers/GuildEmojiManager'); +exports.GuildEmojiRoleManager = require('./managers/GuildEmojiRoleManager'); +exports.GuildForumThreadManager = require('./managers/GuildForumThreadManager'); +exports.GuildInviteManager = require('./managers/GuildInviteManager'); +exports.GuildManager = require('./managers/GuildManager'); +exports.GuildMemberManager = require('./managers/GuildMemberManager'); +exports.GuildMemberRoleManager = require('./managers/GuildMemberRoleManager'); +exports.GuildMessageManager = require('./managers/GuildMessageManager'); +exports.GuildScheduledEventManager = require('./managers/GuildScheduledEventManager'); +exports.GuildStickerManager = require('./managers/GuildStickerManager'); +exports.GuildTextThreadManager = require('./managers/GuildTextThreadManager'); +exports.MessageManager = require('./managers/MessageManager'); +exports.PermissionOverwriteManager = require('./managers/PermissionOverwriteManager'); +exports.PresenceManager = require('./managers/PresenceManager'); +exports.ReactionManager = require('./managers/ReactionManager'); +exports.ReactionUserManager = require('./managers/ReactionUserManager'); +exports.RoleManager = require('./managers/RoleManager'); +exports.StageInstanceManager = require('./managers/StageInstanceManager'); +exports.ThreadManager = require('./managers/ThreadManager'); +exports.ThreadMemberManager = require('./managers/ThreadMemberManager'); +exports.UserManager = require('./managers/UserManager'); +exports.VoiceStateManager = require('./managers/VoiceStateManager'); +exports.WebSocketManager = require('./client/websocket/WebSocketManager'); +exports.WebSocketShard = require('./client/websocket/WebSocketShard'); + +// Structures +exports.ActionRow = require('./structures/ActionRow'); +exports.ActionRowBuilder = require('./structures/ActionRowBuilder'); +exports.Activity = require('./structures/Presence').Activity; +exports.AnonymousGuild = require('./structures/AnonymousGuild'); +exports.Application = require('./structures/interfaces/Application'); +exports.ApplicationCommand = require('./structures/ApplicationCommand'); +exports.ApplicationRoleConnectionMetadata = + require('./structures/ApplicationRoleConnectionMetadata').ApplicationRoleConnectionMetadata; +exports.AutocompleteInteraction = require('./structures/AutocompleteInteraction'); +exports.AutoModerationActionExecution = require('./structures/AutoModerationActionExecution'); +exports.AutoModerationRule = require('./structures/AutoModerationRule'); +exports.Base = require('./structures/Base'); +exports.BaseGuild = require('./structures/BaseGuild'); +exports.BaseGuildEmoji = require('./structures/BaseGuildEmoji'); +exports.BaseGuildTextChannel = require('./structures/BaseGuildTextChannel'); +exports.BaseGuildVoiceChannel = require('./structures/BaseGuildVoiceChannel'); +exports.ButtonBuilder = require('./structures/ButtonBuilder'); +exports.ButtonComponent = require('./structures/ButtonComponent'); +exports.ButtonInteraction = require('./structures/ButtonInteraction'); +exports.CategoryChannel = require('./structures/CategoryChannel'); +exports.BaseChannel = require('./structures/BaseChannel').BaseChannel; +exports.ChatInputCommandInteraction = require('./structures/ChatInputCommandInteraction'); +exports.ClientApplication = require('./structures/ClientApplication'); +exports.ClientPresence = require('./structures/ClientPresence'); +exports.ClientUser = require('./structures/ClientUser'); +exports.CommandInteraction = require('./structures/CommandInteraction'); +exports.Collector = require('./structures/interfaces/Collector'); +exports.CommandInteractionOptionResolver = require('./structures/CommandInteractionOptionResolver'); +exports.Component = require('./structures/Component'); +exports.ContextMenuCommandInteraction = require('./structures/ContextMenuCommandInteraction'); +exports.DMChannel = require('./structures/DMChannel'); +exports.Embed = require('./structures/Embed'); +exports.EmbedBuilder = require('./structures/EmbedBuilder'); +exports.Emoji = require('./structures/Emoji').Emoji; +exports.ForumChannel = require('./structures/ForumChannel'); +exports.Guild = require('./structures/Guild').Guild; +exports.GuildAuditLogs = require('./structures/GuildAuditLogs'); +exports.GuildAuditLogsEntry = require('./structures/GuildAuditLogsEntry'); +exports.GuildBan = require('./structures/GuildBan'); +exports.GuildChannel = require('./structures/GuildChannel'); +exports.GuildEmoji = require('./structures/GuildEmoji'); +exports.GuildMember = require('./structures/GuildMember').GuildMember; +exports.GuildOnboarding = require('./structures/GuildOnboarding').GuildOnboarding; +exports.GuildOnboardingPrompt = require('./structures/GuildOnboardingPrompt').GuildOnboardingPrompt; +exports.GuildOnboardingPromptOption = require('./structures/GuildOnboardingPromptOption').GuildOnboardingPromptOption; +exports.GuildPreview = require('./structures/GuildPreview'); +exports.GuildPreviewEmoji = require('./structures/GuildPreviewEmoji'); +exports.GuildScheduledEvent = require('./structures/GuildScheduledEvent').GuildScheduledEvent; +exports.GuildTemplate = require('./structures/GuildTemplate'); +exports.Integration = require('./structures/Integration'); +exports.IntegrationApplication = require('./structures/IntegrationApplication'); +exports.BaseInteraction = require('./structures/BaseInteraction'); +exports.InteractionCollector = require('./structures/InteractionCollector'); +exports.InteractionResponse = require('./structures/InteractionResponse'); +exports.InteractionWebhook = require('./structures/InteractionWebhook'); +exports.Invite = require('./structures/Invite'); +exports.InviteStageInstance = require('./structures/InviteStageInstance'); +exports.InviteGuild = require('./structures/InviteGuild'); +exports.Message = require('./structures/Message').Message; +exports.Attachment = require('./structures/Attachment'); +exports.AttachmentBuilder = require('./structures/AttachmentBuilder'); +exports.ModalBuilder = require('./structures/ModalBuilder'); +exports.MessageCollector = require('./structures/MessageCollector'); +exports.MessageComponentInteraction = require('./structures/MessageComponentInteraction'); +exports.MessageContextMenuCommandInteraction = require('./structures/MessageContextMenuCommandInteraction'); +exports.MessageMentions = require('./structures/MessageMentions'); +exports.MessagePayload = require('./structures/MessagePayload'); +exports.MessageReaction = require('./structures/MessageReaction'); +exports.ModalSubmitInteraction = require('./structures/ModalSubmitInteraction'); +exports.ModalSubmitFields = require('./structures/ModalSubmitFields'); +exports.NewsChannel = require('./structures/NewsChannel'); +exports.OAuth2Guild = require('./structures/OAuth2Guild'); +exports.PartialGroupDMChannel = require('./structures/PartialGroupDMChannel'); +exports.PermissionOverwrites = require('./structures/PermissionOverwrites'); +exports.Presence = require('./structures/Presence').Presence; +exports.ReactionCollector = require('./structures/ReactionCollector'); +exports.ReactionEmoji = require('./structures/ReactionEmoji'); +exports.RichPresenceAssets = require('./structures/Presence').RichPresenceAssets; +exports.Role = require('./structures/Role').Role; +exports.SelectMenuBuilder = require('./structures/SelectMenuBuilder'); +exports.ChannelSelectMenuBuilder = require('./structures/ChannelSelectMenuBuilder'); +exports.MentionableSelectMenuBuilder = require('./structures/MentionableSelectMenuBuilder'); +exports.RoleSelectMenuBuilder = require('./structures/RoleSelectMenuBuilder'); +exports.StringSelectMenuBuilder = require('./structures/StringSelectMenuBuilder'); +exports.UserSelectMenuBuilder = require('./structures/UserSelectMenuBuilder'); +exports.BaseSelectMenuComponent = require('./structures/BaseSelectMenuComponent'); +exports.SelectMenuComponent = require('./structures/SelectMenuComponent'); +exports.ChannelSelectMenuComponent = require('./structures/ChannelSelectMenuComponent'); +exports.MentionableSelectMenuComponent = require('./structures/MentionableSelectMenuComponent'); +exports.RoleSelectMenuComponent = require('./structures/RoleSelectMenuComponent'); +exports.StringSelectMenuComponent = require('./structures/StringSelectMenuComponent'); +exports.UserSelectMenuComponent = require('./structures/UserSelectMenuComponent'); +exports.SelectMenuInteraction = require('./structures/SelectMenuInteraction'); +exports.ChannelSelectMenuInteraction = require('./structures/ChannelSelectMenuInteraction'); +exports.MentionableSelectMenuInteraction = require('./structures/MentionableSelectMenuInteraction'); +exports.MentionableSelectMenuInteraction = require('./structures/MentionableSelectMenuInteraction'); +exports.RoleSelectMenuInteraction = require('./structures/RoleSelectMenuInteraction'); +exports.StringSelectMenuInteraction = require('./structures/StringSelectMenuInteraction'); +exports.UserSelectMenuInteraction = require('./structures/UserSelectMenuInteraction'); +exports.SelectMenuOptionBuilder = require('./structures/SelectMenuOptionBuilder'); +exports.StringSelectMenuOptionBuilder = require('./structures/StringSelectMenuOptionBuilder'); +exports.StageChannel = require('./structures/StageChannel'); +exports.StageInstance = require('./structures/StageInstance').StageInstance; +exports.Sticker = require('./structures/Sticker').Sticker; +exports.StickerPack = require('./structures/StickerPack'); +exports.Team = require('./structures/Team'); +exports.TeamMember = require('./structures/TeamMember'); +exports.TextChannel = require('./structures/TextChannel'); +exports.TextInputBuilder = require('./structures/TextInputBuilder'); +exports.TextInputComponent = require('./structures/TextInputComponent'); +exports.ThreadChannel = require('./structures/ThreadChannel'); +exports.ThreadMember = require('./structures/ThreadMember'); +exports.Typing = require('./structures/Typing'); +exports.User = require('./structures/User'); +exports.UserContextMenuCommandInteraction = require('./structures/UserContextMenuCommandInteraction'); +exports.VoiceChannel = require('./structures/VoiceChannel'); +exports.VoiceRegion = require('./structures/VoiceRegion'); +exports.VoiceState = require('./structures/VoiceState'); +exports.Webhook = require('./structures/Webhook'); +exports.Widget = require('./structures/Widget'); +exports.WidgetMember = require('./structures/WidgetMember'); +exports.WelcomeChannel = require('./structures/WelcomeChannel'); +exports.WelcomeScreen = require('./structures/WelcomeScreen'); + +// External +__exportStar(require('discord-api-types/v10'), exports); +__exportStar(require('@discordjs/builders'), exports); +__exportStar(require('@discordjs/formatters'), exports); +__exportStar(require('@discordjs/rest'), exports); +__exportStar(require('@discordjs/util'), exports); +__exportStar(require('@discordjs/ws'), exports); diff --git a/node_modules/discord.js/src/managers/ApplicationCommandManager.js b/node_modules/discord.js/src/managers/ApplicationCommandManager.js new file mode 100644 index 0000000..417afc4 --- /dev/null +++ b/node_modules/discord.js/src/managers/ApplicationCommandManager.js @@ -0,0 +1,263 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { isJSONEncodable } = require('@discordjs/util'); +const { Routes } = require('discord-api-types/v10'); +const ApplicationCommandPermissionsManager = require('./ApplicationCommandPermissionsManager'); +const CachedManager = require('./CachedManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const ApplicationCommand = require('../structures/ApplicationCommand'); +const PermissionsBitField = require('../util/PermissionsBitField'); + +/** + * Manages API methods for application commands and stores their cache. + * @extends {CachedManager} + */ +class ApplicationCommandManager extends CachedManager { + constructor(client, iterable) { + super(client, ApplicationCommand, iterable); + + /** + * The manager for permissions of arbitrary commands on arbitrary guilds + * @type {ApplicationCommandPermissionsManager} + */ + this.permissions = new ApplicationCommandPermissionsManager(this); + } + + /** + * The cache of this manager + * @type {Collection<Snowflake, ApplicationCommand>} + * @name ApplicationCommandManager#cache + */ + + _add(data, cache, guildId) { + return super._add(data, cache, { extras: [this.guild, guildId] }); + } + + /** + * The APIRouter path to the commands + * @param {Snowflake} [options.id] The application command's id + * @param {Snowflake} [options.guildId] The guild's id to use in the path, + * ignored when using a {@link GuildApplicationCommandManager} + * @returns {string} + * @private + */ + commandPath({ id, guildId } = {}) { + if (this.guild ?? guildId) { + if (id) { + return Routes.applicationGuildCommand(this.client.application.id, this.guild?.id ?? guildId, id); + } + + return Routes.applicationGuildCommands(this.client.application.id, this.guild?.id ?? guildId); + } + + if (id) { + return Routes.applicationCommand(this.client.application.id, id); + } + + return Routes.applicationCommands(this.client.application.id); + } + + /** + * Data that resolves to give an ApplicationCommand object. This can be: + * * An ApplicationCommand object + * * A Snowflake + * @typedef {ApplicationCommand|Snowflake} ApplicationCommandResolvable + */ + + /** + * Data that resolves to the data of an ApplicationCommand + * @typedef {ApplicationCommandData|APIApplicationCommand} ApplicationCommandDataResolvable + */ + + /** + * Options used to fetch data from Discord + * @typedef {Object} BaseFetchOptions + * @property {boolean} [cache=true] Whether to cache the fetched data if it wasn't already + * @property {boolean} [force=false] Whether to skip the cache check and request the API + */ + + /** + * Options used to fetch Application Commands from Discord + * @typedef {BaseFetchOptions} FetchApplicationCommandOptions + * @property {Snowflake} [guildId] The guild's id to fetch commands for, for when the guild is not cached + * @property {LocaleString} [locale] The locale to use when fetching this command + * @property {boolean} [withLocalizations] Whether to fetch all localization data + */ + + /** + * Obtains one or multiple application commands from Discord, or the cache if it's already available. + * @param {Snowflake} [id] The application command's id + * @param {FetchApplicationCommandOptions} [options] Additional options for this fetch + * @returns {Promise<ApplicationCommand|Collection<Snowflake, ApplicationCommand>>} + * @example + * // Fetch a single command + * client.application.commands.fetch('123456789012345678') + * .then(command => console.log(`Fetched command ${command.name}`)) + * .catch(console.error); + * @example + * // Fetch all commands + * guild.commands.fetch() + * .then(commands => console.log(`Fetched ${commands.size} commands`)) + * .catch(console.error); + */ + async fetch(id, { guildId, cache = true, force = false, locale, withLocalizations } = {}) { + if (typeof id === 'object') { + ({ guildId, cache = true, locale, withLocalizations } = id); + } else if (id) { + if (!force) { + const existing = this.cache.get(id); + if (existing) return existing; + } + const command = await this.client.rest.get(this.commandPath({ id, guildId })); + return this._add(command, cache); + } + + const data = await this.client.rest.get(this.commandPath({ guildId }), { + headers: { + 'X-Discord-Locale': locale, + }, + query: makeURLSearchParams({ with_localizations: withLocalizations }), + }); + return data.reduce((coll, command) => coll.set(command.id, this._add(command, cache, guildId)), new Collection()); + } + + /** + * Creates an application command. + * @param {ApplicationCommandDataResolvable} command The command + * @param {Snowflake} [guildId] The guild's id to create this command in, + * ignored when using a {@link GuildApplicationCommandManager} + * @returns {Promise<ApplicationCommand>} + * @example + * // Create a new command + * client.application.commands.create({ + * name: 'test', + * description: 'A test command', + * }) + * .then(console.log) + * .catch(console.error); + */ + async create(command, guildId) { + const data = await this.client.rest.post(this.commandPath({ guildId }), { + body: this.constructor.transformCommand(command), + }); + return this._add(data, true, guildId); + } + + /** + * Sets all the commands for this application or guild. + * @param {ApplicationCommandDataResolvable[]} commands The commands + * @param {Snowflake} [guildId] The guild's id to create the commands in, + * ignored when using a {@link GuildApplicationCommandManager} + * @returns {Promise<Collection<Snowflake, ApplicationCommand>>} + * @example + * // Set all commands to just this one + * client.application.commands.set([ + * { + * name: 'test', + * description: 'A test command', + * }, + * ]) + * .then(console.log) + * .catch(console.error); + * @example + * // Remove all commands + * guild.commands.set([]) + * .then(console.log) + * .catch(console.error); + */ + async set(commands, guildId) { + const data = await this.client.rest.put(this.commandPath({ guildId }), { + body: commands.map(c => this.constructor.transformCommand(c)), + }); + return data.reduce((coll, command) => coll.set(command.id, this._add(command, true, guildId)), new Collection()); + } + + /** + * Edits an application command. + * @param {ApplicationCommandResolvable} command The command to edit + * @param {Partial<ApplicationCommandDataResolvable>} data The data to update the command with + * @param {Snowflake} [guildId] The guild's id where the command registered, + * ignored when using a {@link GuildApplicationCommandManager} + * @returns {Promise<ApplicationCommand>} + * @example + * // Edit an existing command + * client.application.commands.edit('123456789012345678', { + * description: 'New description', + * }) + * .then(console.log) + * .catch(console.error); + */ + async edit(command, data, guildId) { + const id = this.resolveId(command); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'command', 'ApplicationCommandResolvable'); + + const patched = await this.client.rest.patch(this.commandPath({ id, guildId }), { + body: this.constructor.transformCommand(data), + }); + return this._add(patched, true, guildId); + } + + /** + * Deletes an application command. + * @param {ApplicationCommandResolvable} command The command to delete + * @param {Snowflake} [guildId] The guild's id where the command is registered, + * ignored when using a {@link GuildApplicationCommandManager} + * @returns {Promise<?ApplicationCommand>} + * @example + * // Delete a command + * guild.commands.delete('123456789012345678') + * .then(console.log) + * .catch(console.error); + */ + async delete(command, guildId) { + const id = this.resolveId(command); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'command', 'ApplicationCommandResolvable'); + + await this.client.rest.delete(this.commandPath({ id, guildId })); + + const cached = this.cache.get(id); + this.cache.delete(id); + return cached ?? null; + } + + /** + * Transforms an {@link ApplicationCommandData} object into something that can be used with the API. + * @param {ApplicationCommandDataResolvable} command The command to transform + * @returns {APIApplicationCommand} + * @private + */ + static transformCommand(command) { + if (isJSONEncodable(command)) return command.toJSON(); + + let default_member_permissions; + + if ('default_member_permissions' in command) { + default_member_permissions = command.default_member_permissions + ? new PermissionsBitField(BigInt(command.default_member_permissions)).bitfield.toString() + : command.default_member_permissions; + } + + if ('defaultMemberPermissions' in command) { + default_member_permissions = + command.defaultMemberPermissions !== null + ? new PermissionsBitField(command.defaultMemberPermissions).bitfield.toString() + : command.defaultMemberPermissions; + } + + return { + name: command.name, + name_localizations: command.nameLocalizations ?? command.name_localizations, + description: command.description, + nsfw: command.nsfw, + description_localizations: command.descriptionLocalizations ?? command.description_localizations, + type: command.type, + options: command.options?.map(o => ApplicationCommand.transformOption(o)), + default_member_permissions, + dm_permission: command.dmPermission ?? command.dm_permission, + }; + } +} + +module.exports = ApplicationCommandManager; diff --git a/node_modules/discord.js/src/managers/ApplicationCommandPermissionsManager.js b/node_modules/discord.js/src/managers/ApplicationCommandPermissionsManager.js new file mode 100644 index 0000000..2f7279a --- /dev/null +++ b/node_modules/discord.js/src/managers/ApplicationCommandPermissionsManager.js @@ -0,0 +1,434 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { ApplicationCommandPermissionType, RESTJSONErrorCodes, Routes } = require('discord-api-types/v10'); +const BaseManager = require('./BaseManager'); +const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * Manages API methods for permissions of Application Commands. + * @extends {BaseManager} + */ +class ApplicationCommandPermissionsManager extends BaseManager { + constructor(manager) { + super(manager.client); + + /** + * The manager or command that this manager belongs to + * @type {ApplicationCommandManager|ApplicationCommand} + * @private + */ + this.manager = manager; + + /** + * The guild that this manager acts on + * @type {?Guild} + */ + this.guild = manager.guild ?? null; + + /** + * The id of the guild that this manager acts on + * @type {?Snowflake} + */ + this.guildId = manager.guildId ?? manager.guild?.id ?? null; + + /** + * The id of the command this manager acts on + * @type {?Snowflake} + */ + this.commandId = manager.id ?? null; + } + + /** + * The APIRouter path to the commands + * @param {Snowflake} guildId The guild's id to use in the path, + * @param {Snowflake} [commandId] The application command's id + * @returns {string} + * @private + */ + permissionsPath(guildId, commandId) { + if (commandId) { + return Routes.applicationCommandPermissions(this.client.application.id, guildId, commandId); + } + + return Routes.guildApplicationCommandsPermissions(this.client.application.id, guildId); + } + + /* eslint-disable max-len */ + /** + * The object returned when fetching permissions for an application command. + * @typedef {Object} ApplicationCommandPermissions + * @property {Snowflake} id The role, user, or channel's id. Can also be a + * {@link https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-constants permission constant}. + * @property {ApplicationCommandPermissionType} type Whether this permission is for a role or a user + * @property {boolean} permission Whether the role or user has the permission to use this command + */ + /* eslint-enable max-len */ + + /** + * Options for managing permissions for one or more Application Commands + * <warn>When passing these options to a manager where `guildId` is `null`, + * `guild` is a required parameter</warn> + * @typedef {Object} BaseApplicationCommandPermissionsOptions + * @property {GuildResolvable} [guild] The guild to modify / check permissions for + * <warn>Ignored when the manager has a non-null `guildId` property</warn> + * @property {ApplicationCommandResolvable} [command] The command to modify / check permissions for + * <warn>Ignored when the manager has a non-null `commandId` property</warn> + */ + + /** + * Fetches the permissions for one or multiple commands. Providing the client's id as the "command id" will fetch + * *only* the guild level permissions + * @param {BaseApplicationCommandPermissionsOptions} [options] Options used to fetch permissions + * @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>} + * @example + * // Fetch permissions for one command + * guild.commands.permissions.fetch({ command: '123456789012345678' }) + * .then(perms => console.log(`Fetched ${perms.length} overwrites`)) + * .catch(console.error); + * @example + * // Fetch permissions for all commands in a guild + * client.application.commands.permissions.fetch({ guild: '123456789012345678' }) + * .then(perms => console.log(`Fetched permissions for ${perms.size} commands`)) + * .catch(console.error); + * @example + * // Fetch guild level permissions + * guild.commands.permissions.fetch({ command: client.user.id }) + * .then(perms => console.log(`Fetched ${perms.length} guild level permissions`)) + * .catch(console.error); + */ + async fetch({ guild, command } = {}) { + const { guildId, commandId } = this._validateOptions(guild, command); + if (commandId) { + const data = await this.client.rest.get(this.permissionsPath(guildId, commandId)); + return data.permissions; + } + + const data = await this.client.rest.get(this.permissionsPath(guildId)); + return data.reduce((coll, perm) => coll.set(perm.id, perm.permissions), new Collection()); + } + + /** + * Options used to set permissions for one or more Application Commands in a guild + * <warn>Omitting the `command` parameter edits the guild wide permissions + * when the manager's `commandId` is `null`</warn> + * @typedef {BaseApplicationCommandPermissionsOptions} ApplicationCommandPermissionsEditOptions + * @property {ApplicationCommandPermissions[]} permissions The new permissions for the guild or overwrite + * @property {string} token The bearer token to use that authorizes the permission edit + */ + + /** + * Sets the permissions for the guild or a command overwrite. + * @param {ApplicationCommandPermissionsEditOptions} options Options used to set permissions + * @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>} + * @example + * // Set a permission overwrite for a command + * client.application.commands.permissions.set({ + * guild: '892455839386304532', + * command: '123456789012345678', + * token: 'TotallyRealToken', + * permissions: [ + * { + * id: '876543210987654321', + * type: ApplicationCommandPermissionType.User, + * permission: false, + * }, + * ]}) + * .then(console.log) + * .catch(console.error); + * @example + * // Set the permissions used for the guild (commands without overwrites) + * guild.commands.permissions.set({ token: 'TotallyRealToken', permissions: [ + * { + * id: '123456789012345678', + * permissions: [{ + * id: '876543210987654321', + * type: ApplicationCommandPermissionType.User, + * permission: false, + * }], + * }, + * ]}) + * .then(console.log) + * .catch(console.error); + */ + async set({ guild, command, permissions, token } = {}) { + if (!token) { + throw new DiscordjsError(ErrorCodes.ApplicationCommandPermissionsTokenMissing); + } + let { guildId, commandId } = this._validateOptions(guild, command); + + if (!Array.isArray(permissions)) { + throw new DiscordjsTypeError( + ErrorCodes.InvalidType, + 'permissions', + 'Array of ApplicationCommandPermissions', + true, + ); + } + + if (!commandId) { + commandId = this.client.user.id; + } + const data = await this.client.rest.put(this.permissionsPath(guildId, commandId), { + body: { permissions }, + auth: false, + headers: { Authorization: `Bearer ${token}` }, + }); + return data.permissions; + } + + /** + * Add permissions to a command. + * @param {ApplicationCommandPermissionsEditOptions} options Options used to add permissions + * @returns {Promise<ApplicationCommandPermissions[]>} + * @example + * // Add a rule to block a role from using a command + * guild.commands.permissions.add({ command: '123456789012345678', token: 'TotallyRealToken', permissions: [ + * { + * id: '876543211234567890', + * type: ApplicationCommandPermissionType.Role, + * permission: false + * }, + * ]}) + * .then(console.log) + * .catch(console.error); + */ + async add({ guild, command, permissions, token } = {}) { + if (!token) { + throw new DiscordjsError(ErrorCodes.ApplicationCommandPermissionsTokenMissing); + } + let { guildId, commandId } = this._validateOptions(guild, command); + if (!commandId) { + commandId = this.client.user.id; + } + if (!Array.isArray(permissions)) { + throw new DiscordjsTypeError( + ErrorCodes.InvalidType, + 'permissions', + 'Array of ApplicationCommandPermissions', + true, + ); + } + + let existing = []; + try { + existing = await this.fetch({ guild: guildId, command: commandId }); + } catch (error) { + if (error.code !== RESTJSONErrorCodes.UnknownApplicationCommandPermissions) throw error; + } + + const newPermissions = permissions.slice(); + for (const perm of existing) { + if (!newPermissions.some(x => x.id === perm.id)) { + newPermissions.push(perm); + } + } + + return this.set({ guild: guildId, command: commandId, permissions: newPermissions, token }); + } + + /** + * A static snowflake that identifies the everyone role for application command permissions. + * It is the same as the guild id + * @typedef {Snowflake} RolePermissionConstant + */ + + /** + * A static snowflake that identifies the "all channels" entity for application command permissions. + * It will be the result of the calculation `guildId - 1` + * @typedef {Snowflake} ChannelPermissionConstant + */ + + /** + * Options used to remove permissions from a command + * <warn>Omitting the `command` parameter removes from the guild wide permissions + * when the managers `commandId` is `null`</warn> + * <warn>At least one of `users`, `roles`, and `channels` is required</warn> + * @typedef {BaseApplicationCommandPermissionsOptions} RemoveApplicationCommandPermissionsOptions + * @property {string} token The bearer token to use that authorizes the permission removal + * @property {UserResolvable[]} [users] The user(s) to remove + * @property {Array<RoleResolvable|RolePermissionConstant>} [roles] The role(s) to remove + * @property {Array<GuildChannelResolvable|ChannelPermissionConstant>} [channels] The channel(s) to remove + */ + + /** + * Remove permissions from a command. + * @param {RemoveApplicationCommandPermissionsOptions} options Options used to remove permissions + * @returns {Promise<ApplicationCommandPermissions[]>} + * @example + * // Remove a user permission from this command + * guild.commands.permissions.remove({ + * command: '123456789012345678', users: '876543210123456789', token: 'TotallyRealToken', + * }) + * .then(console.log) + * .catch(console.error); + * @example + * // Remove multiple roles from this command + * guild.commands.permissions.remove({ + * command: '123456789012345678', roles: ['876543210123456789', '765432101234567890'], token: 'TotallyRealToken', + * }) + * .then(console.log) + * .catch(console.error); + */ + async remove({ guild, command, users, roles, channels, token } = {}) { + if (!token) { + throw new DiscordjsError(ErrorCodes.ApplicationCommandPermissionsTokenMissing); + } + let { guildId, commandId } = this._validateOptions(guild, command); + if (!commandId) { + commandId = this.client.user.id; + } + + if (!users && !roles && !channels) { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'users OR roles OR channels', 'Array or Resolvable', true); + } + + let resolvedUserIds = []; + if (Array.isArray(users)) { + for (const user of users) { + const userId = this.client.users.resolveId(user); + if (!userId) throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array', 'users', user); + resolvedUserIds.push(userId); + } + } + + let resolvedRoleIds = []; + if (Array.isArray(roles)) { + for (const role of roles) { + if (typeof role === 'string') { + resolvedRoleIds.push(role); + continue; + } + if (!this.guild) throw new DiscordjsError(ErrorCodes.GuildUncachedEntityResolve, 'roles'); + const roleId = this.guild.roles.resolveId(role); + if (!roleId) throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array', 'users', role); + resolvedRoleIds.push(roleId); + } + } + + let resolvedChannelIds = []; + if (Array.isArray(channels)) { + for (const channel of channels) { + if (typeof channel === 'string') { + resolvedChannelIds.push(channel); + continue; + } + if (!this.guild) throw new DiscordjsError(ErrorCodes.GuildUncachedEntityResolve, 'channels'); + const channelId = this.guild.channels.resolveId(channel); + if (!channelId) throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array', 'channels', channel); + resolvedChannelIds.push(channelId); + } + } + + let existing = []; + try { + existing = await this.fetch({ guild: guildId, command: commandId }); + } catch (error) { + if (error.code !== RESTJSONErrorCodes.UnknownApplicationCommandPermissions) throw error; + } + + const permissions = existing.filter(perm => { + switch (perm.type) { + case ApplicationCommandPermissionType.Role: + return !resolvedRoleIds.includes(perm.id); + case ApplicationCommandPermissionType.User: + return !resolvedUserIds.includes(perm.id); + case ApplicationCommandPermissionType.Channel: + return !resolvedChannelIds.includes(perm.id); + } + return true; + }); + + return this.set({ guild: guildId, command: commandId, permissions, token }); + } + + /** + * Options used to check the existence of permissions on a command + * <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn> + * @typedef {BaseApplicationCommandPermissionsOptions} HasApplicationCommandPermissionsOptions + * @property {ApplicationCommandPermissionIdResolvable} permissionId The entity to check if a permission exists for + * on this command. + * @property {ApplicationCommandPermissionType} [permissionType] Check for a specific type of permission + */ + + /** + * Check whether a permission exists for a user, role, or channel + * @param {HasApplicationCommandPermissionsOptions} options Options used to check permissions + * @returns {Promise<boolean>} + * @example + * // Check whether a user has permission to use a command + * guild.commands.permissions.has({ command: '123456789012345678', permissionId: '876543210123456789' }) + * .then(console.log) + * .catch(console.error); + */ + async has({ guild, command, permissionId, permissionType }) { + const { guildId, commandId } = this._validateOptions(guild, command); + if (!commandId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'command', 'ApplicationCommandResolvable'); + + if (!permissionId) { + throw new DiscordjsTypeError( + ErrorCodes.InvalidType, + 'permissionId', + 'UserResolvable, RoleResolvable, ChannelResolvable, or Permission Constant', + ); + } + let resolvedId = permissionId; + if (typeof permissionId !== 'string') { + resolvedId = this.client.users.resolveId(permissionId); + if (!resolvedId) { + if (!this.guild) throw new DiscordjsError(ErrorCodes.GuildUncachedEntityResolve, 'roles'); + resolvedId = this.guild.roles.resolveId(permissionId); + } + if (!resolvedId) { + resolvedId = this.guild.channels.resolveId(permissionId); + } + if (!resolvedId) { + throw new DiscordjsTypeError( + ErrorCodes.InvalidType, + 'permissionId', + 'UserResolvable, RoleResolvable, ChannelResolvable, or Permission Constant', + ); + } + } + + let existing = []; + try { + existing = await this.fetch({ guild: guildId, command: commandId }); + } catch (error) { + if (error.code !== RESTJSONErrorCodes.UnknownApplicationCommandPermissions) throw error; + } + + // Check permission type if provided for the single edge case where a channel id is the same as the everyone role id + return existing.some(perm => perm.id === resolvedId && (permissionType ?? perm.type) === perm.type); + } + + _validateOptions(guild, command) { + const guildId = this.guildId ?? this.client.guilds.resolveId(guild); + if (!guildId) throw new DiscordjsError(ErrorCodes.GlobalCommandPermissions); + let commandId = this.commandId; + if (command && !commandId) { + commandId = this.manager.resolveId?.(command); + if (!commandId && this.guild) { + commandId = this.guild.commands.resolveId(command); + } + commandId ??= this.client.application?.commands.resolveId(command); + if (!commandId) { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'command', 'ApplicationCommandResolvable', true); + } + } + return { guildId, commandId }; + } +} + +module.exports = ApplicationCommandPermissionsManager; + +/* eslint-disable max-len */ +/** + * @external APIApplicationCommandPermissions + * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-structure} + */ + +/** + * Data that resolves to an id used for an application command permission + * @typedef {UserResolvable|RoleResolvable|GuildChannelResolvable|RolePermissionConstant|ChannelPermissionConstant} ApplicationCommandPermissionIdResolvable + */ diff --git a/node_modules/discord.js/src/managers/AutoModerationRuleManager.js b/node_modules/discord.js/src/managers/AutoModerationRuleManager.js new file mode 100644 index 0000000..dd0ee4e --- /dev/null +++ b/node_modules/discord.js/src/managers/AutoModerationRuleManager.js @@ -0,0 +1,288 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const AutoModerationRule = require('../structures/AutoModerationRule'); + +/** + * Manages API methods for auto moderation rules and stores their cache. + * @extends {CachedManager} + */ +class AutoModerationRuleManager extends CachedManager { + constructor(guild, iterable) { + super(guild.client, AutoModerationRule, iterable); + + /** + * The guild this manager belongs to. + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The cache of this manager + * @type {Collection<Snowflake, AutoModerationRule>} + * @name AutoModerationRuleManager#cache + */ + + /** + * Resolves an {@link AutoModerationRuleResolvable} to an {@link AutoModerationRule} object. + * @method resolve + * @memberof AutoModerationRuleManager + * @instance + * @param {AutoModerationRuleResolvable} autoModerationRule The AutoModerationRule resolvable to resolve + * @returns {?AutoModerationRule} + */ + + /** + * Resolves an {@link AutoModerationRuleResolvable} to a {@link AutoModerationRule} id. + * @method resolveId + * @memberof AutoModerationRuleManager + * @instance + * @param {AutoModerationRuleResolvable} autoModerationRule The AutoModerationRule resolvable to resolve + * @returns {?Snowflake} + */ + + _add(data, cache) { + return super._add(data, cache, { extras: [this.guild] }); + } + + /** + * Options used to set the trigger metadata of an auto moderation rule. + * @typedef {Object} AutoModerationTriggerMetadataOptions + * @property {string[]} [keywordFilter] The substrings that will be searched for in the content + * @property {string[]} [regexPatterns] The regular expression patterns which will be matched against the content + * <info>Only Rust-flavored regular expressions are supported.</info> + * @property {AutoModerationRuleKeywordPresetType[]} [presets] + * The internally pre-defined wordsets which will be searched for in the content + * @property {string[]} [allowList] The substrings that will be exempt from triggering + * {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.KeywordPreset} + * @property {?number} [mentionTotalLimit] The total number of role & user mentions allowed per message + * @property {boolean} [mentionRaidProtectionEnabled] Whether to automatically detect mention raids + */ + + /** + * Options used to set the actions of an auto moderation rule. + * @typedef {Object} AutoModerationActionOptions + * @property {AutoModerationActionType} type The type of this auto moderation rule action + * @property {AutoModerationActionMetadataOptions} [metadata] Additional metadata needed during execution + * <info>This property is required if using a `type` of + * {@link AutoModerationActionType.SendAlertMessage} or {@link AutoModerationActionType.Timeout}.</info> + */ + + /** + * Options used to set the metadata of an auto moderation rule action. + * @typedef {Object} AutoModerationActionMetadataOptions + * @property {GuildTextChannelResolvable|ThreadChannel} [channel] The channel to which content will be logged + * @property {number} [durationSeconds] The timeout duration in seconds + * @property {string} [customMessage] The custom message that is shown whenever a message is blocked + */ + + /** + * Options used to create an auto moderation rule. + * @typedef {Object} AutoModerationRuleCreateOptions + * @property {string} name The name of the auto moderation rule + * @property {AutoModerationRuleEventType} eventType The event type of the auto moderation rule + * @property {AutoModerationRuleTriggerType} triggerType The trigger type of the auto moderation rule + * @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule + * <info>This property is required if using a `triggerType` of + * {@link AutoModerationRuleTriggerType.Keyword}, {@link AutoModerationRuleTriggerType.KeywordPreset}, + * or {@link AutoModerationRuleTriggerType.MentionSpam}.</info> + * @property {AutoModerationActionOptions[]} actions + * The actions that will execute when the auto moderation rule is triggered + * @property {boolean} [enabled] Whether the auto moderation rule should be enabled + * @property {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles] + * The roles that should not be affected by the auto moderation rule + * @property {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels] + * The channels that should not be affected by the auto moderation rule + * @property {string} [reason] The reason for creating the auto moderation rule + */ + + /** + * Creates a new auto moderation rule. + * @param {AutoModerationRuleCreateOptions} options Options for creating the auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + async create({ + name, + eventType, + triggerType, + triggerMetadata, + actions, + enabled, + exemptRoles, + exemptChannels, + reason, + }) { + const data = await this.client.rest.post(Routes.guildAutoModerationRules(this.guild.id), { + body: { + name, + event_type: eventType, + trigger_type: triggerType, + trigger_metadata: triggerMetadata && { + keyword_filter: triggerMetadata.keywordFilter, + regex_patterns: triggerMetadata.regexPatterns, + presets: triggerMetadata.presets, + allow_list: triggerMetadata.allowList, + mention_total_limit: triggerMetadata.mentionTotalLimit, + mention_raid_protection_enabled: triggerMetadata.mentionRaidProtectionEnabled, + }, + actions: actions.map(action => ({ + type: action.type, + metadata: { + duration_seconds: action.metadata?.durationSeconds, + channel_id: action.metadata?.channel && this.guild.channels.resolveId(action.metadata.channel), + custom_message: action.metadata?.customMessage, + }, + })), + enabled, + exempt_roles: exemptRoles?.map(exemptRole => this.guild.roles.resolveId(exemptRole)), + exempt_channels: exemptChannels?.map(exemptChannel => this.guild.channels.resolveId(exemptChannel)), + }, + reason, + }); + + return this._add(data); + } + + /** + * Options used to edit an auto moderation rule. + * @typedef {Object} AutoModerationRuleEditOptions + * @property {string} [name] The name of the auto moderation rule + * @property {AutoModerationRuleEventType} [eventType] The event type of the auto moderation rule + * @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule + * @property {AutoModerationActionOptions[]} [actions] + * The actions that will execute when the auto moderation rule is triggered + * @property {boolean} [enabled] Whether the auto moderation rule should be enabled + * @property {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles] + * The roles that should not be affected by the auto moderation rule + * @property {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels] + * The channels that should not be affected by the auto moderation rule + * @property {string} [reason] The reason for creating the auto moderation rule + */ + + /** + * Edits an auto moderation rule. + * @param {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to edit + * @param {AutoModerationRuleEditOptions} options Options for editing the auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + async edit( + autoModerationRule, + { name, eventType, triggerMetadata, actions, enabled, exemptRoles, exemptChannels, reason }, + ) { + const autoModerationRuleId = this.resolveId(autoModerationRule); + + const data = await this.client.rest.patch(Routes.guildAutoModerationRule(this.guild.id, autoModerationRuleId), { + body: { + name, + event_type: eventType, + trigger_metadata: triggerMetadata && { + keyword_filter: triggerMetadata.keywordFilter, + regex_patterns: triggerMetadata.regexPatterns, + presets: triggerMetadata.presets, + allow_list: triggerMetadata.allowList, + mention_total_limit: triggerMetadata.mentionTotalLimit, + mention_raid_protection_enabled: triggerMetadata.mentionRaidProtectionEnabled, + }, + actions: actions?.map(action => ({ + type: action.type, + metadata: { + duration_seconds: action.metadata?.durationSeconds, + channel_id: action.metadata?.channel && this.guild.channels.resolveId(action.metadata.channel), + custom_message: action.metadata?.customMessage, + }, + })), + enabled, + exempt_roles: exemptRoles?.map(exemptRole => this.guild.roles.resolveId(exemptRole)), + exempt_channels: exemptChannels?.map(exemptChannel => this.guild.channels.resolveId(exemptChannel)), + }, + reason, + }); + + return this._add(data); + } + + /** + * Data that can be resolved to give an AutoModerationRule object. This can be: + * * An AutoModerationRule + * * A Snowflake + * @typedef {AutoModerationRule|Snowflake} AutoModerationRuleResolvable + */ + + /** + * Options used to fetch a single auto moderation rule from a guild. + * @typedef {BaseFetchOptions} FetchAutoModerationRuleOptions + * @property {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to fetch + */ + + /** + * Options used to fetch all auto moderation rules from a guild. + * @typedef {Object} FetchAutoModerationRulesOptions + * @property {boolean} [cache] Whether to cache the fetched auto moderation rules + */ + + /** + * Fetches auto moderation rules from Discord. + * @param {AutoModerationRuleResolvable|FetchAutoModerationRuleOptions|FetchAutoModerationRulesOptions} [options] + * Options for fetching auto moderation rule(s) + * @returns {Promise<AutoModerationRule|Collection<Snowflake, AutoModerationRule>>} + * @example + * // Fetch all auto moderation rules from a guild without caching + * guild.autoModerationRules.fetch({ cache: false }) + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a single auto moderation rule + * guild.autoModerationRules.fetch('979083472868098119') + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a single auto moderation rule without checking cache and without caching + * guild.autoModerationRules.fetch({ autoModerationRule: '979083472868098119', cache: false, force: true }) + * .then(console.log) + * .catch(console.error) + */ + fetch(options) { + if (!options) return this._fetchMany(); + const { autoModerationRule, cache, force } = options; + const resolvedAutoModerationRule = this.resolveId(autoModerationRule ?? options); + if (resolvedAutoModerationRule) { + return this._fetchSingle({ autoModerationRule: resolvedAutoModerationRule, cache, force }); + } + return this._fetchMany(options); + } + + async _fetchSingle({ autoModerationRule, cache, force = false }) { + if (!force) { + const existing = this.cache.get(autoModerationRule); + if (existing) return existing; + } + + const data = await this.client.rest.get(Routes.guildAutoModerationRule(this.guild.id, autoModerationRule)); + return this._add(data, cache); + } + + async _fetchMany(options = {}) { + const data = await this.client.rest.get(Routes.guildAutoModerationRules(this.guild.id)); + + return data.reduce( + (col, autoModerationRule) => col.set(autoModerationRule.id, this._add(autoModerationRule, options.cache)), + new Collection(), + ); + } + + /** + * Deletes an auto moderation rule. + * @param {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to delete + * @param {string} [reason] The reason for deleting the auto moderation rule + * @returns {Promise<void>} + */ + async delete(autoModerationRule, reason) { + const autoModerationRuleId = this.resolveId(autoModerationRule); + await this.client.rest.delete(Routes.guildAutoModerationRule(this.guild.id, autoModerationRuleId), { reason }); + } +} + +module.exports = AutoModerationRuleManager; diff --git a/node_modules/discord.js/src/managers/BaseGuildEmojiManager.js b/node_modules/discord.js/src/managers/BaseGuildEmojiManager.js new file mode 100644 index 0000000..89eee4c --- /dev/null +++ b/node_modules/discord.js/src/managers/BaseGuildEmojiManager.js @@ -0,0 +1,80 @@ +'use strict'; + +const CachedManager = require('./CachedManager'); +const GuildEmoji = require('../structures/GuildEmoji'); +const ReactionEmoji = require('../structures/ReactionEmoji'); +const { parseEmoji } = require('../util/Util'); + +/** + * Holds methods to resolve GuildEmojis and stores their cache. + * @extends {CachedManager} + */ +class BaseGuildEmojiManager extends CachedManager { + constructor(client, iterable) { + super(client, GuildEmoji, iterable); + } + + /** + * The cache of GuildEmojis + * @type {Collection<Snowflake, GuildEmoji>} + * @name BaseGuildEmojiManager#cache + */ + + /** + * Data that can be resolved into a GuildEmoji object. This can be: + * * A Snowflake + * * A GuildEmoji object + * * A ReactionEmoji object + * @typedef {Snowflake|GuildEmoji|ReactionEmoji} EmojiResolvable + */ + + /** + * Resolves an EmojiResolvable to an Emoji object. + * @param {EmojiResolvable} emoji The Emoji resolvable to identify + * @returns {?GuildEmoji} + */ + resolve(emoji) { + if (emoji instanceof ReactionEmoji) return super.resolve(emoji.id); + return super.resolve(emoji); + } + + /** + * Resolves an EmojiResolvable to an Emoji id string. + * @param {EmojiResolvable} emoji The Emoji resolvable to identify + * @returns {?Snowflake} + */ + resolveId(emoji) { + if (emoji instanceof ReactionEmoji) return emoji.id; + return super.resolveId(emoji); + } + + /** + * Data that can be resolved to give an emoji identifier. This can be: + * * An EmojiResolvable + * * The `<a:name:id>`, `<:name:id>`, `a:name:id` or `name:id` emoji identifier string of an emoji + * * The Unicode representation of an emoji + * @typedef {string|EmojiResolvable} EmojiIdentifierResolvable + */ + + /** + * Resolves an EmojiResolvable to an emoji identifier. + * @param {EmojiIdentifierResolvable} emoji The emoji resolvable to resolve + * @returns {?string} + */ + resolveIdentifier(emoji) { + const emojiResolvable = this.resolve(emoji); + if (emojiResolvable) return emojiResolvable.identifier; + if (emoji instanceof ReactionEmoji) return emoji.identifier; + if (typeof emoji === 'string') { + const res = parseEmoji(emoji); + if (res?.name.length) { + emoji = `${res.animated ? 'a:' : ''}${res.name}${res.id ? `:${res.id}` : ''}`; + } + if (!emoji.includes('%')) return encodeURIComponent(emoji); + return emoji; + } + return null; + } +} + +module.exports = BaseGuildEmojiManager; diff --git a/node_modules/discord.js/src/managers/BaseManager.js b/node_modules/discord.js/src/managers/BaseManager.js new file mode 100644 index 0000000..0651401 --- /dev/null +++ b/node_modules/discord.js/src/managers/BaseManager.js @@ -0,0 +1,19 @@ +'use strict'; + +/** + * Manages the API methods of a data model. + * @abstract + */ +class BaseManager { + constructor(client) { + /** + * The client that instantiated this Manager + * @name BaseManager#client + * @type {Client} + * @readonly + */ + Object.defineProperty(this, 'client', { value: client }); + } +} + +module.exports = BaseManager; diff --git a/node_modules/discord.js/src/managers/CachedManager.js b/node_modules/discord.js/src/managers/CachedManager.js new file mode 100644 index 0000000..b4c50b1 --- /dev/null +++ b/node_modules/discord.js/src/managers/CachedManager.js @@ -0,0 +1,64 @@ +'use strict'; + +const DataManager = require('./DataManager'); +const { MakeCacheOverrideSymbol } = require('../util/Symbols'); + +/** + * Manages the API methods of a data model with a mutable cache of instances. + * @extends {DataManager} + * @abstract + */ +class CachedManager extends DataManager { + constructor(client, holds, iterable) { + super(client, holds); + + /** + * The private cache of items for this manager. + * @type {Collection} + * @private + * @readonly + * @name CachedManager#_cache + */ + Object.defineProperty(this, '_cache', { + value: this.client.options.makeCache( + this.constructor[MakeCacheOverrideSymbol] ?? this.constructor, + this.holds, + this.constructor, + ), + }); + + if (iterable) { + for (const item of iterable) { + this._add(item); + } + } + } + + /** + * The cache of items for this manager. + * @type {Collection} + * @abstract + */ + get cache() { + return this._cache; + } + + _add(data, cache = true, { id, extras = [] } = {}) { + const existing = this.cache.get(id ?? data.id); + if (existing) { + if (cache) { + existing._patch(data); + return existing; + } + const clone = existing._clone(); + clone._patch(data); + return clone; + } + + const entry = this.holds ? new this.holds(this.client, data, ...extras) : data; + if (cache) this.cache.set(id ?? entry.id, entry); + return entry; + } +} + +module.exports = CachedManager; diff --git a/node_modules/discord.js/src/managers/CategoryChannelChildManager.js b/node_modules/discord.js/src/managers/CategoryChannelChildManager.js new file mode 100644 index 0000000..347526a --- /dev/null +++ b/node_modules/discord.js/src/managers/CategoryChannelChildManager.js @@ -0,0 +1,77 @@ +'use strict'; + +const DataManager = require('./DataManager'); +const GuildChannel = require('../structures/GuildChannel'); + +/** + * Manages API methods for CategoryChannels' children. + * @extends {DataManager} + */ +class CategoryChannelChildManager extends DataManager { + constructor(channel) { + super(channel.client, GuildChannel); + /** + * The category channel this manager belongs to + * @type {CategoryChannel} + */ + this.channel = channel; + } + + /** + * The channels that are a part of this category + * @type {Collection<Snowflake, GuildChannel>} + * @readonly + */ + get cache() { + return this.guild.channels.cache.filter(c => c.parentId === this.channel.id); + } + + /** + * The guild this manager belongs to + * @type {Guild} + * @readonly + */ + get guild() { + return this.channel.guild; + } + + /** + * Options for creating a channel using {@link CategoryChannel#createChannel}. + * @typedef {Object} CategoryCreateChannelOptions + * @property {string} name The name for the new channel + * @property {ChannelType} [type=ChannelType.GuildText] The type of the new channel. + * @property {string} [topic] The topic for the new channel + * @property {boolean} [nsfw] Whether the new channel is NSFW + * @property {number} [bitrate] Bitrate of the new channel in bits (only voice) + * @property {number} [userLimit] Maximum amount of users allowed in the new channel (only voice) + * @property {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} [permissionOverwrites] + * Permission overwrites of the new channel + * @property {number} [position] Position of the new channel + * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the new channel in seconds + * @property {string} [rtcRegion] The specific region of the new channel. + * @property {VideoQualityMode} [videoQualityMode] The camera video quality mode of the voice channel + * @property {GuildForumTagData[]} [availableTags] The tags that can be used in this channel (forum only). + * @property {DefaultReactionEmoji} [defaultReactionEmoji] + * The emoji to show in the add reaction button on a thread in a guild forum channel. + * @property {ThreadAutoArchiveDuration} [defaultAutoArchiveDuration] + * The default auto archive duration for all new threads in this channel + * @property {SortOrderType} [defaultSortOrder] The default sort order mode used to order posts (forum only). + * @property {ForumLayoutType} [defaultForumLayout] The default layout used to display posts (forum only). + * @property {string} [reason] Reason for creating the new channel + */ + + /** + * Creates a new channel within this category. + * <info>You cannot create a channel of type {@link ChannelType.GuildCategory} inside a CategoryChannel.</info> + * @param {CategoryCreateChannelOptions} options Options for creating the new channel + * @returns {Promise<GuildChannel>} + */ + create(options) { + return this.guild.channels.create({ + ...options, + parent: this.channel.id, + }); + } +} + +module.exports = CategoryChannelChildManager; diff --git a/node_modules/discord.js/src/managers/ChannelManager.js b/node_modules/discord.js/src/managers/ChannelManager.js new file mode 100644 index 0000000..0126d91 --- /dev/null +++ b/node_modules/discord.js/src/managers/ChannelManager.js @@ -0,0 +1,128 @@ +'use strict'; + +const process = require('node:process'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { BaseChannel } = require('../structures/BaseChannel'); +const { createChannel } = require('../util/Channels'); +const { ThreadChannelTypes } = require('../util/Constants'); +const Events = require('../util/Events'); + +let cacheWarningEmitted = false; + +/** + * A manager of channels belonging to a client + * @extends {CachedManager} + */ +class ChannelManager extends CachedManager { + constructor(client, iterable) { + super(client, BaseChannel, iterable); + const defaultCaching = + this._cache.constructor.name === 'Collection' || + this._cache.maxSize === undefined || + this._cache.maxSize === Infinity; + if (!cacheWarningEmitted && !defaultCaching) { + cacheWarningEmitted = true; + process.emitWarning( + `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`, + 'UnsupportedCacheOverwriteWarning', + ); + } + } + + /** + * The cache of Channels + * @type {Collection<Snowflake, BaseChannel>} + * @name ChannelManager#cache + */ + + _add(data, guild, { cache = true, allowUnknownGuild = false } = {}) { + const existing = this.cache.get(data.id); + if (existing) { + if (cache) existing._patch(data); + guild?.channels?._add(existing); + if (ThreadChannelTypes.includes(existing.type)) { + existing.parent?.threads?._add(existing); + } + return existing; + } + + const channel = createChannel(this.client, data, guild, { allowUnknownGuild }); + + if (!channel) { + this.client.emit(Events.Debug, `Failed to find guild, or unknown type for channel ${data.id} ${data.type}`); + return null; + } + + if (cache && !allowUnknownGuild) this.cache.set(channel.id, channel); + + return channel; + } + + _remove(id) { + const channel = this.cache.get(id); + channel?.guild?.channels.cache.delete(id); + + for (const [code, invite] of channel?.guild?.invites.cache ?? []) { + if (invite.channelId === id) channel.guild.invites.cache.delete(code); + } + + channel?.parent?.threads?.cache.delete(id); + this.cache.delete(id); + } + + /** + * Data that can be resolved to give a Channel object. This can be: + * * A Channel object + * * A Snowflake + * @typedef {BaseChannel|Snowflake} ChannelResolvable + */ + + /** + * Resolves a ChannelResolvable to a Channel object. + * @method resolve + * @memberof ChannelManager + * @instance + * @param {ChannelResolvable} channel The channel resolvable to resolve + * @returns {?BaseChannel} + */ + + /** + * Resolves a ChannelResolvable to a channel id string. + * @method resolveId + * @memberof ChannelManager + * @instance + * @param {ChannelResolvable} channel The channel resolvable to resolve + * @returns {?Snowflake} + */ + + /** + * Options for fetching a channel from Discord + * @typedef {BaseFetchOptions} FetchChannelOptions + * @property {boolean} [allowUnknownGuild=false] Allows the channel to be returned even if the guild is not in cache, + * it will not be cached. <warn>Many of the properties and methods on the returned channel will throw errors</warn> + */ + + /** + * Obtains a channel from Discord, or the channel cache if it's already available. + * @param {Snowflake} id The channel's id + * @param {FetchChannelOptions} [options] Additional options for this fetch + * @returns {Promise<?BaseChannel>} + * @example + * // Fetch a channel by its id + * client.channels.fetch('222109930545610754') + * .then(channel => console.log(channel.name)) + * .catch(console.error); + */ + async fetch(id, { allowUnknownGuild = false, cache = true, force = false } = {}) { + if (!force) { + const existing = this.cache.get(id); + if (existing && !existing.partial) return existing; + } + + const data = await this.client.rest.get(Routes.channel(id)); + return this._add(data, null, { cache, allowUnknownGuild }); + } +} + +module.exports = ChannelManager; diff --git a/node_modules/discord.js/src/managers/DMMessageManager.js b/node_modules/discord.js/src/managers/DMMessageManager.js new file mode 100644 index 0000000..f0b3a33 --- /dev/null +++ b/node_modules/discord.js/src/managers/DMMessageManager.js @@ -0,0 +1,17 @@ +'use strict'; + +const MessageManager = require('./MessageManager'); + +/** + * Manages API methods for messages in direct message channels and holds their cache. + * @extends {MessageManager} + */ +class DMMessageManager extends MessageManager { + /** + * The channel that the messages belong to + * @name DMMessageManager#channel + * @type {DMChannel} + */ +} + +module.exports = DMMessageManager; diff --git a/node_modules/discord.js/src/managers/DataManager.js b/node_modules/discord.js/src/managers/DataManager.js new file mode 100644 index 0000000..383844e --- /dev/null +++ b/node_modules/discord.js/src/managers/DataManager.js @@ -0,0 +1,61 @@ +'use strict'; + +const BaseManager = require('./BaseManager'); +const { DiscordjsError, ErrorCodes } = require('../errors'); + +/** + * Manages the API methods of a data model along with a collection of instances. + * @extends {BaseManager} + * @abstract + */ +class DataManager extends BaseManager { + constructor(client, holds) { + super(client); + + /** + * The data structure belonging to this manager. + * @name DataManager#holds + * @type {Function} + * @private + * @readonly + */ + Object.defineProperty(this, 'holds', { value: holds }); + } + + /** + * The cache of items for this manager. + * @type {Collection} + * @abstract + */ + get cache() { + throw new DiscordjsError(ErrorCodes.NotImplemented, 'get cache', this.constructor.name); + } + + /** + * Resolves a data entry to a data Object. + * @param {string|Object} idOrInstance The id or instance of something in this Manager + * @returns {?Object} An instance from this Manager + */ + resolve(idOrInstance) { + if (idOrInstance instanceof this.holds) return idOrInstance; + if (typeof idOrInstance === 'string') return this.cache.get(idOrInstance) ?? null; + return null; + } + + /** + * Resolves a data entry to an instance id. + * @param {string|Object} idOrInstance The id or instance of something in this Manager + * @returns {?Snowflake} + */ + resolveId(idOrInstance) { + if (idOrInstance instanceof this.holds) return idOrInstance.id; + if (typeof idOrInstance === 'string') return idOrInstance; + return null; + } + + valueOf() { + return this.cache; + } +} + +module.exports = DataManager; diff --git a/node_modules/discord.js/src/managers/GuildApplicationCommandManager.js b/node_modules/discord.js/src/managers/GuildApplicationCommandManager.js new file mode 100644 index 0000000..97fea5e --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildApplicationCommandManager.js @@ -0,0 +1,28 @@ +'use strict'; + +const ApplicationCommandManager = require('./ApplicationCommandManager'); +const ApplicationCommandPermissionsManager = require('./ApplicationCommandPermissionsManager'); + +/** + * An extension for guild-specific application commands. + * @extends {ApplicationCommandManager} + */ +class GuildApplicationCommandManager extends ApplicationCommandManager { + constructor(guild, iterable) { + super(guild.client, iterable); + + /** + * The guild that this manager belongs to + * @type {Guild} + */ + this.guild = guild; + + /** + * The manager for permissions of arbitrary commands on this guild + * @type {ApplicationCommandPermissionsManager} + */ + this.permissions = new ApplicationCommandPermissionsManager(this); + } +} + +module.exports = GuildApplicationCommandManager; diff --git a/node_modules/discord.js/src/managers/GuildBanManager.js b/node_modules/discord.js/src/managers/GuildBanManager.js new file mode 100644 index 0000000..d3c8a00 --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildBanManager.js @@ -0,0 +1,204 @@ +'use strict'; + +const process = require('node:process'); +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../errors'); +const GuildBan = require('../structures/GuildBan'); +const { GuildMember } = require('../structures/GuildMember'); + +let deprecationEmittedForDeleteMessageDays = false; + +/** + * Manages API methods for guild bans and stores their cache. + * @extends {CachedManager} + */ +class GuildBanManager extends CachedManager { + constructor(guild, iterable) { + super(guild.client, GuildBan, iterable); + + /** + * The guild this Manager belongs to + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The cache of this Manager + * @type {Collection<Snowflake, GuildBan>} + * @name GuildBanManager#cache + */ + + _add(data, cache) { + return super._add(data, cache, { id: data.user.id, extras: [this.guild] }); + } + + /** + * Data that resolves to give a GuildBan object. This can be: + * * A GuildBan object + * * A User resolvable + * @typedef {GuildBan|UserResolvable} GuildBanResolvable + */ + + /** + * Resolves a GuildBanResolvable to a GuildBan object. + * @param {GuildBanResolvable} ban The ban that is in the guild + * @returns {?GuildBan} + */ + resolve(ban) { + return super.resolve(ban) ?? super.resolve(this.client.users.resolveId(ban)); + } + + /** + * Options used to fetch a single ban from a guild. + * @typedef {BaseFetchOptions} FetchBanOptions + * @property {UserResolvable} user The ban to fetch + */ + + /** + * Options used to fetch multiple bans from a guild. + * @typedef {Object} FetchBansOptions + * @property {number} [limit] The maximum number of bans to return + * @property {Snowflake} [before] Consider only bans before this id + * @property {Snowflake} [after] Consider only bans after this id + * @property {boolean} [cache] Whether to cache the fetched bans + */ + + /** + * Fetches ban(s) from Discord. + * @param {UserResolvable|FetchBanOptions|FetchBansOptions} [options] Options for fetching guild ban(s) + * @returns {Promise<GuildBan|Collection<Snowflake, GuildBan>>} + * @example + * // Fetch multiple bans from a guild + * guild.bans.fetch() + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a maximum of 5 bans from a guild without caching + * guild.bans.fetch({ limit: 5, cache: false }) + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a single ban + * guild.bans.fetch('351871113346809860') + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a single ban without checking cache + * guild.bans.fetch({ user, force: true }) + * .then(console.log) + * .catch(console.error) + * @example + * // Fetch a single ban without caching + * guild.bans.fetch({ user, cache: false }) + * .then(console.log) + * .catch(console.error); + */ + fetch(options) { + if (!options) return this._fetchMany(); + const { user, cache, force, limit, before, after } = options; + const resolvedUser = this.client.users.resolveId(user ?? options); + if (resolvedUser) return this._fetchSingle({ user: resolvedUser, cache, force }); + + if (!before && !after && !limit && cache === undefined) { + return Promise.reject(new DiscordjsError(ErrorCodes.FetchBanResolveId)); + } + + return this._fetchMany(options); + } + + async _fetchSingle({ user, cache, force = false }) { + if (!force) { + const existing = this.cache.get(user); + if (existing && !existing.partial) return existing; + } + + const data = await this.client.rest.get(Routes.guildBan(this.guild.id, user)); + return this._add(data, cache); + } + + async _fetchMany(options = {}) { + const data = await this.client.rest.get(Routes.guildBans(this.guild.id), { + query: makeURLSearchParams(options), + }); + + return data.reduce((col, ban) => col.set(ban.user.id, this._add(ban, options.cache)), new Collection()); + } + + /** + * Options used to ban a user from a guild. + * @typedef {Object} BanOptions + * @property {number} [deleteMessageDays] Number of days of messages to delete, must be between 0 and 7, inclusive + * <warn>This property is deprecated. Use `deleteMessageSeconds` instead.</warn> + * @property {number} [deleteMessageSeconds] Number of seconds of messages to delete, + * must be between 0 and 604800 (7 days), inclusive + * @property {string} [reason] The reason for the ban + */ + + /** + * Bans a user from the guild. + * @param {UserResolvable} user The user to ban + * @param {BanOptions} [options] Options for the ban + * @returns {Promise<GuildMember|User|Snowflake>} Result object will be resolved as specifically as possible. + * If the GuildMember cannot be resolved, the User will instead be attempted to be resolved. If that also cannot + * be resolved, the user id will be the result. + * @example + * // Ban a user by id (or with a user/guild member object) + * guild.bans.create('84484653687267328') + * .then(banInfo => console.log(`Banned ${banInfo.user?.tag ?? banInfo.tag ?? banInfo}`)) + * .catch(console.error); + */ + async create(user, options = {}) { + if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true); + const id = this.client.users.resolveId(user); + if (!id) throw new DiscordjsError(ErrorCodes.BanResolveId, true); + + if (options.deleteMessageDays !== undefined && !deprecationEmittedForDeleteMessageDays) { + process.emitWarning( + // eslint-disable-next-line max-len + 'The deleteMessageDays option for GuildBanManager#create() is deprecated. Use the deleteMessageSeconds option instead.', + 'DeprecationWarning', + ); + + deprecationEmittedForDeleteMessageDays = true; + } + + await this.client.rest.put(Routes.guildBan(this.guild.id, id), { + body: { + delete_message_seconds: + options.deleteMessageSeconds ?? + (options.deleteMessageDays ? options.deleteMessageDays * 24 * 60 * 60 : undefined), + }, + reason: options.reason, + }); + if (user instanceof GuildMember) return user; + const _user = this.client.users.resolve(id); + if (_user) { + return this.guild.members.resolve(_user) ?? _user; + } + return id; + } + + /** + * Unbans a user from the guild. + * @param {UserResolvable} user The user to unban + * @param {string} [reason] Reason for unbanning user + * @returns {Promise<?User>} + * @example + * // Unban a user by id (or with a user/guild member object) + * guild.bans.remove('84484653687267328') + * .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`)) + * .catch(console.error); + */ + async remove(user, reason) { + const id = this.client.users.resolveId(user); + if (!id) throw new DiscordjsError(ErrorCodes.BanResolveId); + await this.client.rest.delete(Routes.guildBan(this.guild.id, id), { reason }); + return this.client.users.resolve(user); + } +} + +module.exports = GuildBanManager; diff --git a/node_modules/discord.js/src/managers/GuildChannelManager.js b/node_modules/discord.js/src/managers/GuildChannelManager.js new file mode 100644 index 0000000..7ca9287 --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildChannelManager.js @@ -0,0 +1,503 @@ +'use strict'; + +const process = require('node:process'); +const { Collection } = require('@discordjs/collection'); +const { ChannelType, Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const GuildTextThreadManager = require('./GuildTextThreadManager'); +const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors'); +const GuildChannel = require('../structures/GuildChannel'); +const PermissionOverwrites = require('../structures/PermissionOverwrites'); +const ThreadChannel = require('../structures/ThreadChannel'); +const Webhook = require('../structures/Webhook'); +const ChannelFlagsBitField = require('../util/ChannelFlagsBitField'); +const { transformGuildForumTag, transformGuildDefaultReaction } = require('../util/Channels'); +const { ThreadChannelTypes } = require('../util/Constants'); +const DataResolver = require('../util/DataResolver'); +const { setPosition } = require('../util/Util'); + +let cacheWarningEmitted = false; + +/** + * Manages API methods for GuildChannels and stores their cache. + * @extends {CachedManager} + */ +class GuildChannelManager extends CachedManager { + constructor(guild, iterable) { + super(guild.client, GuildChannel, iterable); + const defaultCaching = + this._cache.constructor.name === 'Collection' || + this._cache.maxSize === undefined || + this._cache.maxSize === Infinity; + if (!cacheWarningEmitted && !defaultCaching) { + cacheWarningEmitted = true; + process.emitWarning( + `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`, + 'UnsupportedCacheOverwriteWarning', + ); + } + + /** + * The guild this Manager belongs to + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The number of channels in this managers cache excluding thread channels + * that do not count towards a guild's maximum channels restriction. + * @type {number} + * @readonly + */ + get channelCountWithoutThreads() { + return this.cache.reduce((acc, channel) => { + if (ThreadChannelTypes.includes(channel.type)) return acc; + return ++acc; + }, 0); + } + + /** + * The cache of this Manager + * @type {Collection<Snowflake, GuildChannel|ThreadChannel>} + * @name GuildChannelManager#cache + */ + + _add(channel) { + const existing = this.cache.get(channel.id); + if (existing) return existing; + this.cache.set(channel.id, channel); + return channel; + } + + /** + * Data that can be resolved to give a Guild Channel object. This can be: + * * A GuildChannel object + * * A ThreadChannel object + * * A Snowflake + * @typedef {GuildChannel|ThreadChannel|Snowflake} GuildChannelResolvable + */ + + /** + * Resolves a GuildChannelResolvable to a Channel object. + * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve + * @returns {?(GuildChannel|ThreadChannel)} + */ + resolve(channel) { + if (channel instanceof ThreadChannel) return super.resolve(channel.id); + return super.resolve(channel); + } + + /** + * Resolves a GuildChannelResolvable to a channel id. + * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve + * @returns {?Snowflake} + */ + resolveId(channel) { + if (channel instanceof ThreadChannel) return super.resolveId(channel.id); + return super.resolveId(channel); + } + + /** + * Adds the target channel to a channel's followers. + * @param {NewsChannel|Snowflake} channel The channel to follow + * @param {TextChannelResolvable} targetChannel The channel where published announcements will be posted at + * @param {string} [reason] Reason for creating the webhook + * @returns {Promise<Snowflake>} Returns created target webhook id. + */ + async addFollower(channel, targetChannel, reason) { + const channelId = this.resolveId(channel); + const targetChannelId = this.resolveId(targetChannel); + if (!channelId || !targetChannelId) throw new Error(ErrorCodes.GuildChannelResolve); + const { webhook_id } = await this.client.rest.post(Routes.channelFollowers(channelId), { + body: { webhook_channel_id: targetChannelId }, + reason, + }); + return webhook_id; + } + + /** + * Options used to create a new channel in a guild. + * @typedef {CategoryCreateChannelOptions} GuildChannelCreateOptions + * @property {?CategoryChannelResolvable} [parent] Parent of the new channel + */ + + /** + * Creates a new channel in the guild. + * @param {GuildChannelCreateOptions} options Options for creating the new channel + * @returns {Promise<GuildChannel>} + * @example + * // Create a new text channel + * guild.channels.create({ name: 'new-general', reason: 'Needed a cool new channel' }) + * .then(console.log) + * .catch(console.error); + * @example + * // Create a new channel with permission overwrites + * guild.channels.create({ + * name: 'new-general', + * type: ChannelType.GuildVoice, + * permissionOverwrites: [ + * { + * id: message.author.id, + * deny: [PermissionFlagsBits.ViewChannel], + * }, + * ], + * }) + */ + async create({ + name, + type, + topic, + nsfw, + bitrate, + userLimit, + parent, + permissionOverwrites, + position, + rateLimitPerUser, + rtcRegion, + videoQualityMode, + availableTags, + defaultReactionEmoji, + defaultAutoArchiveDuration, + defaultSortOrder, + defaultForumLayout, + reason, + }) { + parent &&= this.client.channels.resolveId(parent); + permissionOverwrites &&= permissionOverwrites.map(o => PermissionOverwrites.resolve(o, this.guild)); + + const data = await this.client.rest.post(Routes.guildChannels(this.guild.id), { + body: { + name, + topic, + type, + nsfw, + bitrate, + user_limit: userLimit, + parent_id: parent, + position, + permission_overwrites: permissionOverwrites, + rate_limit_per_user: rateLimitPerUser, + rtc_region: rtcRegion, + video_quality_mode: videoQualityMode, + available_tags: availableTags?.map(availableTag => transformGuildForumTag(availableTag)), + default_reaction_emoji: defaultReactionEmoji && transformGuildDefaultReaction(defaultReactionEmoji), + default_auto_archive_duration: defaultAutoArchiveDuration, + default_sort_order: defaultSortOrder, + default_forum_layout: defaultForumLayout, + }, + reason, + }); + return this.client.actions.ChannelCreate.handle(data).channel; + } + + /** + * @typedef {ChannelWebhookCreateOptions} WebhookCreateOptions + * @property {TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel|Snowflake} channel + * The channel to create the webhook for + */ + + /** + * Creates a webhook for the channel. + * @param {WebhookCreateOptions} options Options for creating the webhook + * @returns {Promise<Webhook>} Returns the created Webhook + * @example + * // Create a webhook for the current channel + * guild.channels.createWebhook({ + * channel: '222197033908436994', + * name: 'Snek', + * avatar: 'https://i.imgur.com/mI8XcpG.jpg', + * reason: 'Needed a cool new Webhook' + * }) + * .then(console.log) + * .catch(console.error) + */ + async createWebhook({ channel, name, avatar, reason }) { + const id = this.resolveId(channel); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable'); + if (typeof avatar === 'string' && !avatar.startsWith('data:')) { + avatar = await DataResolver.resolveImage(avatar); + } + const data = await this.client.rest.post(Routes.channelWebhooks(id), { + body: { + name, + avatar, + }, + reason, + }); + return new Webhook(this.client, data); + } + + /** + * Options used to edit a guild channel. + * @typedef {Object} GuildChannelEditOptions + * @property {string} [name] The name of the channel + * @property {ChannelType} [type] The type of the channel (only conversion between text and news is supported) + * @property {number} [position] The position of the channel + * @property {?string} [topic] The topic of the text channel + * @property {boolean} [nsfw] Whether the channel is NSFW + * @property {number} [bitrate] The bitrate of the voice channel + * @property {number} [userLimit] The user limit of the voice channel + * @property {?CategoryChannelResolvable} [parent] The parent of the channel + * @property {boolean} [lockPermissions] + * Lock the permissions of the channel to what the parent's permissions are + * @property {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} [permissionOverwrites] + * Permission overwrites for the channel + * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the channel in seconds + * @property {ThreadAutoArchiveDuration} [defaultAutoArchiveDuration] + * The default auto archive duration for all new threads in this channel + * @property {?string} [rtcRegion] The RTC region of the channel + * @property {?VideoQualityMode} [videoQualityMode] The camera video quality mode of the channel + * @property {GuildForumTagData[]} [availableTags] The tags to set as available in a forum channel + * @property {?DefaultReactionEmoji} [defaultReactionEmoji] The emoji to set as the default reaction emoji + * @property {number} [defaultThreadRateLimitPerUser] The rate limit per user (slowmode) to set on forum posts + * @property {ChannelFlagsResolvable} [flags] The flags to set on the channel + * @property {?SortOrderType} [defaultSortOrder] The default sort order mode to set on the channel + * @property {ForumLayoutType} [defaultForumLayout] The default forum layout to set on the channel + * @property {string} [reason] Reason for editing this channel + */ + + /** + * Edits the channel. + * @param {GuildChannelResolvable} channel The channel to edit + * @param {GuildChannelEditOptions} options Options for editing the channel + * @returns {Promise<GuildChannel>} + * @example + * // Edit a channel + * guild.channels.edit('222197033908436994', { name: 'new-channel' }) + * .then(console.log) + * .catch(console.error); + */ + async edit(channel, options) { + channel = this.resolve(channel); + if (!channel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable'); + + const parent = options.parent && this.client.channels.resolveId(options.parent); + + if (options.position !== undefined) { + await this.setPosition(channel, options.position, { position: options.position, reason: options.reason }); + } + + let permission_overwrites = options.permissionOverwrites?.map(o => PermissionOverwrites.resolve(o, this.guild)); + + if (options.lockPermissions) { + if (parent) { + const newParent = this.guild.channels.resolve(parent); + if (newParent?.type === ChannelType.GuildCategory) { + permission_overwrites = newParent.permissionOverwrites.cache.map(o => + PermissionOverwrites.resolve(o, this.guild), + ); + } + } else if (channel.parent) { + permission_overwrites = channel.parent.permissionOverwrites.cache.map(o => + PermissionOverwrites.resolve(o, this.guild), + ); + } + } + + const newData = await this.client.rest.patch(Routes.channel(channel.id), { + body: { + name: (options.name ?? channel.name).trim(), + type: options.type, + topic: options.topic, + nsfw: options.nsfw, + bitrate: options.bitrate ?? channel.bitrate, + user_limit: options.userLimit ?? channel.userLimit, + rtc_region: 'rtcRegion' in options ? options.rtcRegion : channel.rtcRegion, + video_quality_mode: options.videoQualityMode, + parent_id: parent, + lock_permissions: options.lockPermissions, + rate_limit_per_user: options.rateLimitPerUser, + default_auto_archive_duration: options.defaultAutoArchiveDuration, + permission_overwrites, + available_tags: options.availableTags?.map(availableTag => transformGuildForumTag(availableTag)), + default_reaction_emoji: + options.defaultReactionEmoji && transformGuildDefaultReaction(options.defaultReactionEmoji), + default_thread_rate_limit_per_user: options.defaultThreadRateLimitPerUser, + flags: 'flags' in options ? ChannelFlagsBitField.resolve(options.flags) : undefined, + default_sort_order: options.defaultSortOrder, + default_forum_layout: options.defaultForumLayout, + }, + reason: options.reason, + }); + + return this.client.actions.ChannelUpdate.handle(newData).updated; + } + + /** + * Sets a new position for the guild channel. + * @param {GuildChannelResolvable} channel The channel to set the position for + * @param {number} position The new position for the guild channel + * @param {SetChannelPositionOptions} options Options for setting position + * @returns {Promise<GuildChannel>} + * @example + * // Set a new channel position + * guild.channels.setPosition('222078374472843266', 2) + * .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`)) + * .catch(console.error); + */ + async setPosition(channel, position, { relative, reason } = {}) { + channel = this.resolve(channel); + if (!channel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable'); + const updatedChannels = await setPosition( + channel, + position, + relative, + this.guild._sortedChannels(channel), + this.client, + Routes.guildChannels(this.guild.id), + reason, + ); + + this.client.actions.GuildChannelsPositionUpdate.handle({ + guild_id: this.guild.id, + channels: updatedChannels, + }); + return channel; + } + + /** + * Obtains one or more guild channels from Discord, or the channel cache if they're already available. + * @param {Snowflake} [id] The channel's id + * @param {BaseFetchOptions} [options] Additional options for this fetch + * @returns {Promise<?GuildChannel|ThreadChannel|Collection<Snowflake, ?GuildChannel>>} + * @example + * // Fetch all channels from the guild (excluding threads) + * message.guild.channels.fetch() + * .then(channels => console.log(`There are ${channels.size} channels.`)) + * .catch(console.error); + * @example + * // Fetch a single channel + * message.guild.channels.fetch('222197033908436994') + * .then(channel => console.log(`The channel name is: ${channel.name}`)) + * .catch(console.error); + */ + async fetch(id, { cache = true, force = false } = {}) { + if (id && !force) { + const existing = this.cache.get(id); + if (existing) return existing; + } + + if (id) { + const data = await this.client.rest.get(Routes.channel(id)); + // Since this is the guild manager, throw if on a different guild + if (this.guild.id !== data.guild_id) throw new DiscordjsError(ErrorCodes.GuildChannelUnowned); + return this.client.channels._add(data, this.guild, { cache }); + } + + const data = await this.client.rest.get(Routes.guildChannels(this.guild.id)); + const channels = new Collection(); + for (const channel of data) channels.set(channel.id, this.client.channels._add(channel, this.guild, { cache })); + return channels; + } + + /** + * Fetches all webhooks for the channel. + * @param {GuildChannelResolvable} channel The channel to fetch webhooks for + * @returns {Promise<Collection<Snowflake, Webhook>>} + * @example + * // Fetch webhooks + * guild.channels.fetchWebhooks('769862166131245066') + * .then(hooks => console.log(`This channel has ${hooks.size} hooks`)) + * .catch(console.error); + */ + async fetchWebhooks(channel) { + const id = this.resolveId(channel); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable'); + const data = await this.client.rest.get(Routes.channelWebhooks(id)); + return data.reduce((hooks, hook) => hooks.set(hook.id, new Webhook(this.client, hook)), new Collection()); + } + + /** + * Data that can be resolved to give a Category Channel object. This can be: + * * A CategoryChannel object + * * A Snowflake + * @typedef {CategoryChannel|Snowflake} CategoryChannelResolvable + */ + + /** + * The data needed for updating a channel's position. + * @typedef {Object} ChannelPosition + * @property {GuildChannel|Snowflake} channel Channel to update + * @property {number} [position] New position for the channel + * @property {CategoryChannelResolvable} [parent] Parent channel for this channel + * @property {boolean} [lockPermissions] If the overwrites should be locked to the parents overwrites + */ + + /** + * Batch-updates the guild's channels' positions. + * <info>Only one channel's parent can be changed at a time</info> + * @param {ChannelPosition[]} channelPositions Channel positions to update + * @returns {Promise<Guild>} + * @example + * guild.channels.setPositions([{ channel: channelId, position: newChannelIndex }]) + * .then(guild => console.log(`Updated channel positions for ${guild}`)) + * .catch(console.error); + */ + async setPositions(channelPositions) { + channelPositions = channelPositions.map(r => ({ + id: this.client.channels.resolveId(r.channel), + position: r.position, + lock_permissions: r.lockPermissions, + parent_id: r.parent !== undefined ? this.resolveId(r.parent) : undefined, + })); + + await this.client.rest.patch(Routes.guildChannels(this.guild.id), { body: channelPositions }); + return this.client.actions.GuildChannelsPositionUpdate.handle({ + guild_id: this.guild.id, + channels: channelPositions, + }).guild; + } + + /** + * Data returned from fetching threads. + * @typedef {Object} FetchedThreads + * @property {Collection<Snowflake, ThreadChannel>} threads The threads that were fetched + * @property {Collection<Snowflake, ThreadMember>} members The thread members in the received threads + */ + + /** + * Obtains all active thread channels in the guild. + * @param {boolean} [cache=true] Whether to cache the fetched data + * @returns {Promise<FetchedThreads>} + * @example + * // Fetch all threads from the guild + * message.guild.channels.fetchActiveThreads() + * .then(fetched => console.log(`There are ${fetched.threads.size} threads.`)) + * .catch(console.error); + */ + async fetchActiveThreads(cache = true) { + const data = await this.rawFetchGuildActiveThreads(); + return GuildTextThreadManager._mapThreads(data, this.client, { guild: this.guild, cache }); + } + + /** + * `GET /guilds/{guild.id}/threads/active` + * @private + * @returns {Promise<RESTGetAPIGuildThreadsResult>} + */ + rawFetchGuildActiveThreads() { + return this.client.rest.get(Routes.guildActiveThreads(this.guild.id)); + } + + /** + * Deletes the channel. + * @param {GuildChannelResolvable} channel The channel to delete + * @param {string} [reason] Reason for deleting this channel + * @returns {Promise<void>} + * @example + * // Delete the channel + * guild.channels.delete('858850993013260338', 'making room for new channels') + * .then(console.log) + * .catch(console.error); + */ + async delete(channel, reason) { + const id = this.resolveId(channel); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable'); + await this.client.rest.delete(Routes.channel(id), { reason }); + this.client.actions.ChannelDelete.handle({ id }); + } +} + +module.exports = GuildChannelManager; diff --git a/node_modules/discord.js/src/managers/GuildEmojiManager.js b/node_modules/discord.js/src/managers/GuildEmojiManager.js new file mode 100644 index 0000000..61f5050 --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildEmojiManager.js @@ -0,0 +1,174 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { Routes, PermissionFlagsBits } = require('discord-api-types/v10'); +const BaseGuildEmojiManager = require('./BaseGuildEmojiManager'); +const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors'); +const DataResolver = require('../util/DataResolver'); + +/** + * Manages API methods for GuildEmojis and stores their cache. + * @extends {BaseGuildEmojiManager} + */ +class GuildEmojiManager extends BaseGuildEmojiManager { + constructor(guild, iterable) { + super(guild.client, iterable); + + /** + * The guild this manager belongs to + * @type {Guild} + */ + this.guild = guild; + } + + _add(data, cache) { + return super._add(data, cache, { extras: [this.guild] }); + } + + /** + * Options used for creating an emoji in a guild. + * @typedef {Object} GuildEmojiCreateOptions + * @property {BufferResolvable|Base64Resolvable} attachment The image for the emoji + * @property {string} name The name for the emoji + * @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] The roles to limit the emoji to + * @property {string} [reason] The reason for creating the emoji + */ + + /** + * Creates a new custom emoji in the guild. + * @param {GuildEmojiCreateOptions} options Options for creating the emoji + * @returns {Promise<Emoji>} The created emoji + * @example + * // Create a new emoji from a URL + * guild.emojis.create({ attachment: 'https://i.imgur.com/w3duR07.png', name: 'rip' }) + * .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`)) + * .catch(console.error); + * @example + * // Create a new emoji from a file on your computer + * guild.emojis.create({ attachment: './memes/banana.png', name: 'banana' }) + * .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`)) + * .catch(console.error); + */ + async create({ attachment, name, roles, reason }) { + attachment = await DataResolver.resolveImage(attachment); + if (!attachment) throw new DiscordjsTypeError(ErrorCodes.ReqResourceType); + + const body = { image: attachment, name }; + if (roles) { + if (!Array.isArray(roles) && !(roles instanceof Collection)) { + throw new DiscordjsTypeError( + ErrorCodes.InvalidType, + 'options.roles', + 'Array or Collection of Roles or Snowflakes', + true, + ); + } + body.roles = []; + for (const role of roles.values()) { + const resolvedRole = this.guild.roles.resolveId(role); + if (!resolvedRole) { + throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'options.roles', role); + } + body.roles.push(resolvedRole); + } + } + + const emoji = await this.client.rest.post(Routes.guildEmojis(this.guild.id), { body, reason }); + return this.client.actions.GuildEmojiCreate.handle(this.guild, emoji).emoji; + } + + /** + * Obtains one or more emojis from Discord, or the emoji cache if they're already available. + * @param {Snowflake} [id] The emoji's id + * @param {BaseFetchOptions} [options] Additional options for this fetch + * @returns {Promise<GuildEmoji|Collection<Snowflake, GuildEmoji>>} + * @example + * // Fetch all emojis from the guild + * message.guild.emojis.fetch() + * .then(emojis => console.log(`There are ${emojis.size} emojis.`)) + * .catch(console.error); + * @example + * // Fetch a single emoji + * message.guild.emojis.fetch('222078108977594368') + * .then(emoji => console.log(`The emoji name is: ${emoji.name}`)) + * .catch(console.error); + */ + async fetch(id, { cache = true, force = false } = {}) { + if (id) { + if (!force) { + const existing = this.cache.get(id); + if (existing) return existing; + } + const emoji = await this.client.rest.get(Routes.guildEmoji(this.guild.id, id)); + return this._add(emoji, cache); + } + + const data = await this.client.rest.get(Routes.guildEmojis(this.guild.id)); + const emojis = new Collection(); + for (const emoji of data) emojis.set(emoji.id, this._add(emoji, cache)); + return emojis; + } + + /** + * Deletes an emoji. + * @param {EmojiResolvable} emoji The Emoji resolvable to delete + * @param {string} [reason] Reason for deleting the emoji + * @returns {Promise<void>} + */ + async delete(emoji, reason) { + const id = this.resolveId(emoji); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true); + await this.client.rest.delete(Routes.guildEmoji(this.guild.id, id), { reason }); + } + + /** + * Edits an emoji. + * @param {EmojiResolvable} emoji The Emoji resolvable to edit + * @param {GuildEmojiEditOptions} options The options to provide + * @returns {Promise<GuildEmoji>} + */ + async edit(emoji, options) { + const id = this.resolveId(emoji); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true); + const roles = options.roles?.map(r => this.guild.roles.resolveId(r)); + const newData = await this.client.rest.patch(Routes.guildEmoji(this.guild.id, id), { + body: { + name: options.name, + roles, + }, + reason: options.reason, + }); + const existing = this.cache.get(id); + if (existing) { + const clone = existing._clone(); + clone._patch(newData); + return clone; + } + return this._add(newData); + } + + /** + * Fetches the author for this emoji + * @param {EmojiResolvable} emoji The emoji to fetch the author of + * @returns {Promise<User>} + */ + async fetchAuthor(emoji) { + emoji = this.resolve(emoji); + if (!emoji) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true); + if (emoji.managed) { + throw new DiscordjsError(ErrorCodes.EmojiManaged); + } + + const { me } = this.guild.members; + if (!me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe); + if (!me.permissions.has(PermissionFlagsBits.ManageGuildExpressions)) { + throw new DiscordjsError(ErrorCodes.MissingManageGuildExpressionsPermission, this.guild); + } + + const data = await this.client.rest.get(Routes.guildEmoji(this.guild.id, emoji.id)); + emoji._patch(data); + return emoji.author; + } +} + +module.exports = GuildEmojiManager; diff --git a/node_modules/discord.js/src/managers/GuildEmojiRoleManager.js b/node_modules/discord.js/src/managers/GuildEmojiRoleManager.js new file mode 100644 index 0000000..7b97f41 --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildEmojiRoleManager.js @@ -0,0 +1,118 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const DataManager = require('./DataManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const { Role } = require('../structures/Role'); + +/** + * Manages API methods for roles belonging to emojis and stores their cache. + * @extends {DataManager} + */ +class GuildEmojiRoleManager extends DataManager { + constructor(emoji) { + super(emoji.client, Role); + + /** + * The emoji belonging to this manager + * @type {GuildEmoji} + */ + this.emoji = emoji; + /** + * The guild belonging to this manager + * @type {Guild} + */ + this.guild = emoji.guild; + } + + /** + * The cache of roles belonging to this emoji + * @type {Collection<Snowflake, Role>} + * @readonly + */ + get cache() { + return this.guild.roles.cache.filter(role => this.emoji._roles.includes(role.id)); + } + + /** + * Adds a role (or multiple roles) to the list of roles that can use this emoji. + * @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to add + * @returns {Promise<GuildEmoji>} + */ + add(roleOrRoles) { + if (!Array.isArray(roleOrRoles) && !(roleOrRoles instanceof Collection)) roleOrRoles = [roleOrRoles]; + + const resolvedRoles = []; + for (const role of roleOrRoles.values()) { + const resolvedRole = this.guild.roles.resolveId(role); + if (!resolvedRole) { + return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role)); + } + resolvedRoles.push(resolvedRole); + } + + const newRoles = [...new Set(resolvedRoles.concat(...this.cache.keys()))]; + return this.set(newRoles); + } + + /** + * Removes a role (or multiple roles) from the list of roles that can use this emoji. + * @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to remove + * @returns {Promise<GuildEmoji>} + */ + remove(roleOrRoles) { + if (!Array.isArray(roleOrRoles) && !(roleOrRoles instanceof Collection)) roleOrRoles = [roleOrRoles]; + + const resolvedRoleIds = []; + for (const role of roleOrRoles.values()) { + const roleId = this.guild.roles.resolveId(role); + if (!roleId) { + return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role)); + } + resolvedRoleIds.push(roleId); + } + + const newRoles = [...this.cache.keys()].filter(id => !resolvedRoleIds.includes(id)); + return this.set(newRoles); + } + + /** + * Sets the role(s) that can use this emoji. + * @param {Collection<Snowflake, Role>|RoleResolvable[]} roles The roles or role ids to apply + * @returns {Promise<GuildEmoji>} + * @example + * // Set the emoji's roles to a single role + * guildEmoji.roles.set(['391156570408615936']) + * .then(console.log) + * .catch(console.error); + * @example + * // Remove all roles from an emoji + * guildEmoji.roles.set([]) + * .then(console.log) + * .catch(console.error); + */ + set(roles) { + return this.emoji.edit({ roles }); + } + + clone() { + const clone = new this.constructor(this.emoji); + clone._patch([...this.cache.keys()]); + return clone; + } + + /** + * Patches the roles for this manager's cache + * @param {Snowflake[]} roles The new roles + * @private + */ + _patch(roles) { + this.emoji._roles = roles; + } + + valueOf() { + return this.cache; + } +} + +module.exports = GuildEmojiRoleManager; diff --git a/node_modules/discord.js/src/managers/GuildForumThreadManager.js b/node_modules/discord.js/src/managers/GuildForumThreadManager.js new file mode 100644 index 0000000..f830b98 --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildForumThreadManager.js @@ -0,0 +1,83 @@ +'use strict'; + +const { Routes } = require('discord-api-types/v10'); +const ThreadManager = require('./ThreadManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const MessagePayload = require('../structures/MessagePayload'); + +/** + * Manages API methods for threads in forum channels and stores their cache. + * @extends {ThreadManager} + */ +class GuildForumThreadManager extends ThreadManager { + /** + * The channel this Manager belongs to + * @name GuildForumThreadManager#channel + * @type {ForumChannel} + */ + + /** + * @typedef {BaseMessageOptions} GuildForumThreadMessageCreateOptions + * @property {StickerResolvable} [stickers] The stickers to send with the message + * @property {BitFieldResolvable} [flags] The flags to send with the message + * <info>Only `MessageFlags.SuppressEmbeds` and `MessageFlags.SuppressNotifications` can be set.</info> + */ + + /** + * Options for creating a thread. + * @typedef {StartThreadOptions} GuildForumThreadCreateOptions + * @property {GuildForumThreadMessageCreateOptions|MessagePayload} message The message associated with the thread post + * @property {Snowflake[]} [appliedTags] The tags to apply to the thread + */ + + /** + * Creates a new thread in the channel. + * @param {GuildForumThreadCreateOptions} [options] Options to create a new thread + * @returns {Promise<ThreadChannel>} + * @example + * // Create a new forum post + * forum.threads + * .create({ + * name: 'Food Talk', + * autoArchiveDuration: ThreadAutoArchiveDuration.OneHour, + * message: { + * content: 'Discuss your favorite food!', + * }, + * reason: 'Needed a separate thread for food', + * }) + * .then(threadChannel => console.log(threadChannel)) + * .catch(console.error); + */ + async create({ + name, + autoArchiveDuration = this.channel.defaultAutoArchiveDuration, + message, + reason, + rateLimitPerUser, + appliedTags, + } = {}) { + if (!message) { + throw new DiscordjsTypeError(ErrorCodes.GuildForumMessageRequired); + } + + const { body, files } = await (message instanceof MessagePayload ? message : MessagePayload.create(this, message)) + .resolveBody() + .resolveFiles(); + + const data = await this.client.rest.post(Routes.threads(this.channel.id), { + body: { + name, + auto_archive_duration: autoArchiveDuration, + rate_limit_per_user: rateLimitPerUser, + applied_tags: appliedTags, + message: body, + }, + files, + reason, + }); + + return this.client.actions.ThreadCreate.handle(data).thread; + } +} + +module.exports = GuildForumThreadManager; diff --git a/node_modules/discord.js/src/managers/GuildInviteManager.js b/node_modules/discord.js/src/managers/GuildInviteManager.js new file mode 100644 index 0000000..f1fe3eb --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildInviteManager.js @@ -0,0 +1,214 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const Invite = require('../structures/Invite'); +const DataResolver = require('../util/DataResolver'); + +/** + * Manages API methods for GuildInvites and stores their cache. + * @extends {CachedManager} + */ +class GuildInviteManager extends CachedManager { + constructor(guild, iterable) { + super(guild.client, Invite, iterable); + + /** + * The guild this Manager belongs to + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The cache of this Manager + * @type {Collection<string, Invite>} + * @name GuildInviteManager#cache + */ + + _add(data, cache) { + return super._add(data, cache, { id: data.code, extras: [this.guild] }); + } + + /** + * Data that resolves to give an Invite object. This can be: + * * An invite code + * * An invite URL + * @typedef {string} InviteResolvable + */ + + /** + * Data that can be resolved to a channel that an invite can be created on. This can be: + * * TextChannel + * * VoiceChannel + * * NewsChannel + * * StageChannel + * * ForumChannel + * * Snowflake + * @typedef {TextChannel|VoiceChannel|NewsChannel|StageChannel|ForumChannel|Snowflake} + * GuildInvitableChannelResolvable + */ + + /** + * Resolves an InviteResolvable to an Invite object. + * @method resolve + * @memberof GuildInviteManager + * @instance + * @param {InviteResolvable} invite The invite resolvable to resolve + * @returns {?Invite} + */ + + /** + * Resolves an InviteResolvable to an invite code string. + * @method resolveId + * @memberof GuildInviteManager + * @instance + * @param {InviteResolvable} invite The invite resolvable to resolve + * @returns {?string} + */ + + /** + * Options used to fetch a single invite from a guild. + * @typedef {Object} FetchInviteOptions + * @property {InviteResolvable} code The invite to fetch + * @property {boolean} [cache=true] Whether or not to cache the fetched invite + * @property {boolean} [force=false] Whether to skip the cache check and request the API + */ + + /** + * Options used to fetch all invites from a guild. + * @typedef {Object} FetchInvitesOptions + * @property {GuildInvitableChannelResolvable} [channelId] + * The channel to fetch all invites from + * @property {boolean} [cache=true] Whether or not to cache the fetched invites + */ + + /** + * Fetches invite(s) from Discord. + * @param {InviteResolvable|FetchInviteOptions|FetchInvitesOptions} [options] Options for fetching guild invite(s) + * @returns {Promise<Invite|Collection<string, Invite>>} + * @example + * // Fetch all invites from a guild + * guild.invites.fetch() + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch all invites from a guild without caching + * guild.invites.fetch({ cache: false }) + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch all invites from a channel + * guild.invites.fetch({ channelId: '222197033908436994' }) + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a single invite + * guild.invites.fetch('bRCvFy9') + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a single invite without checking cache + * guild.invites.fetch({ code: 'bRCvFy9', force: true }) + * .then(console.log) + * .catch(console.error) + * @example + * // Fetch a single invite without caching + * guild.invites.fetch({ code: 'bRCvFy9', cache: false }) + * .then(console.log) + * .catch(console.error); + */ + fetch(options) { + if (!options) return this._fetchMany(); + if (typeof options === 'string') { + const code = DataResolver.resolveInviteCode(options); + if (!code) return Promise.reject(new DiscordjsError(ErrorCodes.InviteResolveCode)); + return this._fetchSingle({ code, cache: true }); + } + if (!options.code) { + if (options.channelId) { + const id = this.guild.channels.resolveId(options.channelId); + if (!id) return Promise.reject(new DiscordjsError(ErrorCodes.GuildChannelResolve)); + return this._fetchChannelMany(id, options.cache); + } + + if ('cache' in options) return this._fetchMany(options.cache); + return Promise.reject(new DiscordjsError(ErrorCodes.InviteResolveCode)); + } + return this._fetchSingle({ + ...options, + code: DataResolver.resolveInviteCode(options.code), + }); + } + + async _fetchSingle({ code, cache, force = false }) { + if (!force) { + const existing = this.cache.get(code); + if (existing) return existing; + } + + const invites = await this._fetchMany(cache); + const invite = invites.get(code); + if (!invite) throw new DiscordjsError(ErrorCodes.InviteNotFound); + return invite; + } + + async _fetchMany(cache) { + const data = await this.client.rest.get(Routes.guildInvites(this.guild.id)); + return data.reduce((col, invite) => col.set(invite.code, this._add(invite, cache)), new Collection()); + } + + async _fetchChannelMany(channelId, cache) { + const data = await this.client.rest.get(Routes.channelInvites(channelId)); + return data.reduce((col, invite) => col.set(invite.code, this._add(invite, cache)), new Collection()); + } + + /** + * Create an invite to the guild from the provided channel. + * @param {GuildInvitableChannelResolvable} channel The options for creating the invite from a channel. + * @param {InviteCreateOptions} [options={}] The options for creating the invite from a channel. + * @returns {Promise<Invite>} + * @example + * // Create an invite to a selected channel + * guild.invites.create('599942732013764608') + * .then(console.log) + * .catch(console.error); + */ + async create( + channel, + { temporary, maxAge, maxUses, unique, targetUser, targetApplication, targetType, reason } = {}, + ) { + const id = this.guild.channels.resolveId(channel); + if (!id) throw new DiscordjsError(ErrorCodes.GuildChannelResolve); + + const invite = await this.client.rest.post(Routes.channelInvites(id), { + body: { + temporary, + max_age: maxAge, + max_uses: maxUses, + unique, + target_user_id: this.client.users.resolveId(targetUser), + target_application_id: targetApplication?.id ?? targetApplication?.applicationId ?? targetApplication, + target_type: targetType, + }, + reason, + }); + return new Invite(this.client, invite); + } + + /** + * Deletes an invite. + * @param {InviteResolvable} invite The invite to delete + * @param {string} [reason] Reason for deleting the invite + * @returns {Promise<void>} + */ + async delete(invite, reason) { + const code = DataResolver.resolveInviteCode(invite); + + await this.client.rest.delete(Routes.invite(code), { reason }); + } +} + +module.exports = GuildInviteManager; diff --git a/node_modules/discord.js/src/managers/GuildManager.js b/node_modules/discord.js/src/managers/GuildManager.js new file mode 100644 index 0000000..1d2d4ba --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildManager.js @@ -0,0 +1,283 @@ +'use strict'; + +const process = require('node:process'); +const { setTimeout, clearTimeout } = require('node:timers'); +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { Guild } = require('../structures/Guild'); +const GuildChannel = require('../structures/GuildChannel'); +const GuildEmoji = require('../structures/GuildEmoji'); +const { GuildMember } = require('../structures/GuildMember'); +const Invite = require('../structures/Invite'); +const OAuth2Guild = require('../structures/OAuth2Guild'); +const { Role } = require('../structures/Role'); +const DataResolver = require('../util/DataResolver'); +const Events = require('../util/Events'); +const PermissionsBitField = require('../util/PermissionsBitField'); +const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField'); +const { resolveColor } = require('../util/Util'); + +let cacheWarningEmitted = false; + +/** + * Manages API methods for Guilds and stores their cache. + * @extends {CachedManager} + */ +class GuildManager extends CachedManager { + constructor(client, iterable) { + super(client, Guild, iterable); + if (!cacheWarningEmitted && this._cache.constructor.name !== 'Collection') { + cacheWarningEmitted = true; + process.emitWarning( + `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`, + 'UnsupportedCacheOverwriteWarning', + ); + } + } + + /** + * The cache of this Manager + * @type {Collection<Snowflake, Guild>} + * @name GuildManager#cache + */ + + /** + * Data that resolves to give a Guild object. This can be: + * * A Guild object + * * A GuildChannel object + * * A GuildEmoji object + * * A Role object + * * A Snowflake + * * An Invite object + * @typedef {Guild|GuildChannel|GuildMember|GuildEmoji|Role|Snowflake|Invite} GuildResolvable + */ + + /** + * Partial data for a Role. + * @typedef {Object} PartialRoleData + * @property {Snowflake|number} [id] The role's id, used to set channel overrides. + * This is a placeholder and will be replaced by the API after consumption + * @property {string} [name] The name of the role + * @property {ColorResolvable} [color] The color of the role, either a hex string or a base 10 number + * @property {boolean} [hoist] Whether the role should be hoisted + * @property {number} [position] The position of the role + * @property {PermissionResolvable} [permissions] The permissions of the role + * @property {boolean} [mentionable] Whether the role should be mentionable + */ + + /** + * Partial overwrite data. + * @typedef {Object} PartialOverwriteData + * @property {Snowflake|number} id The id of the {@link Role} or {@link User} this overwrite belongs to + * @property {OverwriteType} [type] The type of this overwrite + * @property {PermissionResolvable} [allow] The permissions to allow + * @property {PermissionResolvable} [deny] The permissions to deny + */ + + /** + * Partial data for a Channel. + * @typedef {Object} PartialChannelData + * @property {Snowflake|number} [id] The channel's id, used to set its parent. + * This is a placeholder and will be replaced by the API after consumption + * @property {Snowflake|number} [parentId] The parent id for this channel + * @property {ChannelType.GuildText|ChannelType.GuildVoice|ChannelType.GuildCategory} [type] The type of the channel + * @property {string} name The name of the channel + * @property {?string} [topic] The topic of the text channel + * @property {boolean} [nsfw] Whether the channel is NSFW + * @property {number} [bitrate] The bitrate of the voice channel + * @property {number} [userLimit] The user limit of the channel + * @property {?string} [rtcRegion] The RTC region of the channel + * @property {VideoQualityMode} [videoQualityMode] The camera video quality mode of the channel + * @property {PartialOverwriteData[]} [permissionOverwrites] + * Overwrites of the channel + * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) of the channel in seconds + */ + + /** + * Resolves a GuildResolvable to a Guild object. + * @method resolve + * @memberof GuildManager + * @instance + * @param {GuildResolvable} guild The guild resolvable to identify + * @returns {?Guild} + */ + resolve(guild) { + if ( + guild instanceof GuildChannel || + guild instanceof GuildMember || + guild instanceof GuildEmoji || + guild instanceof Role || + (guild instanceof Invite && guild.guild) + ) { + return super.resolve(guild.guild); + } + return super.resolve(guild); + } + + /** + * Resolves a {@link GuildResolvable} to a {@link Guild} id string. + * @method resolveId + * @memberof GuildManager + * @instance + * @param {GuildResolvable} guild The guild resolvable to identify + * @returns {?Snowflake} + */ + resolveId(guild) { + if ( + guild instanceof GuildChannel || + guild instanceof GuildMember || + guild instanceof GuildEmoji || + guild instanceof Role || + (guild instanceof Invite && guild.guild) + ) { + return super.resolveId(guild.guild.id); + } + return super.resolveId(guild); + } + + /** + * Options used to create a guild. + * @typedef {Object} GuildCreateOptions + * @property {string} name The name of the guild + * @property {?(BufferResolvable|Base64Resolvable)} [icon=null] The icon for the guild + * @property {GuildVerificationLevel} [verificationLevel] The verification level for the guild + * @property {GuildDefaultMessageNotifications} [defaultMessageNotifications] The default message notifications + * for the guild + * @property {GuildExplicitContentFilter} [explicitContentFilter] The explicit content filter level for the guild + * @property {PartialRoleData[]} [roles=[]] The roles for this guild, + * @property {PartialChannelData[]} [channels=[]] The channels for this guild + * @property {Snowflake|number} [afkChannelId] The AFK channel's id + * @property {number} [afkTimeout] The AFK timeout in seconds + * the first element of this array is used to change properties of the guild's everyone role. + * @property {Snowflake|number} [systemChannelId] The system channel's id + * @property {SystemChannelFlagsResolvable} [systemChannelFlags] The flags of the system channel + */ + /* eslint-enable max-len */ + + /** + * Creates a guild. + * <warn>This is only available to bots in fewer than 10 guilds.</warn> + * @param {GuildCreateOptions} options Options for creating the guild + * @returns {Promise<Guild>} The guild that was created + */ + async create({ + name, + icon = null, + verificationLevel, + defaultMessageNotifications, + explicitContentFilter, + roles = [], + channels = [], + afkChannelId, + afkTimeout, + systemChannelId, + systemChannelFlags, + }) { + const data = await this.client.rest.post(Routes.guilds(), { + body: { + name, + icon: icon && (await DataResolver.resolveImage(icon)), + verification_level: verificationLevel, + default_message_notifications: defaultMessageNotifications, + explicit_content_filter: explicitContentFilter, + roles: roles.map(({ color, permissions, ...options }) => ({ + ...options, + color: color && resolveColor(color), + permissions: permissions === undefined ? undefined : PermissionsBitField.resolve(permissions).toString(), + })), + channels: channels.map( + ({ + parentId, + userLimit, + rtcRegion, + videoQualityMode, + permissionOverwrites, + rateLimitPerUser, + ...options + }) => ({ + ...options, + parent_id: parentId, + user_limit: userLimit, + rtc_region: rtcRegion, + video_quality_mode: videoQualityMode, + permission_overwrites: permissionOverwrites?.map(({ allow, deny, ...permissionOverwriteOptions }) => ({ + ...permissionOverwriteOptions, + allow: allow === undefined ? undefined : PermissionsBitField.resolve(allow).toString(), + deny: deny === undefined ? undefined : PermissionsBitField.resolve(deny).toString(), + })), + rate_limit_per_user: rateLimitPerUser, + }), + ), + afk_channel_id: afkChannelId, + afk_timeout: afkTimeout, + system_channel_id: systemChannelId, + system_channel_flags: + systemChannelFlags === undefined ? undefined : SystemChannelFlagsBitField.resolve(systemChannelFlags), + }, + }); + + return ( + this.client.guilds.cache.get(data.id) ?? + new Promise(resolve => { + const handleGuild = guild => { + if (guild.id === data.id) { + clearTimeout(timeout); + this.client.decrementMaxListeners(); + resolve(guild); + } + }; + this.client.incrementMaxListeners(); + this.client.once(Events.GuildCreate, handleGuild); + + const timeout = setTimeout(() => { + this.client.removeListener(Events.GuildCreate, handleGuild); + this.client.decrementMaxListeners(); + resolve(this.client.guilds._add(data)); + }, 10_000).unref(); + }) + ); + } + + /** + * Options used to fetch a single guild. + * @typedef {BaseFetchOptions} FetchGuildOptions + * @property {GuildResolvable} guild The guild to fetch + * @property {boolean} [withCounts=true] Whether the approximate member and presence counts should be returned + */ + + /** + * Options used to fetch multiple guilds. + * @typedef {Object} FetchGuildsOptions + * @property {Snowflake} [before] Get guilds before this guild id + * @property {Snowflake} [after] Get guilds after this guild id + * @property {number} [limit] Maximum number of guilds to request (1-200) + */ + + /** + * Obtains one or multiple guilds from Discord, or the guild cache if it's already available. + * @param {GuildResolvable|FetchGuildOptions|FetchGuildsOptions} [options] The guild's id or options + * @returns {Promise<Guild|Collection<Snowflake, OAuth2Guild>>} + */ + async fetch(options = {}) { + const id = this.resolveId(options) ?? this.resolveId(options.guild); + + if (id) { + if (!options.force) { + const existing = this.cache.get(id); + if (existing) return existing; + } + + const data = await this.client.rest.get(Routes.guild(id), { + query: makeURLSearchParams({ with_counts: options.withCounts ?? true }), + }); + return this._add(data, options.cache); + } + + const data = await this.client.rest.get(Routes.userGuilds(), { query: makeURLSearchParams(options) }); + return data.reduce((coll, guild) => coll.set(guild.id, new OAuth2Guild(this.client, guild)), new Collection()); + } +} + +module.exports = GuildManager; diff --git a/node_modules/discord.js/src/managers/GuildMemberManager.js b/node_modules/discord.js/src/managers/GuildMemberManager.js new file mode 100644 index 0000000..a4cf09b --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildMemberManager.js @@ -0,0 +1,540 @@ +'use strict'; + +const { setTimeout, clearTimeout } = require('node:timers'); +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { Routes, GatewayOpcodes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } = require('../errors'); +const BaseGuildVoiceChannel = require('../structures/BaseGuildVoiceChannel'); +const { GuildMember } = require('../structures/GuildMember'); +const { Role } = require('../structures/Role'); +const Events = require('../util/Events'); +const { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField'); +const Partials = require('../util/Partials'); + +/** + * Manages API methods for GuildMembers and stores their cache. + * @extends {CachedManager} + */ +class GuildMemberManager extends CachedManager { + constructor(guild, iterable) { + super(guild.client, GuildMember, iterable); + + /** + * The guild this manager belongs to + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The cache of this Manager + * @type {Collection<Snowflake, GuildMember>} + * @name GuildMemberManager#cache + */ + + _add(data, cache = true) { + return super._add(data, cache, { id: data.user.id, extras: [this.guild] }); + } + + /** + * Data that resolves to give a GuildMember object. This can be: + * * A GuildMember object + * * A User resolvable + * @typedef {GuildMember|UserResolvable} GuildMemberResolvable + */ + + /** + * Resolves a {@link GuildMemberResolvable} to a {@link GuildMember} object. + * @param {GuildMemberResolvable} member The user that is part of the guild + * @returns {?GuildMember} + */ + resolve(member) { + const memberResolvable = super.resolve(member); + if (memberResolvable) return memberResolvable; + const userResolvable = this.client.users.resolveId(member); + if (userResolvable) return super.resolve(userResolvable); + return null; + } + + /** + * Resolves a {@link GuildMemberResolvable} to a member id. + * @param {GuildMemberResolvable} member The user that is part of the guild + * @returns {?Snowflake} + */ + resolveId(member) { + const memberResolvable = super.resolveId(member); + if (memberResolvable) return memberResolvable; + const userResolvable = this.client.users.resolveId(member); + return this.cache.has(userResolvable) ? userResolvable : null; + } + + /** + * Options used to add a user to a guild using OAuth2. + * @typedef {Object} AddGuildMemberOptions + * @property {string} accessToken An OAuth2 access token for the user with the {@link OAuth2Scopes.GuildsJoin} + * scope granted to the bot's application + * @property {string} [nick] The nickname to give to the member + * <info>This property requires the {@link PermissionFlagsBits.ManageNicknames} permission.</info> + * @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] The roles to add to the member + * <info>This property requires the {@link PermissionFlagsBits.ManageRoles} permission.</info> + * @property {boolean} [mute] Whether the member should be muted + * <info>This property requires the {@link PermissionFlagsBits.MuteMembers} permission.</info> + * @property {boolean} [deaf] Whether the member should be deafened + * <info>This property requires the {@link PermissionFlagsBits.MuteMembers} permission.</info> + * @property {boolean} [force] Whether to skip the cache check and request the API directly + * @property {boolean} [fetchWhenExisting=true] Whether to fetch the user if not cached and already a member + */ + + /** + * Adds a user to the guild using OAuth2. + * <info>This method requires the {@link PermissionFlagsBits.CreateInstantInvite} permission. + * @param {UserResolvable} user The user to add to the guild + * @param {AddGuildMemberOptions} options Options for adding the user to the guild + * @returns {Promise<GuildMember|null>} + */ + async add(user, options) { + const userId = this.client.users.resolveId(user); + if (!userId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable'); + if (!options.force) { + const cachedUser = this.cache.get(userId); + if (cachedUser) return cachedUser; + } + const resolvedOptions = { + access_token: options.accessToken, + nick: options.nick, + mute: options.mute, + deaf: options.deaf, + }; + if (options.roles) { + if (!Array.isArray(options.roles) && !(options.roles instanceof Collection)) { + throw new DiscordjsTypeError( + ErrorCodes.InvalidType, + 'options.roles', + 'Array or Collection of Roles or Snowflakes', + true, + ); + } + const resolvedRoles = []; + for (const role of options.roles.values()) { + const resolvedRole = this.guild.roles.resolveId(role); + if (!resolvedRole) { + throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'options.roles', role); + } + resolvedRoles.push(resolvedRole); + } + resolvedOptions.roles = resolvedRoles; + } + const data = await this.client.rest.put(Routes.guildMember(this.guild.id, userId), { body: resolvedOptions }); + // Data is an empty Uint8Array if the member is already part of the guild. + return data instanceof Uint8Array + ? options.fetchWhenExisting === false + ? null + : this.fetch(userId) + : this._add(data); + } + + /** + * The client user as a GuildMember of this guild + * @type {?GuildMember} + * @readonly + */ + get me() { + return ( + this.resolve(this.client.user.id) ?? + (this.client.options.partials.includes(Partials.GuildMember) + ? this._add({ user: { id: this.client.user.id } }, true) + : null) + ); + } + + /** + * Options used to fetch a single member from a guild. + * @typedef {BaseFetchOptions} FetchMemberOptions + * @property {UserResolvable} user The user to fetch + */ + + /** + * Options used to fetch multiple members from a guild. + * @typedef {Object} FetchMembersOptions + * @property {UserResolvable|UserResolvable[]} [user] The user(s) to fetch + * @property {?string} [query] Limit fetch to members with similar usernames + * @property {number} [limit=0] Maximum number of members to request + * @property {boolean} [withPresences=false] Whether to include the presences + * @property {number} [time=120e3] Timeout for receipt of members + * @property {?string} [nonce] Nonce for this request (32 characters max - default to base 16 now timestamp) + */ + + /** + * Fetches member(s) from a guild. + * @param {UserResolvable|FetchMemberOptions|FetchMembersOptions} [options] Options for fetching member(s). + * Omitting the parameter or providing `undefined` will fetch all members. + * @returns {Promise<GuildMember|Collection<Snowflake, GuildMember>>} + * @example + * // Fetch all members from a guild + * guild.members.fetch() + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a single member + * guild.members.fetch('66564597481480192') + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch a single member without checking cache + * guild.members.fetch({ user, force: true }) + * .then(console.log) + * .catch(console.error) + * @example + * // Fetch a single member without caching + * guild.members.fetch({ user, cache: false }) + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch by an array of users including their presences + * guild.members.fetch({ user: ['66564597481480192', '191615925336670208'], withPresences: true }) + * .then(console.log) + * .catch(console.error); + * @example + * // Fetch by query + * guild.members.fetch({ query: 'hydra', limit: 1 }) + * .then(console.log) + * .catch(console.error); + */ + fetch(options) { + if (!options) return this._fetchMany(); + const { user: users, limit, withPresences, cache, force } = options; + const resolvedUser = this.client.users.resolveId(users ?? options); + if (resolvedUser && !limit && !withPresences) return this._fetchSingle({ user: resolvedUser, cache, force }); + const resolvedUsers = users?.map?.(user => this.client.users.resolveId(user)) ?? resolvedUser ?? undefined; + return this._fetchMany({ ...options, users: resolvedUsers }); + } + + async _fetchSingle({ user, cache, force = false }) { + if (!force) { + const existing = this.cache.get(user); + if (existing && !existing.partial) return existing; + } + + const data = await this.client.rest.get(Routes.guildMember(this.guild.id, user)); + return this._add(data, cache); + } + + _fetchMany({ + limit = 0, + withPresences: presences, + users, + query, + time = 120e3, + nonce = DiscordSnowflake.generate().toString(), + } = {}) { + if (nonce.length > 32) return Promise.reject(new DiscordjsRangeError(ErrorCodes.MemberFetchNonceLength)); + + return new Promise((resolve, reject) => { + if (!query && !users) query = ''; + this.guild.shard.send({ + op: GatewayOpcodes.RequestGuildMembers, + d: { + guild_id: this.guild.id, + presences, + user_ids: users, + query, + nonce, + limit, + }, + }); + const fetchedMembers = new Collection(); + let i = 0; + const handler = (members, _, chunk) => { + if (chunk.nonce !== nonce) return; + timeout.refresh(); + i++; + for (const member of members.values()) { + fetchedMembers.set(member.id, member); + } + if (members.size < 1_000 || (limit && fetchedMembers.size >= limit) || i === chunk.count) { + clearTimeout(timeout); + this.client.removeListener(Events.GuildMembersChunk, handler); + this.client.decrementMaxListeners(); + resolve(users && !Array.isArray(users) && fetchedMembers.size ? fetchedMembers.first() : fetchedMembers); + } + }; + const timeout = setTimeout(() => { + this.client.removeListener(Events.GuildMembersChunk, handler); + this.client.decrementMaxListeners(); + reject(new DiscordjsError(ErrorCodes.GuildMembersTimeout)); + }, time).unref(); + this.client.incrementMaxListeners(); + this.client.on(Events.GuildMembersChunk, handler); + }); + } + + /** + * Fetches the client user as a GuildMember of the guild. + * @param {BaseFetchOptions} [options] The options for fetching the member + * @returns {Promise<GuildMember>} + */ + fetchMe(options) { + return this.fetch({ ...options, user: this.client.user.id }); + } + + /** + * Options used for searching guild members. + * @typedef {Object} GuildSearchMembersOptions + * @property {string} query Filter members whose username or nickname start with this query + * @property {number} [limit] Maximum number of members to search + * @property {boolean} [cache=true] Whether or not to cache the fetched member(s) + */ + + /** + * Searches for members in the guild based on a query. + * @param {GuildSearchMembersOptions} options Options for searching members + * @returns {Promise<Collection<Snowflake, GuildMember>>} + */ + async search({ query, limit, cache = true } = {}) { + const data = await this.client.rest.get(Routes.guildMembersSearch(this.guild.id), { + query: makeURLSearchParams({ query, limit }), + }); + return data.reduce((col, member) => col.set(member.user.id, this._add(member, cache)), new Collection()); + } + + /** + * Options used for listing guild members. + * @typedef {Object} GuildListMembersOptions + * @property {Snowflake} [after] Limit fetching members to those with an id greater than the supplied id + * @property {number} [limit] Maximum number of members to list + * @property {boolean} [cache=true] Whether or not to cache the fetched member(s) + */ + + /** + * Lists up to 1000 members of the guild. + * @param {GuildListMembersOptions} [options] Options for listing members + * @returns {Promise<Collection<Snowflake, GuildMember>>} + */ + async list({ after, limit, cache = true } = {}) { + const query = makeURLSearchParams({ limit, after }); + const data = await this.client.rest.get(Routes.guildMembers(this.guild.id), { query }); + return data.reduce((col, member) => col.set(member.user.id, this._add(member, cache)), new Collection()); + } + + /** + * The data for editing a guild member. + * @typedef {Object} GuildMemberEditOptions + * @property {?string} [nick] The nickname to set for the member + * @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] The roles or role ids to apply + * @property {boolean} [mute] Whether or not the member should be muted + * @property {boolean} [deaf] Whether or not the member should be deafened + * @property {GuildVoiceChannelResolvable|null} [channel] Channel to move the member to + * (if they are connected to voice), or `null` if you want to disconnect them from voice + * @property {DateResolvable|null} [communicationDisabledUntil] The date or timestamp + * for the member's communication to be disabled until. Provide `null` to enable communication again. + * @property {GuildMemberFlagsResolvable} [flags] The flags to set for the member + * @property {string} [reason] Reason for editing this user + */ + + /** + * Edits a member of the guild. + * <info>The user must be a member of the guild</info> + * @param {UserResolvable} user The member to edit + * @param {GuildMemberEditOptions} options The options to provide + * @returns {Promise<GuildMember>} + */ + async edit(user, { reason, ...options }) { + const id = this.client.users.resolveId(user); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable'); + + if (options.channel) { + options.channel = this.guild.channels.resolve(options.channel); + if (!(options.channel instanceof BaseGuildVoiceChannel)) { + throw new DiscordjsError(ErrorCodes.GuildVoiceChannelResolve); + } + options.channel_id = options.channel.id; + options.channel = undefined; + } else if (options.channel === null) { + options.channel_id = null; + options.channel = undefined; + } + options.roles &&= options.roles.map(role => (role instanceof Role ? role.id : role)); + + if (options.communicationDisabledUntil !== undefined) { + options.communication_disabled_until = + // eslint-disable-next-line eqeqeq + options.communicationDisabledUntil != null + ? new Date(options.communicationDisabledUntil).toISOString() + : options.communicationDisabledUntil; + } + + if (options.flags !== undefined) { + options.flags = GuildMemberFlagsBitField.resolve(options.flags); + } + + let endpoint; + if (id === this.client.user.id) { + const keys = Object.keys(options); + if (keys.length === 1 && keys[0] === 'nick') endpoint = Routes.guildMember(this.guild.id); + else endpoint = Routes.guildMember(this.guild.id, id); + } else { + endpoint = Routes.guildMember(this.guild.id, id); + } + const d = await this.client.rest.patch(endpoint, { body: options, reason }); + + const clone = this.cache.get(id)?._clone(); + clone?._patch(d); + return clone ?? this._add(d, false); + } + + /** + * Options used for pruning guild members. + * <info>It's recommended to set {@link GuildPruneMembersOptions#count options.count} + * to `false` for large guilds.</info> + * @typedef {Object} GuildPruneMembersOptions + * @property {number} [days] Number of days of inactivity required to kick + * @property {boolean} [dry=false] Get the number of users that will be kicked, without actually kicking them + * @property {boolean} [count] Whether or not to return the number of users that have been kicked. + * @property {RoleResolvable[]} [roles] Array of roles to bypass the "...and no roles" constraint when pruning + * @property {string} [reason] Reason for this prune + */ + + /** + * Prunes members from the guild based on how long they have been inactive. + * @param {GuildPruneMembersOptions} [options] Options for pruning + * @returns {Promise<number|null>} The number of members that were/will be kicked + * @example + * // See how many members will be pruned + * guild.members.prune({ dry: true }) + * .then(pruned => console.log(`This will prune ${pruned} people!`)) + * .catch(console.error); + * @example + * // Actually prune the members + * guild.members.prune({ days: 1, reason: 'too many people!' }) + * .then(pruned => console.log(`I just pruned ${pruned} people!`)) + * .catch(console.error); + * @example + * // Include members with a specified role + * guild.members.prune({ days: 7, roles: ['657259391652855808'] }) + * .then(pruned => console.log(`I just pruned ${pruned} people!`)) + * .catch(console.error); + */ + async prune({ days, dry = false, count: compute_prune_count, roles = [], reason } = {}) { + if (typeof days !== 'number') throw new DiscordjsTypeError(ErrorCodes.PruneDaysType); + + const query = { days }; + const resolvedRoles = []; + + for (const role of roles) { + const resolvedRole = this.guild.roles.resolveId(role); + if (!resolvedRole) { + throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array', 'options.roles', role); + } + resolvedRoles.push(resolvedRole); + } + + if (resolvedRoles.length) { + query.include_roles = dry ? resolvedRoles.join(',') : resolvedRoles; + } + + const endpoint = Routes.guildPrune(this.guild.id); + + const { pruned } = await (dry + ? this.client.rest.get(endpoint, { query: makeURLSearchParams(query), reason }) + : this.client.rest.post(endpoint, { body: { ...query, compute_prune_count }, reason })); + + return pruned; + } + + /** + * Kicks a user from the guild. + * <info>The user must be a member of the guild</info> + * @param {UserResolvable} user The member to kick + * @param {string} [reason] Reason for kicking + * @returns {Promise<GuildMember|User|Snowflake>} Result object will be resolved as specifically as possible. + * If the GuildMember cannot be resolved, the User will instead be attempted to be resolved. If that also cannot + * be resolved, the user's id will be the result. + * @example + * // Kick a user by id (or with a user/guild member object) + * guild.members.kick('84484653687267328') + * .then(kickInfo => console.log(`Kicked ${kickInfo.user?.tag ?? kickInfo.tag ?? kickInfo}`)) + * .catch(console.error); + */ + async kick(user, reason) { + const id = this.client.users.resolveId(user); + if (!id) return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable')); + + await this.client.rest.delete(Routes.guildMember(this.guild.id, id), { reason }); + + return this.resolve(user) ?? this.client.users.resolve(user) ?? id; + } + + /** + * Bans a user from the guild. + * @param {UserResolvable} user The user to ban + * @param {BanOptions} [options] Options for the ban + * @returns {Promise<GuildMember|User|Snowflake>} Result object will be resolved as specifically as possible. + * If the GuildMember cannot be resolved, the User will instead be attempted to be resolved. If that also cannot + * be resolved, the user id will be the result. + * Internally calls the GuildBanManager#create method. + * @example + * // Ban a user by id (or with a user/guild member object) + * guild.members.ban('84484653687267328') + * .then(banInfo => console.log(`Banned ${banInfo.user?.tag ?? banInfo.tag ?? banInfo}`)) + * .catch(console.error); + */ + ban(user, options) { + return this.guild.bans.create(user, options); + } + + /** + * Unbans a user from the guild. Internally calls the {@link GuildBanManager#remove} method. + * @param {UserResolvable} user The user to unban + * @param {string} [reason] Reason for unbanning user + * @returns {Promise<?User>} The user that was unbanned + * @example + * // Unban a user by id (or with a user/guild member object) + * guild.members.unban('84484653687267328') + * .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`)) + * .catch(console.error); + */ + unban(user, reason) { + return this.guild.bans.remove(user, reason); + } + + /** + * Options used for adding or removing a role from a member. + * @typedef {Object} AddOrRemoveGuildMemberRoleOptions + * @property {GuildMemberResolvable} user The user to add/remove the role from + * @property {RoleResolvable} role The role to add/remove + * @property {string} [reason] Reason for adding/removing the role + */ + + /** + * Adds a role to a member. + * @param {AddOrRemoveGuildMemberRoleOptions} options Options for adding the role + * @returns {Promise<GuildMember|User|Snowflake>} + */ + async addRole(options) { + const { user, role, reason } = options; + const userId = this.guild.members.resolveId(user); + const roleId = this.guild.roles.resolveId(role); + await this.client.rest.put(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason }); + + return this.resolve(user) ?? this.client.users.resolve(user) ?? userId; + } + + /** + * Removes a role from a member. + * @param {AddOrRemoveGuildMemberRoleOptions} options Options for removing the role + * @returns {Promise<GuildMember|User|Snowflake>} + */ + async removeRole(options) { + const { user, role, reason } = options; + const userId = this.guild.members.resolveId(user); + const roleId = this.guild.roles.resolveId(role); + await this.client.rest.delete(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason }); + + return this.resolve(user) ?? this.client.users.resolve(user) ?? userId; + } +} + +module.exports = GuildMemberManager; diff --git a/node_modules/discord.js/src/managers/GuildMemberRoleManager.js b/node_modules/discord.js/src/managers/GuildMemberRoleManager.js new file mode 100644 index 0000000..e530268 --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildMemberRoleManager.js @@ -0,0 +1,204 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { Routes } = require('discord-api-types/v10'); +const DataManager = require('./DataManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const { Role } = require('../structures/Role'); + +/** + * Manages API methods for roles of a GuildMember and stores their cache. + * @extends {DataManager} + */ +class GuildMemberRoleManager extends DataManager { + constructor(member) { + super(member.client, Role); + + /** + * The GuildMember this manager belongs to + * @type {GuildMember} + */ + this.member = member; + + /** + * The Guild this manager belongs to + * @type {Guild} + */ + this.guild = member.guild; + } + + /** + * The roles of this member + * @type {Collection<Snowflake, Role>} + * @readonly + */ + get cache() { + const everyone = this.guild.roles.everyone; + return this.guild.roles.cache.filter(role => this.member._roles.includes(role.id)).set(everyone.id, everyone); + } + + /** + * The role of the member used to hoist them in a separate category in the users list + * @type {?Role} + * @readonly + */ + get hoist() { + const hoistedRoles = this.cache.filter(role => role.hoist); + if (!hoistedRoles.size) return null; + return hoistedRoles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev)); + } + + /** + * The role of the member used to set their role icon + * @type {?Role} + * @readonly + */ + get icon() { + const iconRoles = this.cache.filter(role => role.icon || role.unicodeEmoji); + if (!iconRoles.size) return null; + return iconRoles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev)); + } + + /** + * The role of the member used to set their color + * @type {?Role} + * @readonly + */ + get color() { + const coloredRoles = this.cache.filter(role => role.color); + if (!coloredRoles.size) return null; + return coloredRoles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev)); + } + + /** + * The role of the member with the highest position + * @type {Role} + * @readonly + */ + get highest() { + return this.cache.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev), this.cache.first()); + } + + /** + * The premium subscriber role of the guild, if present on the member + * @type {?Role} + * @readonly + */ + get premiumSubscriberRole() { + return this.cache.find(role => role.tags?.premiumSubscriberRole) ?? null; + } + + /** + * The managed role this member created when joining the guild, if any + * <info>Only ever available on bots</info> + * @type {?Role} + * @readonly + */ + get botRole() { + if (!this.member.user.bot) return null; + return this.cache.find(role => role.tags?.botId === this.member.user.id) ?? null; + } + + /** + * Adds a role (or multiple roles) to the member. + * @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to add + * @param {string} [reason] Reason for adding the role(s) + * @returns {Promise<GuildMember>} + */ + async add(roleOrRoles, reason) { + if (roleOrRoles instanceof Collection || Array.isArray(roleOrRoles)) { + const resolvedRoles = []; + for (const role of roleOrRoles.values()) { + const resolvedRole = this.guild.roles.resolveId(role); + if (!resolvedRole) { + throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role); + } + resolvedRoles.push(resolvedRole); + } + + const newRoles = [...new Set(resolvedRoles.concat(...this.cache.keys()))]; + return this.set(newRoles, reason); + } else { + roleOrRoles = this.guild.roles.resolveId(roleOrRoles); + if (roleOrRoles === null) { + throw new DiscordjsTypeError( + ErrorCodes.InvalidType, + 'roles', + 'Role, Snowflake or Array or Collection of Roles or Snowflakes', + ); + } + + await this.client.rest.put(Routes.guildMemberRole(this.guild.id, this.member.id, roleOrRoles), { reason }); + + const clone = this.member._clone(); + clone._roles = [...this.cache.keys(), roleOrRoles]; + return clone; + } + } + + /** + * Removes a role (or multiple roles) from the member. + * @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to remove + * @param {string} [reason] Reason for removing the role(s) + * @returns {Promise<GuildMember>} + */ + async remove(roleOrRoles, reason) { + if (roleOrRoles instanceof Collection || Array.isArray(roleOrRoles)) { + const resolvedRoles = []; + for (const role of roleOrRoles.values()) { + const resolvedRole = this.guild.roles.resolveId(role); + if (!resolvedRole) { + throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role); + } + resolvedRoles.push(resolvedRole); + } + + const newRoles = this.cache.filter(role => !resolvedRoles.includes(role.id)); + return this.set(newRoles, reason); + } else { + roleOrRoles = this.guild.roles.resolveId(roleOrRoles); + if (roleOrRoles === null) { + throw new DiscordjsTypeError( + ErrorCodes.InvalidType, + 'roles', + 'Role, Snowflake or Array or Collection of Roles or Snowflakes', + ); + } + + await this.client.rest.delete(Routes.guildMemberRole(this.guild.id, this.member.id, roleOrRoles), { reason }); + + const clone = this.member._clone(); + const newRoles = this.cache.filter(role => role.id !== roleOrRoles); + clone._roles = [...newRoles.keys()]; + return clone; + } + } + + /** + * Sets the roles applied to the member. + * @param {Collection<Snowflake, Role>|RoleResolvable[]} roles The roles or role ids to apply + * @param {string} [reason] Reason for applying the roles + * @returns {Promise<GuildMember>} + * @example + * // Set the member's roles to a single role + * guildMember.roles.set(['391156570408615936']) + * .then(console.log) + * .catch(console.error); + * @example + * // Remove all the roles from a member + * guildMember.roles.set([]) + * .then(member => console.log(`Member roles is now of ${member.roles.cache.size} size`)) + * .catch(console.error); + */ + set(roles, reason) { + return this.member.edit({ roles, reason }); + } + + clone() { + const clone = new this.constructor(this.member); + clone.member._roles = [...this.cache.keys()]; + return clone; + } +} + +module.exports = GuildMemberRoleManager; diff --git a/node_modules/discord.js/src/managers/GuildMessageManager.js b/node_modules/discord.js/src/managers/GuildMessageManager.js new file mode 100644 index 0000000..7a93c99 --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildMessageManager.js @@ -0,0 +1,17 @@ +'use strict'; + +const MessageManager = require('./MessageManager'); + +/** + * Manages API methods for messages in a guild and holds their cache. + * @extends {MessageManager} + */ +class GuildMessageManager extends MessageManager { + /** + * The channel that the messages belong to + * @name GuildMessageManager#channel + * @type {GuildTextBasedChannel} + */ +} + +module.exports = GuildMessageManager; diff --git a/node_modules/discord.js/src/managers/GuildScheduledEventManager.js b/node_modules/discord.js/src/managers/GuildScheduledEventManager.js new file mode 100644 index 0000000..9071b60 --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildScheduledEventManager.js @@ -0,0 +1,297 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { GuildScheduledEventEntityType, Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../errors'); +const { GuildScheduledEvent } = require('../structures/GuildScheduledEvent'); +const DataResolver = require('../util/DataResolver'); + +/** + * Manages API methods for GuildScheduledEvents and stores their cache. + * @extends {CachedManager} + */ +class GuildScheduledEventManager extends CachedManager { + constructor(guild, iterable) { + super(guild.client, GuildScheduledEvent, iterable); + + /** + * The guild this manager belongs to + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The cache of this manager + * @type {Collection<Snowflake, GuildScheduledEvent>} + * @name GuildScheduledEventManager#cache + */ + + /** + * Data that resolves to give a GuildScheduledEvent object. This can be: + * * A Snowflake + * * A GuildScheduledEvent object + * @typedef {Snowflake|GuildScheduledEvent} GuildScheduledEventResolvable + */ + + /** + * Options used to create a guild scheduled event. + * @typedef {Object} GuildScheduledEventCreateOptions + * @property {string} name The name of the guild scheduled event + * @property {DateResolvable} scheduledStartTime The time to schedule the event at + * @property {DateResolvable} [scheduledEndTime] The time to end the event at + * <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.External}</warn> + * @property {GuildScheduledEventPrivacyLevel} privacyLevel The privacy level of the guild scheduled event + * @property {GuildScheduledEventEntityType} entityType The scheduled entity type of the event + * @property {string} [description] The description of the guild scheduled event + * @property {GuildVoiceChannelResolvable} [channel] The channel of the guild scheduled event + * <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.StageInstance} or + * {@link GuildScheduledEventEntityType.Voice}</warn> + * @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the + * guild scheduled event + * <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.External}</warn> + * @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event + * @property {string} [reason] The reason for creating the guild scheduled event + */ + + /** + * Options used to set entity metadata of a guild scheduled event. + * @typedef {Object} GuildScheduledEventEntityMetadataOptions + * @property {string} [location] The location of the guild scheduled event + * <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.External}</warn> + */ + + /** + * Creates a new guild scheduled event. + * @param {GuildScheduledEventCreateOptions} options Options for creating the guild scheduled event + * @returns {Promise<GuildScheduledEvent>} + */ + async create(options) { + if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true); + let { + privacyLevel, + entityType, + channel, + name, + scheduledStartTime, + description, + scheduledEndTime, + entityMetadata, + reason, + image, + } = options; + + let entity_metadata, channel_id; + if (entityType === GuildScheduledEventEntityType.External) { + channel_id = channel === undefined ? channel : null; + entity_metadata = { location: entityMetadata?.location }; + } else { + channel_id = this.guild.channels.resolveId(channel); + if (!channel_id) throw new DiscordjsError(ErrorCodes.GuildVoiceChannelResolve); + entity_metadata = entityMetadata === undefined ? entityMetadata : null; + } + + const data = await this.client.rest.post(Routes.guildScheduledEvents(this.guild.id), { + body: { + channel_id, + name, + privacy_level: privacyLevel, + scheduled_start_time: new Date(scheduledStartTime).toISOString(), + scheduled_end_time: scheduledEndTime ? new Date(scheduledEndTime).toISOString() : scheduledEndTime, + description, + entity_type: entityType, + entity_metadata, + image: image && (await DataResolver.resolveImage(image)), + }, + reason, + }); + + return this._add(data); + } + + /** + * Options used to fetch a single guild scheduled event from a guild. + * @typedef {BaseFetchOptions} FetchGuildScheduledEventOptions + * @property {GuildScheduledEventResolvable} guildScheduledEvent The guild scheduled event to fetch + * @property {boolean} [withUserCount=true] Whether to fetch the number of users subscribed to the scheduled event + */ + + /** + * Options used to fetch multiple guild scheduled events from a guild. + * @typedef {Object} FetchGuildScheduledEventsOptions + * @property {boolean} [cache] Whether or not to cache the fetched guild scheduled events + * @property {boolean} [withUserCount=true] Whether to fetch the number of users subscribed to each scheduled event + * should be returned + */ + + /** + * Obtains one or more guild scheduled events from Discord, or the guild cache if it's already available. + * @param {GuildScheduledEventResolvable|FetchGuildScheduledEventOptions|FetchGuildScheduledEventsOptions} [options] + * The id of the guild scheduled event or options + * @returns {Promise<GuildScheduledEvent|Collection<Snowflake, GuildScheduledEvent>>} + */ + async fetch(options = {}) { + const id = this.resolveId(options.guildScheduledEvent ?? options); + + if (id) { + if (!options.force) { + const existing = this.cache.get(id); + if (existing) return existing; + } + + const data = await this.client.rest.get(Routes.guildScheduledEvent(this.guild.id, id), { + query: makeURLSearchParams({ with_user_count: options.withUserCount ?? true }), + }); + return this._add(data, options.cache); + } + + const data = await this.client.rest.get(Routes.guildScheduledEvents(this.guild.id), { + query: makeURLSearchParams({ with_user_count: options.withUserCount ?? true }), + }); + + return data.reduce( + (coll, rawGuildScheduledEventData) => + coll.set( + rawGuildScheduledEventData.id, + this.guild.scheduledEvents._add(rawGuildScheduledEventData, options.cache), + ), + new Collection(), + ); + } + + /** + * Options used to edit a guild scheduled event. + * @typedef {Object} GuildScheduledEventEditOptions + * @property {string} [name] The name of the guild scheduled event + * @property {DateResolvable} [scheduledStartTime] The time to schedule the event at + * @property {DateResolvable} [scheduledEndTime] The time to end the event at + * @property {GuildScheduledEventPrivacyLevel} [privacyLevel] The privacy level of the guild scheduled event + * @property {GuildScheduledEventEntityType} [entityType] The scheduled entity type of the event + * @property {string} [description] The description of the guild scheduled event + * @property {?GuildVoiceChannelResolvable} [channel] The channel of the guild scheduled event + * @property {GuildScheduledEventStatus} [status] The status of the guild scheduled event + * @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the + * guild scheduled event + * <warn>This can be modified only if `entityType` of the `GuildScheduledEvent` to be edited is + * {@link GuildScheduledEventEntityType.External}</warn> + * @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event + * @property {string} [reason] The reason for editing the guild scheduled event + */ + + /** + * Edits a guild scheduled event. + * @param {GuildScheduledEventResolvable} guildScheduledEvent The guild scheduled event to edit + * @param {GuildScheduledEventEditOptions} options Options to edit the guild scheduled event + * @returns {Promise<GuildScheduledEvent>} + */ + async edit(guildScheduledEvent, options) { + const guildScheduledEventId = this.resolveId(guildScheduledEvent); + if (!guildScheduledEventId) throw new DiscordjsError(ErrorCodes.GuildScheduledEventResolve); + + if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true); + let { + privacyLevel, + entityType, + channel, + status, + name, + scheduledStartTime, + description, + scheduledEndTime, + entityMetadata, + reason, + image, + } = options; + + let entity_metadata; + if (entityMetadata) { + entity_metadata = { + location: entityMetadata.location, + }; + } + + const data = await this.client.rest.patch(Routes.guildScheduledEvent(this.guild.id, guildScheduledEventId), { + body: { + channel_id: channel === undefined ? channel : this.guild.channels.resolveId(channel), + name, + privacy_level: privacyLevel, + scheduled_start_time: scheduledStartTime ? new Date(scheduledStartTime).toISOString() : undefined, + scheduled_end_time: scheduledEndTime ? new Date(scheduledEndTime).toISOString() : scheduledEndTime, + description, + entity_type: entityType, + status, + image: image && (await DataResolver.resolveImage(image)), + entity_metadata, + }, + reason, + }); + + return this._add(data); + } + + /** + * Deletes a guild scheduled event. + * @param {GuildScheduledEventResolvable} guildScheduledEvent The guild scheduled event to delete + * @returns {Promise<void>} + */ + async delete(guildScheduledEvent) { + const guildScheduledEventId = this.resolveId(guildScheduledEvent); + if (!guildScheduledEventId) throw new DiscordjsError(ErrorCodes.GuildScheduledEventResolve); + + await this.client.rest.delete(Routes.guildScheduledEvent(this.guild.id, guildScheduledEventId)); + } + + /** + * Options used to fetch subscribers of a guild scheduled event + * @typedef {Object} FetchGuildScheduledEventSubscribersOptions + * @property {number} [limit] The maximum numbers of users to fetch + * @property {boolean} [withMember] Whether to fetch guild member data of the users + * @property {Snowflake} [before] Consider only users before this user id + * @property {Snowflake} [after] Consider only users after this user id + * <warn>If both `before` and `after` are provided, only `before` is respected</warn> + */ + + /** + * Represents a subscriber of a {@link GuildScheduledEvent} + * @typedef {Object} GuildScheduledEventUser + * @property {Snowflake} guildScheduledEventId The id of the guild scheduled event which the user subscribed to + * @property {User} user The user that subscribed to the guild scheduled event + * @property {?GuildMember} member The guild member associated with the user, if any + */ + + /** + * Fetches subscribers of a guild scheduled event. + * @param {GuildScheduledEventResolvable} guildScheduledEvent The guild scheduled event to fetch subscribers of + * @param {FetchGuildScheduledEventSubscribersOptions} [options={}] Options for fetching the subscribers + * @returns {Promise<Collection<Snowflake, GuildScheduledEventUser>>} + */ + async fetchSubscribers(guildScheduledEvent, options = {}) { + const guildScheduledEventId = this.resolveId(guildScheduledEvent); + if (!guildScheduledEventId) throw new DiscordjsError(ErrorCodes.GuildScheduledEventResolve); + + const query = makeURLSearchParams({ + limit: options.limit, + with_member: options.withMember, + before: options.before, + after: options.after, + }); + + const data = await this.client.rest.get(Routes.guildScheduledEventUsers(this.guild.id, guildScheduledEventId), { + query, + }); + + return data.reduce( + (coll, rawData) => + coll.set(rawData.user.id, { + guildScheduledEventId: rawData.guild_scheduled_event_id, + user: this.client.users._add(rawData.user), + member: rawData.member ? this.guild.members._add({ ...rawData.member, user: rawData.user }) : null, + }), + new Collection(), + ); + } +} + +module.exports = GuildScheduledEventManager; diff --git a/node_modules/discord.js/src/managers/GuildStickerManager.js b/node_modules/discord.js/src/managers/GuildStickerManager.js new file mode 100644 index 0000000..a4974ec --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildStickerManager.js @@ -0,0 +1,182 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const MessagePayload = require('../structures/MessagePayload'); +const { Sticker } = require('../structures/Sticker'); + +/** + * Manages API methods for Guild Stickers and stores their cache. + * @extends {CachedManager} + */ +class GuildStickerManager extends CachedManager { + constructor(guild, iterable) { + super(guild.client, Sticker, iterable); + + /** + * The guild this manager belongs to + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The cache of Guild Stickers + * @type {Collection<Snowflake, Sticker>} + * @name GuildStickerManager#cache + */ + + _add(data, cache) { + return super._add(data, cache, { extras: [this.guild] }); + } + + /** + * Options used to create a guild sticker. + * @typedef {Object} GuildStickerCreateOptions + * @property {AttachmentPayload|BufferResolvable|Stream} file The file for the sticker + * @property {string} name The name for the sticker + * @property {string} tags The Discord name of a unicode emoji representing the sticker's expression + * @property {?string} [description] The description for the sticker + * @property {string} [reason] Reason for creating the sticker + */ + + /** + * Creates a new custom sticker in the guild. + * @param {GuildStickerCreateOptions} options Options for creating a guild sticker + * @returns {Promise<Sticker>} The created sticker + * @example + * // Create a new sticker from a URL + * guild.stickers.create({ file: 'https://i.imgur.com/w3duR07.png', name: 'rip', tags: 'headstone' }) + * .then(sticker => console.log(`Created new sticker with name ${sticker.name}!`)) + * .catch(console.error); + * @example + * // Create a new sticker from a file on your computer + * guild.stickers.create({ file: './memes/banana.png', name: 'banana', tags: 'banana' }) + * .then(sticker => console.log(`Created new sticker with name ${sticker.name}!`)) + * .catch(console.error); + */ + async create({ file, name, tags, description, reason } = {}) { + const resolvedFile = await MessagePayload.resolveFile(file); + if (!resolvedFile) throw new DiscordjsTypeError(ErrorCodes.ReqResourceType); + file = { ...resolvedFile, key: 'file' }; + + const body = { name, tags, description: description ?? '' }; + + const sticker = await this.client.rest.post(Routes.guildStickers(this.guild.id), { + appendToFormData: true, + body, + files: [file], + reason, + }); + return this.client.actions.GuildStickerCreate.handle(this.guild, sticker).sticker; + } + + /** + * Data that resolves to give a Sticker object. This can be: + * * A Sticker object + * * A Snowflake + * @typedef {Sticker|Snowflake} StickerResolvable + */ + + /** + * Resolves a StickerResolvable to a Sticker object. + * @method resolve + * @memberof GuildStickerManager + * @instance + * @param {StickerResolvable} sticker The Sticker resolvable to identify + * @returns {?Sticker} + */ + + /** + * Resolves a StickerResolvable to a Sticker id string. + * @method resolveId + * @memberof GuildStickerManager + * @instance + * @param {StickerResolvable} sticker The Sticker resolvable to identify + * @returns {?Snowflake} + */ + + /** + * Edits a sticker. + * @param {StickerResolvable} sticker The sticker to edit + * @param {GuildStickerEditOptions} [options={}] The new data for the sticker + * @returns {Promise<Sticker>} + */ + async edit(sticker, options = {}) { + const stickerId = this.resolveId(sticker); + if (!stickerId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'sticker', 'StickerResolvable'); + + const d = await this.client.rest.patch(Routes.guildSticker(this.guild.id, stickerId), { + body: options, + reason: options.reason, + }); + + const existing = this.cache.get(stickerId); + if (existing) { + const clone = existing._clone(); + clone._patch(d); + return clone; + } + return this._add(d); + } + + /** + * Deletes a sticker. + * @param {StickerResolvable} sticker The sticker to delete + * @param {string} [reason] Reason for deleting this sticker + * @returns {Promise<void>} + */ + async delete(sticker, reason) { + sticker = this.resolveId(sticker); + if (!sticker) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'sticker', 'StickerResolvable'); + + await this.client.rest.delete(Routes.guildSticker(this.guild.id, sticker), { reason }); + } + + /** + * Obtains one or more stickers from Discord, or the sticker cache if they're already available. + * @param {Snowflake} [id] The Sticker's id + * @param {BaseFetchOptions} [options] Additional options for this fetch + * @returns {Promise<Sticker|Collection<Snowflake, Sticker>>} + * @example + * // Fetch all stickers from the guild + * message.guild.stickers.fetch() + * .then(stickers => console.log(`There are ${stickers.size} stickers.`)) + * .catch(console.error); + * @example + * // Fetch a single sticker + * message.guild.stickers.fetch('222078108977594368') + * .then(sticker => console.log(`The sticker name is: ${sticker.name}`)) + * .catch(console.error); + */ + async fetch(id, { cache = true, force = false } = {}) { + if (id) { + if (!force) { + const existing = this.cache.get(id); + if (existing) return existing; + } + const sticker = await this.client.rest.get(Routes.guildSticker(this.guild.id, id)); + return this._add(sticker, cache); + } + + const data = await this.client.rest.get(Routes.guildStickers(this.guild.id)); + return new Collection(data.map(sticker => [sticker.id, this._add(sticker, cache)])); + } + + /** + * Fetches the user who uploaded this sticker, if this is a guild sticker. + * @param {StickerResolvable} sticker The sticker to fetch the user for + * @returns {Promise<?User>} + */ + async fetchUser(sticker) { + sticker = this.resolve(sticker); + if (!sticker) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'sticker', 'StickerResolvable'); + const data = await this.client.rest.get(Routes.guildSticker(this.guild.id, sticker.id)); + sticker._patch(data); + return sticker.user; + } +} + +module.exports = GuildStickerManager; diff --git a/node_modules/discord.js/src/managers/GuildTextThreadManager.js b/node_modules/discord.js/src/managers/GuildTextThreadManager.js new file mode 100644 index 0000000..5591845 --- /dev/null +++ b/node_modules/discord.js/src/managers/GuildTextThreadManager.js @@ -0,0 +1,91 @@ +'use strict'; + +const { ChannelType, Routes } = require('discord-api-types/v10'); +const ThreadManager = require('./ThreadManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * Manages API methods for {@link ThreadChannel} objects and stores their cache. + * @extends {ThreadManager} + */ +class GuildTextThreadManager extends ThreadManager { + /** + * The channel this Manager belongs to + * @name GuildTextThreadManager#channel + * @type {TextChannel|NewsChannel} + */ + + /** + * Options for creating a thread. <warn>Only one of `startMessage` or `type` can be defined.</warn> + * @typedef {StartThreadOptions} ThreadCreateOptions + * @property {MessageResolvable} [startMessage] The message to start a thread from. + * <warn>If this is defined, then the `type` of thread gets inferred automatically and cannot be changed.</warn> + * @property {ThreadChannelTypes} [type] The type of thread to create. + * Defaults to {@link ChannelType.PublicThread} if created in a {@link TextChannel} + * <warn>When creating threads in a {@link NewsChannel}, this is ignored and is always + * {@link ChannelType.AnnouncementThread}</warn> + * @property {boolean} [invitable] Whether non-moderators can add other non-moderators to the thread + * <info>Can only be set when type will be {@link ChannelType.PrivateThread}</info> + */ + + /** + * Creates a new thread in the channel. + * @param {ThreadCreateOptions} [options] Options to create a new thread + * @returns {Promise<ThreadChannel>} + * @example + * // Create a new public thread + * channel.threads + * .create({ + * name: 'food-talk', + * autoArchiveDuration: ThreadAutoArchiveDuration.OneHour, + * reason: 'Needed a separate thread for food', + * }) + * .then(threadChannel => console.log(threadChannel)) + * .catch(console.error); + * @example + * // Create a new private thread + * channel.threads + * .create({ + * name: 'mod-talk', + * autoArchiveDuration: ThreadAutoArchiveDuration.OneHour, + * type: ChannelType.PrivateThread, + * reason: 'Needed a separate thread for moderation', + * }) + * .then(threadChannel => console.log(threadChannel)) + * .catch(console.error); + */ + async create({ + name, + autoArchiveDuration = this.channel.defaultAutoArchiveDuration, + startMessage, + type, + invitable, + reason, + rateLimitPerUser, + } = {}) { + let resolvedType = + this.channel.type === ChannelType.GuildAnnouncement ? ChannelType.AnnouncementThread : ChannelType.PublicThread; + let startMessageId; + if (startMessage) { + startMessageId = this.channel.messages.resolveId(startMessage); + if (!startMessageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'startMessage', 'MessageResolvable'); + } else if (this.channel.type !== ChannelType.GuildAnnouncement) { + resolvedType = type ?? resolvedType; + } + + const data = await this.client.rest.post(Routes.threads(this.channel.id, startMessageId), { + body: { + name, + auto_archive_duration: autoArchiveDuration, + type: resolvedType, + invitable: resolvedType === ChannelType.PrivateThread ? invitable : undefined, + rate_limit_per_user: rateLimitPerUser, + }, + reason, + }); + + return this.client.actions.ThreadCreate.handle(data).thread; + } +} + +module.exports = GuildTextThreadManager; diff --git a/node_modules/discord.js/src/managers/MessageManager.js b/node_modules/discord.js/src/managers/MessageManager.js new file mode 100644 index 0000000..6fb95eb --- /dev/null +++ b/node_modules/discord.js/src/managers/MessageManager.js @@ -0,0 +1,263 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const { Message } = require('../structures/Message'); +const MessagePayload = require('../structures/MessagePayload'); +const { MakeCacheOverrideSymbol } = require('../util/Symbols'); +const { resolvePartialEmoji } = require('../util/Util'); + +/** + * Manages API methods for Messages and holds their cache. + * @extends {CachedManager} + * @abstract + */ +class MessageManager extends CachedManager { + static [MakeCacheOverrideSymbol] = MessageManager; + + constructor(channel, iterable) { + super(channel.client, Message, iterable); + + /** + * The channel that the messages belong to + * @type {TextBasedChannels} + */ + this.channel = channel; + } + + /** + * The cache of Messages + * @type {Collection<Snowflake, Message>} + * @name MessageManager#cache + */ + + _add(data, cache) { + return super._add(data, cache); + } + + /** + * Data that can be resolved to a Message object. This can be: + * * A Message + * * A Snowflake + * @typedef {Message|Snowflake} MessageResolvable + */ + + /** + * Options used to fetch a message. + * @typedef {BaseFetchOptions} FetchMessageOptions + * @property {MessageResolvable} message The message to fetch + */ + + /** + * Options used to fetch multiple messages. + * <info>The `before`, `after`, and `around` parameters are mutually exclusive.</info> + * @typedef {Object} FetchMessagesOptions + * @property {number} [limit] The maximum number of messages to return + * @property {Snowflake} [before] Consider only messages before this id + * @property {Snowflake} [after] Consider only messages after this id + * @property {Snowflake} [around] Consider only messages around this id + * @property {boolean} [cache] Whether to cache the fetched messages + */ + + /** + * Fetches message(s) from a channel. + * <info>The returned Collection does not contain reaction users of the messages if they were not cached. + * Those need to be fetched separately in such a case.</info> + * @param {MessageResolvable|FetchMessageOptions|FetchMessagesOptions} [options] Options for fetching message(s) + * @returns {Promise<Message|Collection<Snowflake, Message>>} + * @example + * // Fetch a message + * channel.messages.fetch('99539446449315840') + * .then(message => console.log(message.content)) + * .catch(console.error); + * @example + * // Fetch a maximum of 10 messages without caching + * channel.messages.fetch({ limit: 10, cache: false }) + * .then(messages => console.log(`Received ${messages.size} messages`)) + * .catch(console.error); + * @example + * // Fetch a maximum of 10 messages without caching around a message id + * channel.messages.fetch({ limit: 10, cache: false, around: '99539446449315840' }) + * .then(messages => console.log(`Received ${messages.size} messages`)) + * .catch(console.error); + * @example + * // Fetch messages and filter by a user id + * channel.messages.fetch() + * .then(messages => console.log(`${messages.filter(m => m.author.id === '84484653687267328').size} messages`)) + * .catch(console.error); + */ + fetch(options) { + if (!options) return this._fetchMany(); + const { message, cache, force } = options; + const resolvedMessage = this.resolveId(message ?? options); + if (resolvedMessage) return this._fetchSingle({ message: resolvedMessage, cache, force }); + return this._fetchMany(options); + } + + async _fetchSingle({ message, cache, force = false }) { + if (!force) { + const existing = this.cache.get(message); + if (existing && !existing.partial) return existing; + } + + const data = await this.client.rest.get(Routes.channelMessage(this.channel.id, message)); + return this._add(data, cache); + } + + async _fetchMany(options = {}) { + const data = await this.client.rest.get(Routes.channelMessages(this.channel.id), { + query: makeURLSearchParams(options), + }); + + return data.reduce((_data, message) => _data.set(message.id, this._add(message, options.cache)), new Collection()); + } + + /** + * Fetches the pinned messages of this channel and returns a collection of them. + * <info>The returned Collection does not contain any reaction data of the messages. + * Those need to be fetched separately.</info> + * @param {boolean} [cache=true] Whether to cache the message(s) + * @returns {Promise<Collection<Snowflake, Message>>} + * @example + * // Get pinned messages + * channel.messages.fetchPinned() + * .then(messages => console.log(`Received ${messages.size} messages`)) + * .catch(console.error); + */ + async fetchPinned(cache = true) { + const data = await this.client.rest.get(Routes.channelPins(this.channel.id)); + const messages = new Collection(); + for (const message of data) messages.set(message.id, this._add(message, cache)); + return messages; + } + + /** + * Resolves a {@link MessageResolvable} to a {@link Message} object. + * @method resolve + * @memberof MessageManager + * @instance + * @param {MessageResolvable} message The message resolvable to resolve + * @returns {?Message} + */ + + /** + * Resolves a {@link MessageResolvable} to a {@link Message} id. + * @method resolveId + * @memberof MessageManager + * @instance + * @param {MessageResolvable} message The message resolvable to resolve + * @returns {?Snowflake} + */ + + /** + * Options that can be passed to edit a message. + * @typedef {BaseMessageOptions} MessageEditOptions + * @property {AttachmentPayload[]} [attachments] An array of attachments to keep, + * all attachments will be kept if omitted + * @property {MessageFlags} [flags] Which flags to set for the message + * <info>Only the {@link MessageFlags.SuppressEmbeds} flag can be modified.</info> + */ + + /** + * Edits a message, even if it's not cached. + * @param {MessageResolvable} message The message to edit + * @param {string|MessageEditOptions|MessagePayload} options The options to edit the message + * @returns {Promise<Message>} + */ + async edit(message, options) { + const messageId = this.resolveId(message); + if (!messageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); + + const { body, files } = await (options instanceof MessagePayload + ? options + : MessagePayload.create(message instanceof Message ? message : this, options) + ) + .resolveBody() + .resolveFiles(); + const d = await this.client.rest.patch(Routes.channelMessage(this.channel.id, messageId), { body, files }); + + const existing = this.cache.get(messageId); + if (existing) { + const clone = existing._clone(); + clone._patch(d); + return clone; + } + return this._add(d); + } + + /** + * Publishes a message in an announcement channel to all channels following it, even if it's not cached. + * @param {MessageResolvable} message The message to publish + * @returns {Promise<Message>} + */ + async crosspost(message) { + message = this.resolveId(message); + if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); + + const data = await this.client.rest.post(Routes.channelMessageCrosspost(this.channel.id, message)); + return this.cache.get(data.id) ?? this._add(data); + } + + /** + * Pins a message to the channel's pinned messages, even if it's not cached. + * @param {MessageResolvable} message The message to pin + * @param {string} [reason] Reason for pinning + * @returns {Promise<void>} + */ + async pin(message, reason) { + message = this.resolveId(message); + if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); + + await this.client.rest.put(Routes.channelPin(this.channel.id, message), { reason }); + } + + /** + * Unpins a message from the channel's pinned messages, even if it's not cached. + * @param {MessageResolvable} message The message to unpin + * @param {string} [reason] Reason for unpinning + * @returns {Promise<void>} + */ + async unpin(message, reason) { + message = this.resolveId(message); + if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); + + await this.client.rest.delete(Routes.channelPin(this.channel.id, message), { reason }); + } + + /** + * Adds a reaction to a message, even if it's not cached. + * @param {MessageResolvable} message The message to react to + * @param {EmojiIdentifierResolvable} emoji The emoji to react with + * @returns {Promise<void>} + */ + async react(message, emoji) { + message = this.resolveId(message); + if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); + + emoji = resolvePartialEmoji(emoji); + if (!emoji) throw new DiscordjsTypeError(ErrorCodes.EmojiType, 'emoji', 'EmojiIdentifierResolvable'); + + const emojiId = emoji.id + ? `${emoji.animated ? 'a:' : ''}${emoji.name}:${emoji.id}` + : encodeURIComponent(emoji.name); + + await this.client.rest.put(Routes.channelMessageOwnReaction(this.channel.id, message, emojiId)); + } + + /** + * Deletes a message, even if it's not cached. + * @param {MessageResolvable} message The message to delete + * @returns {Promise<void>} + */ + async delete(message) { + message = this.resolveId(message); + if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); + + await this.client.rest.delete(Routes.channelMessage(this.channel.id, message)); + } +} + +module.exports = MessageManager; diff --git a/node_modules/discord.js/src/managers/PermissionOverwriteManager.js b/node_modules/discord.js/src/managers/PermissionOverwriteManager.js new file mode 100644 index 0000000..011a649 --- /dev/null +++ b/node_modules/discord.js/src/managers/PermissionOverwriteManager.js @@ -0,0 +1,168 @@ +'use strict'; + +const process = require('node:process'); +const { Collection } = require('@discordjs/collection'); +const { OverwriteType, Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const PermissionOverwrites = require('../structures/PermissionOverwrites'); +const { Role } = require('../structures/Role'); + +let cacheWarningEmitted = false; + +/** + * Manages API methods for guild channel permission overwrites and stores their cache. + * @extends {CachedManager} + */ +class PermissionOverwriteManager extends CachedManager { + constructor(channel, iterable) { + super(channel.client, PermissionOverwrites); + if (!cacheWarningEmitted && this._cache.constructor.name !== 'Collection') { + cacheWarningEmitted = true; + process.emitWarning( + `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`, + 'UnsupportedCacheOverwriteWarning', + ); + } + + /** + * The channel of the permission overwrite this manager belongs to + * @type {GuildChannel} + */ + this.channel = channel; + + if (iterable) { + for (const item of iterable) { + this._add(item); + } + } + } + + /** + * The cache of this Manager + * @type {Collection<Snowflake, PermissionOverwrites>} + * @name PermissionOverwriteManager#cache + */ + + _add(data, cache) { + return super._add(data, cache, { extras: [this.channel] }); + } + + /** + * Replaces the permission overwrites in this channel. + * @param {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} overwrites + * Permission overwrites the channel gets updated with + * @param {string} [reason] Reason for updating the channel overwrites + * @returns {Promise<GuildChannel>} + * @example + * message.channel.permissionOverwrites.set([ + * { + * id: message.author.id, + * deny: [PermissionsFlagsBit.ViewChannel], + * }, + * ], 'Needed to change permissions'); + */ + set(overwrites, reason) { + if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) { + return Promise.reject( + new DiscordjsTypeError( + ErrorCodes.InvalidType, + 'overwrites', + 'Array or Collection of Permission Overwrites', + true, + ), + ); + } + return this.channel.edit({ permissionOverwrites: overwrites, reason }); + } + + /** + * Extra information about the overwrite. + * @typedef {Object} GuildChannelOverwriteOptions + * @property {string} [reason] The reason for creating/editing this overwrite + * @property {OverwriteType} [type] The type of overwrite. Use this to bypass automatic resolution of `type` + * that results in an error for an uncached structure + */ + + /** + * Creates or edits permission overwrites for a user or role in this channel. + * @param {RoleResolvable|UserResolvable} userOrRole The user or role to update + * @param {PermissionOverwriteOptions} options The options for the update + * @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update + * @param {PermissionOverwrites} [existing] The existing overwrites to merge with this update + * @returns {Promise<GuildChannel>} + * @private + */ + async upsert(userOrRole, options, overwriteOptions = {}, existing) { + let userOrRoleId = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole); + let { type, reason } = overwriteOptions; + if (typeof type !== 'number') { + userOrRole = this.channel.guild.roles.resolve(userOrRole) ?? this.client.users.resolve(userOrRole); + if (!userOrRole) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'parameter', 'User nor a Role'); + type = userOrRole instanceof Role ? OverwriteType.Role : OverwriteType.Member; + } + + const { allow, deny } = PermissionOverwrites.resolveOverwriteOptions(options, existing); + + await this.client.rest.put(Routes.channelPermission(this.channel.id, userOrRoleId), { + body: { id: userOrRoleId, type, allow, deny }, + reason, + }); + return this.channel; + } + + /** + * Creates permission overwrites for a user or role in this channel, or replaces them if already present. + * @param {RoleResolvable|UserResolvable} userOrRole The user or role to update + * @param {PermissionOverwriteOptions} options The options for the update + * @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update + * @returns {Promise<GuildChannel>} + * @example + * // Create or Replace permission overwrites for a message author + * message.channel.permissionOverwrites.create(message.author, { + * SendMessages: false + * }) + * .then(channel => console.log(channel.permissionOverwrites.cache.get(message.author.id))) + * .catch(console.error); + */ + create(userOrRole, options, overwriteOptions) { + return this.upsert(userOrRole, options, overwriteOptions); + } + + /** + * Edits permission overwrites for a user or role in this channel, or creates an entry if not already present. + * @param {RoleResolvable|UserResolvable} userOrRole The user or role to update + * @param {PermissionOverwriteOptions} options The options for the update + * @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update + * @returns {Promise<GuildChannel>} + * @example + * // Edit or Create permission overwrites for a message author + * message.channel.permissionOverwrites.edit(message.author, { + * SendMessages: false + * }) + * .then(channel => console.log(channel.permissionOverwrites.cache.get(message.author.id))) + * .catch(console.error); + */ + edit(userOrRole, options, overwriteOptions) { + const existing = this.cache.get( + this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole), + ); + return this.upsert(userOrRole, options, overwriteOptions, existing); + } + + /** + * Deletes permission overwrites for a user or role in this channel. + * @param {UserResolvable|RoleResolvable} userOrRole The user or role to delete + * @param {string} [reason] The reason for deleting the overwrite + * @returns {Promise<GuildChannel>} + */ + async delete(userOrRole, reason) { + const userOrRoleId = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole); + if (!userOrRoleId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'parameter', 'User nor a Role'); + + await this.client.rest.delete(Routes.channelPermission(this.channel.id, userOrRoleId), { reason }); + return this.channel; + } +} + +module.exports = PermissionOverwriteManager; diff --git a/node_modules/discord.js/src/managers/PresenceManager.js b/node_modules/discord.js/src/managers/PresenceManager.js new file mode 100644 index 0000000..2d64834 --- /dev/null +++ b/node_modules/discord.js/src/managers/PresenceManager.js @@ -0,0 +1,58 @@ +'use strict'; + +const CachedManager = require('./CachedManager'); +const { Presence } = require('../structures/Presence'); + +/** + * Manages API methods for Presences and holds their cache. + * @extends {CachedManager} + */ +class PresenceManager extends CachedManager { + constructor(client, iterable) { + super(client, Presence, iterable); + } + + /** + * The cache of Presences + * @type {Collection<Snowflake, Presence>} + * @name PresenceManager#cache + */ + + _add(data, cache) { + return super._add(data, cache, { id: data.user.id }); + } + + /** + * Data that can be resolved to a Presence object. This can be: + * * A Presence + * * A UserResolvable + * * A Snowflake + * @typedef {Presence|UserResolvable|Snowflake} PresenceResolvable + */ + + /** + * Resolves a {@link PresenceResolvable} to a {@link Presence} object. + * @param {PresenceResolvable} presence The presence resolvable to resolve + * @returns {?Presence} + */ + resolve(presence) { + const presenceResolvable = super.resolve(presence); + if (presenceResolvable) return presenceResolvable; + const UserResolvable = this.client.users.resolveId(presence); + return super.resolve(UserResolvable); + } + + /** + * Resolves a {@link PresenceResolvable} to a {@link Presence} id. + * @param {PresenceResolvable} presence The presence resolvable to resolve + * @returns {?Snowflake} + */ + resolveId(presence) { + const presenceResolvable = super.resolveId(presence); + if (presenceResolvable) return presenceResolvable; + const userResolvable = this.client.users.resolveId(presence); + return this.cache.has(userResolvable) ? userResolvable : null; + } +} + +module.exports = PresenceManager; diff --git a/node_modules/discord.js/src/managers/ReactionManager.js b/node_modules/discord.js/src/managers/ReactionManager.js new file mode 100644 index 0000000..5535882 --- /dev/null +++ b/node_modules/discord.js/src/managers/ReactionManager.js @@ -0,0 +1,68 @@ +'use strict'; + +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const MessageReaction = require('../structures/MessageReaction'); + +/** + * Manages API methods for reactions and holds their cache. + * @extends {CachedManager} + */ +class ReactionManager extends CachedManager { + constructor(message, iterable) { + super(message.client, MessageReaction, iterable); + + /** + * The message that this manager belongs to + * @type {Message} + */ + this.message = message; + } + + _add(data, cache) { + return super._add(data, cache, { id: data.emoji.id ?? data.emoji.name, extras: [this.message] }); + } + + /** + * The reaction cache of this manager + * @type {Collection<string|Snowflake, MessageReaction>} + * @name ReactionManager#cache + */ + + /** + * Data that can be resolved to a MessageReaction object. This can be: + * * A MessageReaction + * * A Snowflake + * * The Unicode representation of an emoji + * @typedef {MessageReaction|Snowflake} MessageReactionResolvable + */ + + /** + * Resolves a {@link MessageReactionResolvable} to a {@link MessageReaction} object. + * @method resolve + * @memberof ReactionManager + * @instance + * @param {MessageReactionResolvable} reaction The MessageReaction to resolve + * @returns {?MessageReaction} + */ + + /** + * Resolves a {@link MessageReactionResolvable} to a {@link MessageReaction} id. + * @method resolveId + * @memberof ReactionManager + * @instance + * @param {MessageReactionResolvable} reaction The MessageReaction to resolve + * @returns {?Snowflake} + */ + + /** + * Removes all reactions from a message. + * @returns {Promise<Message>} + */ + async removeAll() { + await this.client.rest.delete(Routes.channelMessageAllReactions(this.message.channelId, this.message.id)); + return this.message; + } +} + +module.exports = ReactionManager; diff --git a/node_modules/discord.js/src/managers/ReactionUserManager.js b/node_modules/discord.js/src/managers/ReactionUserManager.js new file mode 100644 index 0000000..014cea8 --- /dev/null +++ b/node_modules/discord.js/src/managers/ReactionUserManager.js @@ -0,0 +1,77 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const User = require('../structures/User'); + +/** + * Manages API methods for users who reacted to a reaction and stores their cache. + * @extends {CachedManager} + */ +class ReactionUserManager extends CachedManager { + constructor(reaction, iterable) { + super(reaction.client, User, iterable); + + /** + * The reaction that this manager belongs to + * @type {MessageReaction} + */ + this.reaction = reaction; + } + + /** + * The cache of this manager + * @type {Collection<Snowflake, User>} + * @name ReactionUserManager#cache + */ + + /** + * Options used to fetch users who gave a reaction. + * @typedef {Object} FetchReactionUsersOptions + * @property {number} [limit=100] The maximum amount of users to fetch, defaults to `100` + * @property {Snowflake} [after] Limit fetching users to those with an id greater than the supplied id + */ + + /** + * Fetches all the users that gave this reaction. Resolves with a collection of users, mapped by their ids. + * @param {FetchReactionUsersOptions} [options] Options for fetching the users + * @returns {Promise<Collection<Snowflake, User>>} + */ + async fetch({ limit = 100, after } = {}) { + const message = this.reaction.message; + const query = makeURLSearchParams({ limit, after }); + const data = await this.client.rest.get( + Routes.channelMessageReaction(message.channelId, message.id, this.reaction.emoji.identifier), + { query }, + ); + const users = new Collection(); + for (const rawUser of data) { + const user = this.client.users._add(rawUser); + this.cache.set(user.id, user); + users.set(user.id, user); + } + return users; + } + + /** + * Removes a user from this reaction. + * @param {UserResolvable} [user=this.client.user] The user to remove the reaction of + * @returns {Promise<MessageReaction>} + */ + async remove(user = this.client.user) { + const userId = this.client.users.resolveId(user); + if (!userId) throw new DiscordjsError(ErrorCodes.ReactionResolveUser); + const message = this.reaction.message; + const route = + userId === this.client.user.id + ? Routes.channelMessageOwnReaction(message.channelId, message.id, this.reaction.emoji.identifier) + : Routes.channelMessageUserReaction(message.channelId, message.id, this.reaction.emoji.identifier, userId); + await this.client.rest.delete(route); + return this.reaction; + } +} + +module.exports = ReactionUserManager; diff --git a/node_modules/discord.js/src/managers/RoleManager.js b/node_modules/discord.js/src/managers/RoleManager.js new file mode 100644 index 0000000..e0c4ed7 --- /dev/null +++ b/node_modules/discord.js/src/managers/RoleManager.js @@ -0,0 +1,360 @@ +'use strict'; + +const process = require('node:process'); +const { Collection } = require('@discordjs/collection'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const { Role } = require('../structures/Role'); +const DataResolver = require('../util/DataResolver'); +const PermissionsBitField = require('../util/PermissionsBitField'); +const { setPosition, resolveColor } = require('../util/Util'); + +let cacheWarningEmitted = false; + +/** + * Manages API methods for roles and stores their cache. + * @extends {CachedManager} + */ +class RoleManager extends CachedManager { + constructor(guild, iterable) { + super(guild.client, Role, iterable); + if (!cacheWarningEmitted && this._cache.constructor.name !== 'Collection') { + cacheWarningEmitted = true; + process.emitWarning( + `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`, + 'UnsupportedCacheOverwriteWarning', + ); + } + + /** + * The guild belonging to this manager + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The role cache of this manager + * @type {Collection<Snowflake, Role>} + * @name RoleManager#cache + */ + + _add(data, cache) { + return super._add(data, cache, { extras: [this.guild] }); + } + + /** + * Obtains a role from Discord, or the role cache if they're already available. + * @param {Snowflake} [id] The role's id + * @param {BaseFetchOptions} [options] Additional options for this fetch + * @returns {Promise<?Role|Collection<Snowflake, Role>>} + * @example + * // Fetch all roles from the guild + * message.guild.roles.fetch() + * .then(roles => console.log(`There are ${roles.size} roles.`)) + * .catch(console.error); + * @example + * // Fetch a single role + * message.guild.roles.fetch('222078108977594368') + * .then(role => console.log(`The role color is: ${role.color}`)) + * .catch(console.error); + */ + async fetch(id, { cache = true, force = false } = {}) { + if (id && !force) { + const existing = this.cache.get(id); + if (existing) return existing; + } + + // We cannot fetch a single role, as of this commit's date, Discord API throws with 405 + const data = await this.client.rest.get(Routes.guildRoles(this.guild.id)); + const roles = new Collection(); + for (const role of data) roles.set(role.id, this._add(role, cache)); + return id ? roles.get(id) ?? null : roles; + } + + /** + * Data that can be resolved to a Role object. This can be: + * * A Role + * * A Snowflake + * @typedef {Role|Snowflake} RoleResolvable + */ + + /** + * Resolves a {@link RoleResolvable} to a {@link Role} object. + * @method resolve + * @memberof RoleManager + * @instance + * @param {RoleResolvable} role The role resolvable to resolve + * @returns {?Role} + */ + + /** + * Resolves a {@link RoleResolvable} to a {@link Role} id. + * @method resolveId + * @memberof RoleManager + * @instance + * @param {RoleResolvable} role The role resolvable to resolve + * @returns {?Snowflake} + */ + + /** + * Options used to create a new role. + * @typedef {Object} RoleCreateOptions + * @property {string} [name] The name of the new role + * @property {ColorResolvable} [color] The data to create the role with + * @property {boolean} [hoist] Whether or not the new role should be hoisted + * @property {PermissionResolvable} [permissions] The permissions for the new role + * @property {number} [position] The position of the new role + * @property {boolean} [mentionable] Whether or not the new role should be mentionable + * @property {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} [icon] The icon for the role + * <warn>The `EmojiResolvable` should belong to the same guild as the role. + * If not, pass the emoji's URL directly</warn> + * @property {?string} [unicodeEmoji] The unicode emoji for the role + * @property {string} [reason] The reason for creating this role + */ + + /** + * Creates a new role in the guild with given information. + * <warn>The position will silently reset to 1 if an invalid one is provided, or none.</warn> + * @param {RoleCreateOptions} [options] Options for creating the new role + * @returns {Promise<Role>} + * @example + * // Create a new role + * guild.roles.create() + * .then(console.log) + * .catch(console.error); + * @example + * // Create a new role with data and a reason + * guild.roles.create({ + * name: 'Super Cool Blue People', + * color: Colors.Blue, + * reason: 'we needed a role for Super Cool People', + * }) + * .then(console.log) + * .catch(console.error); + */ + async create(options = {}) { + let { name, color, hoist, permissions, position, mentionable, reason, icon, unicodeEmoji } = options; + color &&= resolveColor(color); + if (permissions !== undefined) permissions = new PermissionsBitField(permissions); + if (icon) { + const guildEmojiURL = this.guild.emojis.resolve(icon)?.url; + icon = guildEmojiURL ? await DataResolver.resolveImage(guildEmojiURL) : await DataResolver.resolveImage(icon); + if (typeof icon !== 'string') icon = undefined; + } + + const data = await this.client.rest.post(Routes.guildRoles(this.guild.id), { + body: { + name, + color, + hoist, + permissions, + mentionable, + icon, + unicode_emoji: unicodeEmoji, + }, + reason, + }); + const { role } = this.client.actions.GuildRoleCreate.handle({ + guild_id: this.guild.id, + role: data, + }); + if (position) return this.setPosition(role, position, { reason }); + return role; + } + + /** + * Options for editing a role + * @typedef {RoleData} RoleEditOptions + * @property {string} [reason] The reason for editing this role + */ + + /** + * Edits a role of the guild. + * @param {RoleResolvable} role The role to edit + * @param {RoleEditOptions} options The options to provide + * @returns {Promise<Role>} + * @example + * // Edit a role + * guild.roles.edit('222079219327434752', { name: 'buddies' }) + * .then(updated => console.log(`Edited role name to ${updated.name}`)) + * .catch(console.error); + */ + async edit(role, options) { + role = this.resolve(role); + if (!role) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'role', 'RoleResolvable'); + + if (typeof options.position === 'number') { + await this.setPosition(role, options.position, { reason: options.reason }); + } + + let icon = options.icon; + if (icon) { + const guildEmojiURL = this.guild.emojis.resolve(icon)?.url; + icon = guildEmojiURL ? await DataResolver.resolveImage(guildEmojiURL) : await DataResolver.resolveImage(icon); + if (typeof icon !== 'string') icon = undefined; + } + + const body = { + name: options.name, + color: options.color === undefined ? undefined : resolveColor(options.color), + hoist: options.hoist, + permissions: options.permissions === undefined ? undefined : new PermissionsBitField(options.permissions), + mentionable: options.mentionable, + icon, + unicode_emoji: options.unicodeEmoji, + }; + + const d = await this.client.rest.patch(Routes.guildRole(this.guild.id, role.id), { body, reason: options.reason }); + + const clone = role._clone(); + clone._patch(d); + return clone; + } + + /** + * Deletes a role. + * @param {RoleResolvable} role The role to delete + * @param {string} [reason] Reason for deleting the role + * @returns {Promise<void>} + * @example + * // Delete a role + * guild.roles.delete('222079219327434752', 'The role needed to go') + * .then(() => console.log('Deleted the role')) + * .catch(console.error); + */ + async delete(role, reason) { + const id = this.resolveId(role); + await this.client.rest.delete(Routes.guildRole(this.guild.id, id), { reason }); + this.client.actions.GuildRoleDelete.handle({ guild_id: this.guild.id, role_id: id }); + } + + /** + * Sets the new position of the role. + * @param {RoleResolvable} role The role to change the position of + * @param {number} position The new position for the role + * @param {SetRolePositionOptions} [options] Options for setting the position + * @returns {Promise<Role>} + * @example + * // Set the position of the role + * guild.roles.setPosition('222197033908436994', 1) + * .then(updated => console.log(`Role position: ${updated.position}`)) + * .catch(console.error); + */ + async setPosition(role, position, { relative, reason } = {}) { + role = this.resolve(role); + if (!role) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'role', 'RoleResolvable'); + const updatedRoles = await setPosition( + role, + position, + relative, + this.guild._sortedRoles(), + this.client, + Routes.guildRoles(this.guild.id), + reason, + ); + + this.client.actions.GuildRolesPositionUpdate.handle({ + guild_id: this.guild.id, + roles: updatedRoles, + }); + return role; + } + + /** + * The data needed for updating a guild role's position + * @typedef {Object} GuildRolePosition + * @property {RoleResolvable} role The role's id + * @property {number} position The position to update + */ + + /** + * Batch-updates the guild's role positions + * @param {GuildRolePosition[]} rolePositions Role positions to update + * @returns {Promise<Guild>} + * @example + * guild.roles.setPositions([{ role: roleId, position: updatedRoleIndex }]) + * .then(guild => console.log(`Role positions updated for ${guild}`)) + * .catch(console.error); + */ + async setPositions(rolePositions) { + // Make sure rolePositions are prepared for API + rolePositions = rolePositions.map(o => ({ + id: this.resolveId(o.role), + position: o.position, + })); + + // Call the API to update role positions + await this.client.rest.patch(Routes.guildRoles(this.guild.id), { body: rolePositions }); + return this.client.actions.GuildRolesPositionUpdate.handle({ + guild_id: this.guild.id, + roles: rolePositions, + }).guild; + } + + /** + * Compares the positions of two roles. + * @param {RoleResolvable} role1 First role to compare + * @param {RoleResolvable} role2 Second role to compare + * @returns {number} Negative number if the first role's position is lower (second role's is higher), + * positive number if the first's is higher (second's is lower), 0 if equal + */ + comparePositions(role1, role2) { + const resolvedRole1 = this.resolve(role1); + const resolvedRole2 = this.resolve(role2); + if (!resolvedRole1 || !resolvedRole2) { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'role', 'Role nor a Snowflake'); + } + + const role1Position = resolvedRole1.position; + const role2Position = resolvedRole2.position; + + if (role1Position === role2Position) { + return Number(BigInt(resolvedRole2.id) - BigInt(resolvedRole1.id)); + } + + return role1Position - role2Position; + } + + /** + * Gets the managed role a user created when joining the guild, if any + * <info>Only ever available for bots</info> + * @param {UserResolvable} user The user to access the bot role for + * @returns {?Role} + */ + botRoleFor(user) { + const userId = this.client.users.resolveId(user); + if (!userId) return null; + return this.cache.find(role => role.tags?.botId === userId) ?? null; + } + + /** + * The `@everyone` role of the guild + * @type {Role} + * @readonly + */ + get everyone() { + return this.cache.get(this.guild.id); + } + + /** + * The premium subscriber role of the guild, if any + * @type {?Role} + * @readonly + */ + get premiumSubscriberRole() { + return this.cache.find(role => role.tags?.premiumSubscriberRole) ?? null; + } + + /** + * The role with the highest position in the cache + * @type {Role} + * @readonly + */ + get highest() { + return this.cache.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev), this.cache.first()); + } +} + +module.exports = RoleManager; diff --git a/node_modules/discord.js/src/managers/StageInstanceManager.js b/node_modules/discord.js/src/managers/StageInstanceManager.js new file mode 100644 index 0000000..ea037cf --- /dev/null +++ b/node_modules/discord.js/src/managers/StageInstanceManager.js @@ -0,0 +1,154 @@ +'use strict'; + +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../errors'); +const { StageInstance } = require('../structures/StageInstance'); + +/** + * Manages API methods for {@link StageInstance} objects and holds their cache. + * @extends {CachedManager} + */ +class StageInstanceManager extends CachedManager { + constructor(guild, iterable) { + super(guild.client, StageInstance, iterable); + + /** + * The guild this manager belongs to + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The cache of this Manager + * @type {Collection<Snowflake, StageInstance>} + * @name StageInstanceManager#cache + */ + + /** + * Options used to create a stage instance. + * @typedef {Object} StageInstanceCreateOptions + * @property {string} topic The topic of the stage instance + * @property {StageInstancePrivacyLevel} [privacyLevel] The privacy level of the stage instance + * @property {boolean} [sendStartNotification] Whether to notify `@everyone` that the stage instance has started + */ + + /** + * Data that can be resolved to a Stage Channel object. This can be: + * * A StageChannel + * * A Snowflake + * @typedef {StageChannel|Snowflake} StageChannelResolvable + */ + + /** + * Creates a new stage instance. + * @param {StageChannelResolvable} channel The stage channel to associate the created stage instance to + * @param {StageInstanceCreateOptions} options The options to create the stage instance + * @returns {Promise<StageInstance>} + * @example + * // Create a stage instance + * guild.stageInstances.create('1234567890123456789', { + * topic: 'A very creative topic', + * privacyLevel: GuildPrivacyLevel.GuildOnly + * }) + * .then(stageInstance => console.log(stageInstance)) + * .catch(console.error); + */ + async create(channel, options) { + const channelId = this.guild.channels.resolveId(channel); + if (!channelId) throw new DiscordjsError(ErrorCodes.StageChannelResolve); + if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true); + let { topic, privacyLevel, sendStartNotification } = options; + + const data = await this.client.rest.post(Routes.stageInstances(), { + body: { + channel_id: channelId, + topic, + privacy_level: privacyLevel, + send_start_notification: sendStartNotification, + }, + }); + + return this._add(data); + } + + /** + * Fetches the stage instance associated with a stage channel, if it exists. + * @param {StageChannelResolvable} channel The stage channel whose associated stage instance is to be fetched + * @param {BaseFetchOptions} [options] Additional options for this fetch + * @returns {Promise<StageInstance>} + * @example + * // Fetch a stage instance + * guild.stageInstances.fetch('1234567890123456789') + * .then(stageInstance => console.log(stageInstance)) + * .catch(console.error); + */ + async fetch(channel, { cache = true, force = false } = {}) { + const channelId = this.guild.channels.resolveId(channel); + if (!channelId) throw new DiscordjsError(ErrorCodes.StageChannelResolve); + + if (!force) { + const existing = this.cache.find(stageInstance => stageInstance.channelId === channelId); + if (existing) return existing; + } + + const data = await this.client.rest.get(Routes.stageInstance(channelId)); + return this._add(data, cache); + } + + /** + * Options used to edit an existing stage instance. + * @typedef {Object} StageInstanceEditOptions + * @property {string} [topic] The new topic of the stage instance + * @property {StageInstancePrivacyLevel} [privacyLevel] The new privacy level of the stage instance + */ + + /** + * Edits an existing stage instance. + * @param {StageChannelResolvable} channel The stage channel whose associated stage instance is to be edited + * @param {StageInstanceEditOptions} options The options to edit the stage instance + * @returns {Promise<StageInstance>} + * @example + * // Edit a stage instance + * guild.stageInstances.edit('1234567890123456789', { topic: 'new topic' }) + * .then(stageInstance => console.log(stageInstance)) + * .catch(console.error); + */ + async edit(channel, options) { + if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true); + const channelId = this.guild.channels.resolveId(channel); + if (!channelId) throw new DiscordjsError(ErrorCodes.StageChannelResolve); + + let { topic, privacyLevel } = options; + + const data = await this.client.rest.patch(Routes.stageInstance(channelId), { + body: { + topic, + privacy_level: privacyLevel, + }, + }); + + if (this.cache.has(data.id)) { + const clone = this.cache.get(data.id)._clone(); + clone._patch(data); + return clone; + } + + return this._add(data); + } + + /** + * Deletes an existing stage instance. + * @param {StageChannelResolvable} channel The stage channel whose associated stage instance is to be deleted + * @returns {Promise<void>} + */ + async delete(channel) { + const channelId = this.guild.channels.resolveId(channel); + if (!channelId) throw new DiscordjsError(ErrorCodes.StageChannelResolve); + + await this.client.rest.delete(Routes.stageInstance(channelId)); + } +} + +module.exports = StageInstanceManager; diff --git a/node_modules/discord.js/src/managers/ThreadManager.js b/node_modules/discord.js/src/managers/ThreadManager.js new file mode 100644 index 0000000..17569f5 --- /dev/null +++ b/node_modules/discord.js/src/managers/ThreadManager.js @@ -0,0 +1,207 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const ThreadChannel = require('../structures/ThreadChannel'); +const { MakeCacheOverrideSymbol } = require('../util/Symbols'); + +/** + * Manages API methods for thread-based channels and stores their cache. + * @extends {CachedManager} + */ +class ThreadManager extends CachedManager { + static [MakeCacheOverrideSymbol] = ThreadManager; + + constructor(channel, iterable) { + super(channel.client, ThreadChannel, iterable); + + /** + * The channel this Manager belongs to + * @type {TextChannel|NewsChannel|ForumChannel} + */ + this.channel = channel; + } + + /** + * Data that can be resolved to a Thread Channel object. This can be: + * * A ThreadChannel object + * * A Snowflake + * @typedef {ThreadChannel|Snowflake} ThreadChannelResolvable + */ + + /** + * The cache of this Manager + * @type {Collection<Snowflake, ThreadChannel>} + * @name ThreadManager#cache + */ + + _add(thread) { + const existing = this.cache.get(thread.id); + if (existing) return existing; + this.cache.set(thread.id, thread); + return thread; + } + + /** + * Resolves a {@link ThreadChannelResolvable} to a {@link ThreadChannel} object. + * @method resolve + * @memberof ThreadManager + * @instance + * @param {ThreadChannelResolvable} thread The ThreadChannel resolvable to resolve + * @returns {?ThreadChannel} + */ + + /** + * Resolves a {@link ThreadChannelResolvable} to a {@link ThreadChannel} id. + * @method resolveId + * @memberof ThreadManager + * @instance + * @param {ThreadChannelResolvable} thread The ThreadChannel resolvable to resolve + * @returns {?Snowflake} + */ + + /** + * Options for creating a thread. <warn>Only one of `startMessage` or `type` can be defined.</warn> + * @typedef {StartThreadOptions} ThreadCreateOptions + * @property {MessageResolvable} [startMessage] The message to start a thread from. <warn>If this is defined then type + * of thread gets automatically defined and cannot be changed. The provided `type` field will be ignored</warn> + * @property {ChannelType.AnnouncementThread|ChannelType.PublicThread|ChannelType.PrivateThread} [type] + * The type of thread to create. + * Defaults to {@link ChannelType.PublicThread} if created in a {@link TextChannel} + * <warn>When creating threads in a {@link NewsChannel} this is ignored and is always + * {@link ChannelType.AnnouncementThread}</warn> + * @property {boolean} [invitable] Whether non-moderators can add other non-moderators to the thread + * <info>Can only be set when type will be {@link ChannelType.PrivateThread}</info> + */ + + /** + * Options for fetching multiple threads. + * @typedef {Object} FetchThreadsOptions + * @property {FetchArchivedThreadOptions} [archived] Options used to fetch archived threads + */ + + /** + * Obtains a thread from Discord, or the channel cache if it's already available. + * @param {ThreadChannelResolvable|FetchThreadsOptions} [options] The options to fetch threads. If it is a + * ThreadChannelResolvable then the specified thread will be fetched. Fetches all active threads if `undefined` + * @param {BaseFetchOptions} [cacheOptions] Additional options for this fetch. <warn>The `force` field gets ignored + * if `options` is not a {@link ThreadChannelResolvable}</warn> + * @returns {Promise<?(ThreadChannel|FetchedThreads|FetchedThreadsMore)>} + * {@link FetchedThreads} if active & {@link FetchedThreadsMore} if archived. + * @example + * // Fetch a thread by its id + * channel.threads.fetch('831955138126104859') + * .then(channel => console.log(channel.name)) + * .catch(console.error); + */ + fetch(options, { cache, force } = {}) { + if (!options) return this.fetchActive(cache); + const channel = this.client.channels.resolveId(options); + if (channel) return this.client.channels.fetch(channel, { cache, force }); + if (options.archived) { + return this.fetchArchived(options.archived, cache); + } + return this.fetchActive(cache); + } + + /** + * Data that can be resolved to a Date object. This can be: + * * A Date object + * * A number representing a timestamp + * * An [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string + * @typedef {Date|number|string} DateResolvable + */ + + /** + * The options used to fetch archived threads. + * @typedef {Object} FetchArchivedThreadOptions + * @property {string} [type='public'] The type of threads to fetch (`public` or `private`) + * @property {boolean} [fetchAll=false] Whether to fetch **all** archived threads when `type` is `private` + * <info>This property requires the {@link PermissionFlagsBits.ManageThreads} permission if `true`.</info> + * @property {DateResolvable|ThreadChannelResolvable} [before] Only return threads that were archived before this Date + * or Snowflake + * <warn>Must be a {@link ThreadChannelResolvable} when `type` is `private` and `fetchAll` is `false`.</warn> + * @property {number} [limit] Maximum number of threads to return + */ + + /** + * Data returned from fetching multiple threads. + * @typedef {FetchedThreads} FetchedThreadsMore + * @property {?boolean} hasMore Whether there are potentially additional threads that require a subsequent call + */ + + /** + * Obtains a set of archived threads from Discord. + * <info>This method requires the {@link PermissionFlagsBits.ReadMessageHistory} permission + * in the parent channel.</info> + * @param {FetchArchivedThreadOptions} [options] The options to fetch archived threads + * @param {boolean} [cache=true] Whether to cache the new thread objects if they aren't already + * @returns {Promise<FetchedThreadsMore>} + */ + async fetchArchived({ type = 'public', fetchAll = false, before, limit } = {}, cache = true) { + let path = Routes.channelThreads(this.channel.id, type); + if (type === 'private' && !fetchAll) { + path = Routes.channelJoinedArchivedThreads(this.channel.id); + } + let timestamp; + let id; + const query = makeURLSearchParams({ limit }); + if (before !== undefined) { + if (before instanceof ThreadChannel || /^\d{17,19}$/.test(String(before))) { + id = this.resolveId(before); + timestamp = this.resolve(before)?.archivedAt?.toISOString(); + const toUse = type === 'private' && !fetchAll ? id : timestamp; + if (toUse) { + query.set('before', toUse); + } + } else { + try { + timestamp = new Date(before).toISOString(); + if (type === 'public' || fetchAll) { + query.set('before', timestamp); + } + } catch { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'before', 'DateResolvable or ThreadChannelResolvable'); + } + } + } + + const raw = await this.client.rest.get(path, { query }); + return this.constructor._mapThreads(raw, this.client, { parent: this.channel, cache }); + } + + /** + * Obtains all active threads in the channel. + * @param {boolean} [cache=true] Whether to cache the fetched data + * @returns {Promise<FetchedThreads>} + */ + async fetchActive(cache = true) { + const data = await this.channel.guild.channels.rawFetchGuildActiveThreads(); + return this.constructor._mapThreads(data, this.client, { parent: this.channel, cache }); + } + + static _mapThreads(rawThreads, client, { parent, guild, cache }) { + const threads = rawThreads.threads.reduce((coll, raw) => { + const thread = client.channels._add(raw, guild ?? parent?.guild, { cache }); + if (parent && thread.parentId !== parent.id) return coll; + return coll.set(thread.id, thread); + }, new Collection()); + + // Discord sends the thread id as id in this object + const threadMembers = rawThreads.members.reduce((coll, raw) => { + const thread = threads.get(raw.id); + return thread ? coll.set(raw.user_id, thread.members._add(raw)) : coll; + }, new Collection()); + + const response = { threads, members: threadMembers }; + + // The GET `/guilds/{guild.id}/threads/active` route does not return `has_more`. + if ('has_more' in rawThreads) response.hasMore = rawThreads.has_more; + return response; + } +} + +module.exports = ThreadManager; diff --git a/node_modules/discord.js/src/managers/ThreadMemberManager.js b/node_modules/discord.js/src/managers/ThreadMemberManager.js new file mode 100644 index 0000000..c138aa3 --- /dev/null +++ b/node_modules/discord.js/src/managers/ThreadMemberManager.js @@ -0,0 +1,182 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const ThreadMember = require('../structures/ThreadMember'); + +/** + * Manages API methods for GuildMembers and stores their cache. + * @extends {CachedManager} + */ +class ThreadMemberManager extends CachedManager { + constructor(thread, iterable) { + super(thread.client, ThreadMember, iterable); + + /** + * The thread this manager belongs to + * @type {ThreadChannel} + */ + this.thread = thread; + } + + /** + * The cache of this Manager + * @type {Collection<Snowflake, ThreadMember>} + * @name ThreadMemberManager#cache + */ + + _add(data, cache = true) { + const existing = this.cache.get(data.user_id); + if (cache) existing?._patch(data, { cache }); + if (existing) return existing; + + const member = new ThreadMember(this.thread, data, { cache }); + if (cache) this.cache.set(data.user_id, member); + return member; + } + + /** + * Fetches the client user as a ThreadMember of the thread. + * @param {BaseFetchOptions} [options] The options for fetching the member + * @returns {Promise<ThreadMember>} + */ + fetchMe(options) { + return this.fetch({ ...options, member: this.client.user.id }); + } + + /** + * The client user as a ThreadMember of this ThreadChannel + * @type {?ThreadMember} + * @readonly + */ + get me() { + return this.resolve(this.client.user.id); + } + + /** + * Data that resolves to give a ThreadMember object. This can be: + * * A ThreadMember object + * * A User resolvable + * @typedef {ThreadMember|UserResolvable} ThreadMemberResolvable + */ + + /** + * Resolves a {@link ThreadMemberResolvable} to a {@link ThreadMember} object. + * @param {ThreadMemberResolvable} member The user that is part of the thread + * @returns {?GuildMember} + */ + resolve(member) { + const memberResolvable = super.resolve(member); + if (memberResolvable) return memberResolvable; + const userResolvable = this.client.users.resolveId(member); + if (userResolvable) return super.resolve(userResolvable); + return null; + } + + /** + * Resolves a {@link ThreadMemberResolvable} to a {@link ThreadMember} id string. + * @param {ThreadMemberResolvable} member The user that is part of the guild + * @returns {?Snowflake} + */ + resolveId(member) { + const memberResolvable = super.resolveId(member); + if (memberResolvable) return memberResolvable; + const userResolvable = this.client.users.resolveId(member); + return this.cache.has(userResolvable) ? userResolvable : null; + } + + /** + * Adds a member to the thread. + * @param {UserResolvable|'@me'} member The member to add + * @param {string} [reason] The reason for adding this member + * @returns {Promise<Snowflake>} + */ + async add(member, reason) { + const id = member === '@me' ? member : this.client.users.resolveId(member); + if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'member', 'UserResolvable'); + await this.client.rest.put(Routes.threadMembers(this.thread.id, id), { reason }); + return id; + } + + /** + * Remove a user from the thread. + * @param {Snowflake|'@me'} id The id of the member to remove + * @param {string} [reason] The reason for removing this member from the thread + * @returns {Promise<Snowflake>} + */ + async remove(id, reason) { + await this.client.rest.delete(Routes.threadMembers(this.thread.id, id), { reason }); + return id; + } + + /** + * Options used to fetch a thread member. + * @typedef {BaseFetchOptions} FetchThreadMemberOptions + * @property {ThreadMemberResolvable} member The thread member to fetch + * @property {boolean} [withMember] Whether to also return the guild member associated with this thread member + */ + + /** + * Options used to fetch multiple thread members with guild member data. + * <info>With `withMember` set to `true`, pagination is enabled.</info> + * @typedef {Object} FetchThreadMembersWithGuildMemberDataOptions + * @property {true} withMember Whether to also return the guild member data + * @property {Snowflake} [after] Consider only thread members after this id + * @property {number} [limit] The maximum number of thread members to return + * @property {boolean} [cache] Whether to cache the fetched thread members and guild members + */ + + /** + * Options used to fetch multiple thread members without guild member data. + * @typedef {Object} FetchThreadMembersWithoutGuildMemberDataOptions + * @property {false} [withMember] Whether to also return the guild member data + * @property {boolean} [cache] Whether to cache the fetched thread members + */ + + /** + * Options used to fetch multiple thread members. + * @typedef {FetchThreadMembersWithGuildMemberDataOptions| + * FetchThreadMembersWithoutGuildMemberDataOptions} FetchThreadMembersOptions + */ + + /** + * Fetches thread member(s) from Discord. + * <info>This method requires the {@link GatewayIntentBits.GuildMembers} privileged gateway intent.</info> + * @param {ThreadMemberResolvable|FetchThreadMemberOptions|FetchThreadMembersOptions} [options] + * Options for fetching thread member(s) + * @returns {Promise<ThreadMember|Collection<Snowflake, ThreadMember>>} + */ + fetch(options) { + if (!options) return this._fetchMany(); + const { member, withMember, cache, force } = options; + const resolvedMember = this.resolveId(member ?? options); + if (resolvedMember) return this._fetchSingle({ member: resolvedMember, withMember, cache, force }); + return this._fetchMany(options); + } + + async _fetchSingle({ member, withMember, cache, force = false }) { + if (!force) { + const existing = this.cache.get(member); + if (existing) return existing; + } + + const data = await this.client.rest.get(Routes.threadMembers(this.thread.id, member), { + query: makeURLSearchParams({ with_member: withMember }), + }); + + return this._add(data, cache); + } + + async _fetchMany({ withMember, after, limit, cache } = {}) { + const data = await this.client.rest.get(Routes.threadMembers(this.thread.id), { + query: makeURLSearchParams({ with_member: withMember, after, limit }), + }); + + return data.reduce((col, member) => col.set(member.user_id, this._add(member, cache)), new Collection()); + } +} + +module.exports = ThreadMemberManager; diff --git a/node_modules/discord.js/src/managers/UserManager.js b/node_modules/discord.js/src/managers/UserManager.js new file mode 100644 index 0000000..24478f6 --- /dev/null +++ b/node_modules/discord.js/src/managers/UserManager.js @@ -0,0 +1,139 @@ +'use strict'; + +const { ChannelType, Routes } = require('discord-api-types/v10'); +const CachedManager = require('./CachedManager'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const { GuildMember } = require('../structures/GuildMember'); +const { Message } = require('../structures/Message'); +const ThreadMember = require('../structures/ThreadMember'); +const User = require('../structures/User'); + +/** + * Manages API methods for users and stores their cache. + * @extends {CachedManager} + */ +class UserManager extends CachedManager { + constructor(client, iterable) { + super(client, User, iterable); + } + + /** + * The cache of this manager + * @type {Collection<Snowflake, User>} + * @name UserManager#cache + */ + + /** + * Data that resolves to give a User object. This can be: + * * A User object + * * A Snowflake + * * A Message object (resolves to the message author) + * * A GuildMember object + * * A ThreadMember object + * @typedef {User|Snowflake|Message|GuildMember|ThreadMember} UserResolvable + */ + + /** + * The DM between the client's user and a user + * @param {Snowflake} userId The user id + * @returns {?DMChannel} + * @private + */ + dmChannel(userId) { + return this.client.channels.cache.find(c => c.type === ChannelType.DM && c.recipientId === userId) ?? null; + } + + /** + * Creates a {@link DMChannel} between the client and a user. + * @param {UserResolvable} user The UserResolvable to identify + * @param {BaseFetchOptions} [options] Additional options for this fetch + * @returns {Promise<DMChannel>} + */ + async createDM(user, { cache = true, force = false } = {}) { + const id = this.resolveId(user); + + if (!force) { + const dmChannel = this.dmChannel(id); + if (dmChannel && !dmChannel.partial) return dmChannel; + } + + const data = await this.client.rest.post(Routes.userChannels(), { body: { recipient_id: id } }); + return this.client.channels._add(data, null, { cache }); + } + + /** + * Deletes a {@link DMChannel} (if one exists) between the client and a user. Resolves with the channel if successful. + * @param {UserResolvable} user The UserResolvable to identify + * @returns {Promise<DMChannel>} + */ + async deleteDM(user) { + const id = this.resolveId(user); + const dmChannel = this.dmChannel(id); + if (!dmChannel) throw new DiscordjsError(ErrorCodes.UserNoDMChannel); + await this.client.rest.delete(Routes.channel(dmChannel.id)); + this.client.channels._remove(dmChannel.id); + return dmChannel; + } + + /** + * Obtains a user from Discord, or the user cache if it's already available. + * @param {UserResolvable} user The user to fetch + * @param {BaseFetchOptions} [options] Additional options for this fetch + * @returns {Promise<User>} + */ + async fetch(user, { cache = true, force = false } = {}) { + const id = this.resolveId(user); + if (!force) { + const existing = this.cache.get(id); + if (existing && !existing.partial) return existing; + } + + const data = await this.client.rest.get(Routes.user(id)); + return this._add(data, cache); + } + + /** + * Fetches a user's flags. + * @param {UserResolvable} user The UserResolvable to identify + * @param {BaseFetchOptions} [options] Additional options for this fetch + * @returns {Promise<UserFlagsBitField>} + */ + async fetchFlags(user, options) { + return (await this.fetch(user, options)).flags; + } + + /** + * Sends a message to a user. + * @param {UserResolvable} user The UserResolvable to identify + * @param {string|MessagePayload|MessageCreateOptions} options The options to provide + * @returns {Promise<Message>} + */ + async send(user, options) { + return (await this.createDM(user)).send(options); + } + + /** + * Resolves a {@link UserResolvable} to a {@link User} object. + * @param {UserResolvable} user The UserResolvable to identify + * @returns {?User} + */ + resolve(user) { + if (user instanceof GuildMember || user instanceof ThreadMember) return user.user; + if (user instanceof Message) return user.author; + return super.resolve(user); + } + + /** + * Resolves a {@link UserResolvable} to a {@link User} id. + * @param {UserResolvable} user The UserResolvable to identify + * @returns {?Snowflake} + */ + resolveId(user) { + if (user instanceof ThreadMember) return user.id; + if (user instanceof GuildMember) return user.user.id; + if (user instanceof Message) return user.author.id; + return super.resolveId(user); + } +} + +module.exports = UserManager; diff --git a/node_modules/discord.js/src/managers/VoiceStateManager.js b/node_modules/discord.js/src/managers/VoiceStateManager.js new file mode 100644 index 0000000..c42fdd2 --- /dev/null +++ b/node_modules/discord.js/src/managers/VoiceStateManager.js @@ -0,0 +1,37 @@ +'use strict'; + +const CachedManager = require('./CachedManager'); +const VoiceState = require('../structures/VoiceState'); + +/** + * Manages API methods for VoiceStates and stores their cache. + * @extends {CachedManager} + */ +class VoiceStateManager extends CachedManager { + constructor(guild, iterable) { + super(guild.client, VoiceState, iterable); + + /** + * The guild this manager belongs to + * @type {Guild} + */ + this.guild = guild; + } + + /** + * The cache of this manager + * @type {Collection<Snowflake, VoiceState>} + * @name VoiceStateManager#cache + */ + + _add(data, cache = true) { + const existing = this.cache.get(data.user_id); + if (existing) return existing._patch(data); + + const entry = new this.holds(this.guild, data); + if (cache) this.cache.set(data.user_id, entry); + return entry; + } +} + +module.exports = VoiceStateManager; diff --git a/node_modules/discord.js/src/sharding/Shard.js b/node_modules/discord.js/src/sharding/Shard.js new file mode 100644 index 0000000..f833309 --- /dev/null +++ b/node_modules/discord.js/src/sharding/Shard.js @@ -0,0 +1,475 @@ +'use strict'; + +const EventEmitter = require('node:events'); +const path = require('node:path'); +const process = require('node:process'); +const { setTimeout, clearTimeout } = require('node:timers'); +const { setTimeout: sleep } = require('node:timers/promises'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const ShardEvents = require('../util/ShardEvents'); +const { makeError, makePlainError } = require('../util/Util'); +let childProcess = null; +let Worker = null; + +/** + * A self-contained shard created by the {@link ShardingManager}. Each one has a {@link ChildProcess} that contains + * an instance of the bot and its {@link Client}. When its child process/worker exits for any reason, the shard will + * spawn a new one to replace it as necessary. + * @extends {EventEmitter} + */ +class Shard extends EventEmitter { + constructor(manager, id) { + super(); + + switch (manager.mode) { + case 'process': + childProcess = require('node:child_process'); + break; + case 'worker': + Worker = require('node:worker_threads').Worker; + break; + } + + /** + * Manager that created the shard + * @type {ShardingManager} + */ + this.manager = manager; + + /** + * The shard's id in the manager + * @type {number} + */ + this.id = id; + + /** + * Whether to pass silent flag to the shard's process (only when {@link ShardingManager#mode} is `process`) + * @type {boolean} + */ + this.silent = manager.silent; + + /** + * Arguments for the shard's process (only when {@link ShardingManager#mode} is `process`) + * @type {string[]} + */ + this.args = manager.shardArgs ?? []; + + /** + * Arguments for the shard's process executable (only when {@link ShardingManager#mode} is `process`) + * @type {string[]} + */ + this.execArgv = manager.execArgv; + + /** + * Environment variables for the shard's process, or workerData for the shard's worker + * @type {Object} + */ + this.env = Object.assign({}, process.env, { + SHARDING_MANAGER: true, + SHARDS: this.id, + SHARD_COUNT: this.manager.totalShards, + DISCORD_TOKEN: this.manager.token, + }); + + /** + * Whether the shard's {@link Client} is ready + * @type {boolean} + */ + this.ready = false; + + /** + * Process of the shard (if {@link ShardingManager#mode} is `process`) + * @type {?ChildProcess} + */ + this.process = null; + + /** + * Worker of the shard (if {@link ShardingManager#mode} is `worker`) + * @type {?Worker} + */ + this.worker = null; + + /** + * Ongoing promises for calls to {@link Shard#eval}, mapped by the `script` they were called with + * @type {Map<string, Promise>} + * @private + */ + this._evals = new Map(); + + /** + * Ongoing promises for calls to {@link Shard#fetchClientValue}, mapped by the `prop` they were called with + * @type {Map<string, Promise>} + * @private + */ + this._fetches = new Map(); + + /** + * Listener function for the {@link ChildProcess}' `exit` event + * @type {Function} + * @private + */ + this._exitListener = null; + } + + /** + * Forks a child process or creates a worker thread for the shard. + * <warn>You should not need to call this manually.</warn> + * @param {number} [timeout=30000] The amount in milliseconds to wait until the {@link Client} has become ready + * before resolving (`-1` or `Infinity` for no wait) + * @returns {Promise<ChildProcess>} + */ + spawn(timeout = 30_000) { + if (this.process) throw new DiscordjsError(ErrorCodes.ShardingProcessExists, this.id); + if (this.worker) throw new DiscordjsError(ErrorCodes.ShardingWorkerExists, this.id); + + this._exitListener = this._handleExit.bind(this, undefined, timeout); + + switch (this.manager.mode) { + case 'process': + this.process = childProcess + .fork(path.resolve(this.manager.file), this.args, { + env: this.env, + execArgv: this.execArgv, + silent: this.silent, + }) + .on('message', this._handleMessage.bind(this)) + .on('exit', this._exitListener); + break; + case 'worker': + this.worker = new Worker(path.resolve(this.manager.file), { workerData: this.env }) + .on('message', this._handleMessage.bind(this)) + .on('exit', this._exitListener); + break; + } + + this._evals.clear(); + this._fetches.clear(); + + const child = this.process ?? this.worker; + + /** + * Emitted upon the creation of the shard's child process/worker. + * @event Shard#spawn + * @param {ChildProcess|Worker} process Child process/worker that was created + */ + this.emit(ShardEvents.Spawn, child); + + if (timeout === -1 || timeout === Infinity) return Promise.resolve(child); + return new Promise((resolve, reject) => { + const cleanup = () => { + clearTimeout(spawnTimeoutTimer); + this.off('ready', onReady); + this.off('disconnect', onDisconnect); + this.off('death', onDeath); + }; + + const onReady = () => { + cleanup(); + resolve(child); + }; + + const onDisconnect = () => { + cleanup(); + reject(new DiscordjsError(ErrorCodes.ShardingReadyDisconnected, this.id)); + }; + + const onDeath = () => { + cleanup(); + reject(new DiscordjsError(ErrorCodes.ShardingReadyDied, this.id)); + }; + + const onTimeout = () => { + cleanup(); + reject(new DiscordjsError(ErrorCodes.ShardingReadyTimeout, this.id)); + }; + + const spawnTimeoutTimer = setTimeout(onTimeout, timeout); + this.once('ready', onReady); + this.once('disconnect', onDisconnect); + this.once('death', onDeath); + }); + } + + /** + * Immediately kills the shard's process/worker and does not restart it. + */ + kill() { + if (this.process) { + this.process.removeListener('exit', this._exitListener); + this.process.kill(); + } else { + this.worker.removeListener('exit', this._exitListener); + this.worker.terminate(); + } + + this._handleExit(false); + } + + /** + * Options used to respawn a shard. + * @typedef {Object} ShardRespawnOptions + * @property {number} [delay=500] How long to wait between killing the process/worker and + * restarting it (in milliseconds) + * @property {number} [timeout=30000] The amount in milliseconds to wait until the {@link Client} + * has become ready before resolving (`-1` or `Infinity` for no wait) + */ + + /** + * Kills and restarts the shard's process/worker. + * @param {ShardRespawnOptions} [options] Options for respawning the shard + * @returns {Promise<ChildProcess>} + */ + async respawn({ delay = 500, timeout = 30_000 } = {}) { + this.kill(); + if (delay > 0) await sleep(delay); + return this.spawn(timeout); + } + + /** + * Sends a message to the shard's process/worker. + * @param {*} message Message to send to the shard + * @returns {Promise<Shard>} + */ + send(message) { + return new Promise((resolve, reject) => { + if (this.process) { + this.process.send(message, err => { + if (err) reject(err); + else resolve(this); + }); + } else { + this.worker.postMessage(message); + resolve(this); + } + }); + } + + /** + * Fetches a client property value of the shard. + * @param {string} prop Name of the client property to get, using periods for nesting + * @returns {Promise<*>} + * @example + * shard.fetchClientValue('guilds.cache.size') + * .then(count => console.log(`${count} guilds in shard ${shard.id}`)) + * .catch(console.error); + */ + fetchClientValue(prop) { + // Shard is dead (maybe respawning), don't cache anything and error immediately + if (!this.process && !this.worker) { + return Promise.reject(new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id)); + } + + // Cached promise from previous call + if (this._fetches.has(prop)) return this._fetches.get(prop); + + const promise = new Promise((resolve, reject) => { + const child = this.process ?? this.worker; + + const listener = message => { + if (message?._fetchProp !== prop) return; + child.removeListener('message', listener); + this.decrementMaxListeners(child); + this._fetches.delete(prop); + if (!message._error) resolve(message._result); + else reject(makeError(message._error)); + }; + + this.incrementMaxListeners(child); + child.on('message', listener); + + this.send({ _fetchProp: prop }).catch(err => { + child.removeListener('message', listener); + this.decrementMaxListeners(child); + this._fetches.delete(prop); + reject(err); + }); + }); + + this._fetches.set(prop, promise); + return promise; + } + + /** + * Evaluates a script or function on the shard, in the context of the {@link Client}. + * @param {string|Function} script JavaScript to run on the shard + * @param {*} [context] The context for the eval + * @returns {Promise<*>} Result of the script execution + */ + eval(script, context) { + // Stringify the script if it's a Function + const _eval = typeof script === 'function' ? `(${script})(this, ${JSON.stringify(context)})` : script; + + // Shard is dead (maybe respawning), don't cache anything and error immediately + if (!this.process && !this.worker) { + return Promise.reject(new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id)); + } + + // Cached promise from previous call + if (this._evals.has(_eval)) return this._evals.get(_eval); + + const promise = new Promise((resolve, reject) => { + const child = this.process ?? this.worker; + + const listener = message => { + if (message?._eval !== _eval) return; + child.removeListener('message', listener); + this.decrementMaxListeners(child); + this._evals.delete(_eval); + if (!message._error) resolve(message._result); + else reject(makeError(message._error)); + }; + + this.incrementMaxListeners(child); + child.on('message', listener); + + this.send({ _eval }).catch(err => { + child.removeListener('message', listener); + this.decrementMaxListeners(child); + this._evals.delete(_eval); + reject(err); + }); + }); + + this._evals.set(_eval, promise); + return promise; + } + + /** + * Handles a message received from the child process/worker. + * @param {*} message Message received + * @private + */ + _handleMessage(message) { + if (message) { + // Shard is ready + if (message._ready) { + this.ready = true; + /** + * Emitted upon the shard's {@link Client#event:shardReady} event. + * @event Shard#ready + */ + this.emit(ShardEvents.Ready); + return; + } + + // Shard has disconnected + if (message._disconnect) { + this.ready = false; + /** + * Emitted upon the shard's {@link Client#event:shardDisconnect} event. + * @event Shard#disconnect + */ + this.emit(ShardEvents.Disconnect); + return; + } + + // Shard is attempting to reconnect + if (message._reconnecting) { + this.ready = false; + /** + * Emitted upon the shard's {@link Client#event:shardReconnecting} event. + * @event Shard#reconnecting + */ + this.emit(ShardEvents.Reconnecting); + return; + } + + // Shard has resumed + if (message._resume) { + this.ready = true; + /** + * Emitted upon the shard's {@link Client#event:shardResume} event. + * @event Shard#resume + */ + this.emit(ShardEvents.Resume); + return; + } + + // Shard is requesting a property fetch + if (message._sFetchProp) { + const resp = { _sFetchProp: message._sFetchProp, _sFetchPropShard: message._sFetchPropShard }; + this.manager.fetchClientValues(message._sFetchProp, message._sFetchPropShard).then( + results => this.send({ ...resp, _result: results }), + err => this.send({ ...resp, _error: makePlainError(err) }), + ); + return; + } + + // Shard is requesting an eval broadcast + if (message._sEval) { + const resp = { _sEval: message._sEval, _sEvalShard: message._sEvalShard }; + this.manager._performOnShards('eval', [message._sEval], message._sEvalShard).then( + results => this.send({ ...resp, _result: results }), + err => this.send({ ...resp, _error: makePlainError(err) }), + ); + return; + } + + // Shard is requesting a respawn of all shards + if (message._sRespawnAll) { + const { shardDelay, respawnDelay, timeout } = message._sRespawnAll; + this.manager.respawnAll({ shardDelay, respawnDelay, timeout }).catch(() => { + // Do nothing + }); + return; + } + } + + /** + * Emitted upon receiving a message from the child process/worker. + * @event Shard#message + * @param {*} message Message that was received + */ + this.emit(ShardEvents.Message, message); + } + + /** + * Handles the shard's process/worker exiting. + * @param {boolean} [respawn=this.manager.respawn] Whether to spawn the shard again + * @param {number} [timeout] The amount in milliseconds to wait until the {@link Client} + * has become ready (`-1` or `Infinity` for no wait) + * @private + */ + _handleExit(respawn = this.manager.respawn, timeout) { + /** + * Emitted upon the shard's child process/worker exiting. + * @event Shard#death + * @param {ChildProcess|Worker} process Child process/worker that exited + */ + this.emit(ShardEvents.Death, this.process ?? this.worker); + + this.ready = false; + this.process = null; + this.worker = null; + this._evals.clear(); + this._fetches.clear(); + + if (respawn) this.spawn(timeout).catch(err => this.emit(ShardEvents.Error, err)); + } + + /** + * Increments max listeners by one for a given emitter, if they are not zero. + * @param {EventEmitter|process} emitter The emitter that emits the events. + * @private + */ + incrementMaxListeners(emitter) { + const maxListeners = emitter.getMaxListeners(); + if (maxListeners !== 0) { + emitter.setMaxListeners(maxListeners + 1); + } + } + + /** + * Decrements max listeners by one for a given emitter, if they are not zero. + * @param {EventEmitter|process} emitter The emitter that emits the events. + * @private + */ + decrementMaxListeners(emitter) { + const maxListeners = emitter.getMaxListeners(); + if (maxListeners !== 0) { + emitter.setMaxListeners(maxListeners - 1); + } + } +} + +module.exports = Shard; diff --git a/node_modules/discord.js/src/sharding/ShardClientUtil.js b/node_modules/discord.js/src/sharding/ShardClientUtil.js new file mode 100644 index 0000000..c1bd4a8 --- /dev/null +++ b/node_modules/discord.js/src/sharding/ShardClientUtil.js @@ -0,0 +1,291 @@ +'use strict'; + +const process = require('node:process'); +const { calculateShardId } = require('@discordjs/util'); +const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors'); +const Events = require('../util/Events'); +const { makeError, makePlainError } = require('../util/Util'); + +/** + * Helper class for sharded clients spawned as a child process/worker, such as from a {@link ShardingManager}. + * Utilises IPC to send and receive data to/from the master process and other shards. + */ +class ShardClientUtil { + constructor(client, mode) { + /** + * Client for the shard + * @type {Client} + */ + this.client = client; + + /** + * Mode the shard was spawned with + * @type {ShardingManagerMode} + */ + this.mode = mode; + + /** + * Message port for the master process (only when {@link ShardClientUtil#mode} is `worker`) + * @type {?MessagePort} + */ + this.parentPort = null; + + switch (mode) { + case 'process': + process.on('message', this._handleMessage.bind(this)); + client.on(Events.ShardReady, () => { + process.send({ _ready: true }); + }); + client.on(Events.ShardDisconnect, () => { + process.send({ _disconnect: true }); + }); + client.on(Events.ShardReconnecting, () => { + process.send({ _reconnecting: true }); + }); + client.on(Events.ShardResume, () => { + process.send({ _resume: true }); + }); + break; + case 'worker': + this.parentPort = require('node:worker_threads').parentPort; + this.parentPort.on('message', this._handleMessage.bind(this)); + client.on(Events.ShardReady, () => { + this.parentPort.postMessage({ _ready: true }); + }); + client.on(Events.ShardDisconnect, () => { + this.parentPort.postMessage({ _disconnect: true }); + }); + client.on(Events.ShardReconnecting, () => { + this.parentPort.postMessage({ _reconnecting: true }); + }); + client.on(Events.ShardResume, () => { + this.parentPort.postMessage({ _resume: true }); + }); + break; + } + } + + /** + * Array of shard ids of this client + * @type {number[]} + * @readonly + */ + get ids() { + return this.client.options.shards; + } + + /** + * Total number of shards + * @type {number} + * @readonly + */ + get count() { + return this.client.options.shardCount; + } + + /** + * Sends a message to the master process. + * @param {*} message Message to send + * @returns {Promise<void>} + * @emits Shard#message + */ + send(message) { + return new Promise((resolve, reject) => { + switch (this.mode) { + case 'process': + process.send(message, err => { + if (err) reject(err); + else resolve(); + }); + break; + case 'worker': + this.parentPort.postMessage(message); + resolve(); + break; + } + }); + } + + /** + * Fetches a client property value of each shard, or a given shard. + * @param {string} prop Name of the client property to get, using periods for nesting + * @param {number} [shard] Shard to fetch property from, all if undefined + * @returns {Promise<*|Array<*>>} + * @example + * client.shard.fetchClientValues('guilds.cache.size') + * .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`)) + * .catch(console.error); + * @see {@link ShardingManager#fetchClientValues} + */ + fetchClientValues(prop, shard) { + return new Promise((resolve, reject) => { + const parent = this.parentPort ?? process; + + const listener = message => { + if (message?._sFetchProp !== prop || message._sFetchPropShard !== shard) return; + parent.removeListener('message', listener); + this.decrementMaxListeners(parent); + if (!message._error) resolve(message._result); + else reject(makeError(message._error)); + }; + this.incrementMaxListeners(parent); + parent.on('message', listener); + + this.send({ _sFetchProp: prop, _sFetchPropShard: shard }).catch(err => { + parent.removeListener('message', listener); + this.decrementMaxListeners(parent); + reject(err); + }); + }); + } + + /** + * Evaluates a script or function on all shards, or a given shard, in the context of the {@link Client}s. + * @param {Function} script JavaScript to run on each shard + * @param {BroadcastEvalOptions} [options={}] The options for the broadcast + * @returns {Promise<*|Array<*>>} Results of the script execution + * @example + * client.shard.broadcastEval(client => client.guilds.cache.size) + * .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`)) + * .catch(console.error); + * @see {@link ShardingManager#broadcastEval} + */ + broadcastEval(script, options = {}) { + return new Promise((resolve, reject) => { + const parent = this.parentPort ?? process; + if (typeof script !== 'function') { + reject(new DiscordjsTypeError(ErrorCodes.ShardingInvalidEvalBroadcast)); + return; + } + script = `(${script})(this, ${JSON.stringify(options.context)})`; + + const listener = message => { + if (message?._sEval !== script || message._sEvalShard !== options.shard) return; + parent.removeListener('message', listener); + this.decrementMaxListeners(parent); + if (!message._error) resolve(message._result); + else reject(makeError(message._error)); + }; + this.incrementMaxListeners(parent); + parent.on('message', listener); + this.send({ _sEval: script, _sEvalShard: options.shard }).catch(err => { + parent.removeListener('message', listener); + this.decrementMaxListeners(parent); + reject(err); + }); + }); + } + + /** + * Requests a respawn of all shards. + * @param {MultipleShardRespawnOptions} [options] Options for respawning shards + * @returns {Promise<void>} Resolves upon the message being sent + * @see {@link ShardingManager#respawnAll} + */ + respawnAll({ shardDelay = 5_000, respawnDelay = 500, timeout = 30_000 } = {}) { + return this.send({ _sRespawnAll: { shardDelay, respawnDelay, timeout } }); + } + + /** + * Handles an IPC message. + * @param {*} message Message received + * @private + */ + async _handleMessage(message) { + if (!message) return; + if (message._fetchProp) { + try { + const props = message._fetchProp.split('.'); + let value = this.client; + for (const prop of props) value = value[prop]; + this._respond('fetchProp', { _fetchProp: message._fetchProp, _result: value }); + } catch (err) { + this._respond('fetchProp', { _fetchProp: message._fetchProp, _error: makePlainError(err) }); + } + } else if (message._eval) { + try { + this._respond('eval', { _eval: message._eval, _result: await this.client._eval(message._eval) }); + } catch (err) { + this._respond('eval', { _eval: message._eval, _error: makePlainError(err) }); + } + } + } + + /** + * Sends a message to the master process, emitting an error from the client upon failure. + * @param {string} type Type of response to send + * @param {*} message Message to send + * @private + */ + _respond(type, message) { + this.send(message).catch(err => { + const error = new Error(`Error when sending ${type} response to master process: ${err.message}`); + error.stack = err.stack; + /** + * Emitted when the client encounters an error. + * <warn>Errors thrown within this event do not have a catch handler, it is + * recommended to not use async functions as `error` event handlers. See the + * [Node.js docs](https://nodejs.org/api/events.html#capture-rejections-of-promises) for details.</warn> + * @event Client#error + * @param {Error} error The error encountered + */ + this.client.emit(Events.Error, error); + }); + } + + /** + * Creates/gets the singleton of this class. + * @param {Client} client The client to use + * @param {ShardingManagerMode} mode Mode the shard was spawned with + * @returns {ShardClientUtil} + */ + static singleton(client, mode) { + if (!this._singleton) { + this._singleton = new this(client, mode); + } else { + client.emit( + Events.Warn, + 'Multiple clients created in child process/worker; only the first will handle sharding helpers.', + ); + } + return this._singleton; + } + + /** + * Get the shard id for a given guild id. + * @param {Snowflake} guildId Snowflake guild id to get shard id for + * @param {number} shardCount Number of shards + * @returns {number} + */ + static shardIdForGuildId(guildId, shardCount) { + const shard = calculateShardId(guildId, shardCount); + if (shard < 0) throw new DiscordjsError(ErrorCodes.ShardingShardMiscalculation, shard, guildId, shardCount); + return shard; + } + + /** + * Increments max listeners by one for a given emitter, if they are not zero. + * @param {EventEmitter|process} emitter The emitter that emits the events. + * @private + */ + incrementMaxListeners(emitter) { + const maxListeners = emitter.getMaxListeners(); + if (maxListeners !== 0) { + emitter.setMaxListeners(maxListeners + 1); + } + } + + /** + * Decrements max listeners by one for a given emitter, if they are not zero. + * @param {EventEmitter|process} emitter The emitter that emits the events. + * @private + */ + decrementMaxListeners(emitter) { + const maxListeners = emitter.getMaxListeners(); + if (maxListeners !== 0) { + emitter.setMaxListeners(maxListeners - 1); + } + } +} + +module.exports = ShardClientUtil; diff --git a/node_modules/discord.js/src/sharding/ShardingManager.js b/node_modules/discord.js/src/sharding/ShardingManager.js new file mode 100644 index 0000000..288456a --- /dev/null +++ b/node_modules/discord.js/src/sharding/ShardingManager.js @@ -0,0 +1,335 @@ +'use strict'; + +const EventEmitter = require('node:events'); +const fs = require('node:fs'); +const path = require('node:path'); +const process = require('node:process'); +const { setTimeout: sleep } = require('node:timers/promises'); +const { Collection } = require('@discordjs/collection'); +const Shard = require('./Shard'); +const { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } = require('../errors'); +const { mergeDefault, fetchRecommendedShardCount } = require('../util/Util'); + +/** + * This is a utility class that makes multi-process sharding of a bot an easy and painless experience. + * It works by spawning a self-contained {@link ChildProcess} or {@link Worker} for each individual shard, each + * containing its own instance of your bot's {@link Client}. They all have a line of communication with the master + * process, and there are several useful methods that utilise it in order to simplify tasks that are normally difficult + * with sharding. It can spawn a specific number of shards or the amount that Discord suggests for the bot, and takes a + * path to your main bot script to launch for each one. + * @extends {EventEmitter} + */ +class ShardingManager extends EventEmitter { + /** + * The mode to spawn shards with for a {@link ShardingManager}. Can be either one of: + * * 'process' to use child processes + * * 'worker' to use [Worker threads](https://nodejs.org/api/worker_threads.html) + * @typedef {string} ShardingManagerMode + */ + + /** + * The options to spawn shards with for a {@link ShardingManager}. + * @typedef {Object} ShardingManagerOptions + * @property {string|number} [totalShards='auto'] Number of total shards of all shard managers or "auto" + * @property {string|number[]} [shardList='auto'] List of shards to spawn or "auto" + * @property {ShardingManagerMode} [mode='process'] Which mode to use for shards + * @property {boolean} [respawn=true] Whether shards should automatically respawn upon exiting + * @property {boolean} [silent=false] Whether to pass the silent flag to child process + * (only available when mode is set to 'process') + * @property {string[]} [shardArgs=[]] Arguments to pass to the shard script when spawning + * (only available when mode is set to 'process') + * @property {string[]} [execArgv=[]] Arguments to pass to the shard script executable when spawning + * (only available when mode is set to 'process') + * @property {string} [token] Token to use for automatic shard count and passing to shards + */ + + /** + * @param {string} file Path to your shard script file + * @param {ShardingManagerOptions} [options] Options for the sharding manager + */ + constructor(file, options = {}) { + super(); + options = mergeDefault( + { + totalShards: 'auto', + mode: 'process', + respawn: true, + silent: false, + shardArgs: [], + execArgv: [], + token: process.env.DISCORD_TOKEN, + }, + options, + ); + + /** + * Path to the shard script file + * @type {string} + */ + this.file = file; + if (!file) throw new DiscordjsError(ErrorCodes.ClientInvalidOption, 'File', 'specified.'); + if (!path.isAbsolute(file)) this.file = path.resolve(process.cwd(), file); + const stats = fs.statSync(this.file); + if (!stats.isFile()) throw new DiscordjsError(ErrorCodes.ClientInvalidOption, 'File', 'a file'); + + /** + * List of shards this sharding manager spawns + * @type {string|number[]} + */ + this.shardList = options.shardList ?? 'auto'; + if (this.shardList !== 'auto') { + if (!Array.isArray(this.shardList)) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'shardList', 'an array.'); + } + this.shardList = [...new Set(this.shardList)]; + if (this.shardList.length < 1) { + throw new DiscordjsRangeError(ErrorCodes.ClientInvalidOption, 'shardList', 'at least 1 id.'); + } + if ( + this.shardList.some( + shardId => typeof shardId !== 'number' || isNaN(shardId) || !Number.isInteger(shardId) || shardId < 0, + ) + ) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'shardList', 'an array of positive integers.'); + } + } + + /** + * Amount of shards that all sharding managers spawn in total + * @type {number} + */ + this.totalShards = options.totalShards || 'auto'; + if (this.totalShards !== 'auto') { + if (typeof this.totalShards !== 'number' || isNaN(this.totalShards)) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'a number.'); + } + if (this.totalShards < 1) { + throw new DiscordjsRangeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'at least 1.'); + } + if (!Number.isInteger(this.totalShards)) { + throw new DiscordjsRangeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'an integer.'); + } + } + + /** + * Mode for shards to spawn with + * @type {ShardingManagerMode} + */ + this.mode = options.mode; + if (this.mode !== 'process' && this.mode !== 'worker') { + throw new DiscordjsRangeError(ErrorCodes.ClientInvalidOption, 'Sharding mode', '"process" or "worker"'); + } + + /** + * Whether shards should automatically respawn upon exiting + * @type {boolean} + */ + this.respawn = options.respawn; + + /** + * Whether to pass the silent flag to child process (only when {@link ShardingManager#mode} is `process`) + * @type {boolean} + */ + this.silent = options.silent; + + /** + * An array of arguments to pass to shards (only when {@link ShardingManager#mode} is `process`) + * @type {string[]} + */ + this.shardArgs = options.shardArgs; + + /** + * An array of arguments to pass to the executable (only when {@link ShardingManager#mode} is `process`) + * @type {string[]} + */ + this.execArgv = options.execArgv; + + /** + * Token to use for obtaining the automatic shard count, and passing to shards + * @type {?string} + */ + this.token = options.token?.replace(/^Bot\s*/i, '') ?? null; + + /** + * A collection of shards that this manager has spawned + * @type {Collection<number, Shard>} + */ + this.shards = new Collection(); + + process.env.SHARDING_MANAGER = true; + process.env.SHARDING_MANAGER_MODE = this.mode; + process.env.DISCORD_TOKEN = this.token; + } + + /** + * Creates a single shard. + * <warn>Using this method is usually not necessary if you use the spawn method.</warn> + * @param {number} [id=this.shards.size] Id of the shard to create + * <info>This is usually not necessary to manually specify.</info> + * @returns {Shard} Note that the created shard needs to be explicitly spawned using its spawn method. + */ + createShard(id = this.shards.size) { + const shard = new Shard(this, id); + this.shards.set(id, shard); + /** + * Emitted upon creating a shard. + * @event ShardingManager#shardCreate + * @param {Shard} shard Shard that was created + */ + this.emit('shardCreate', shard); + return shard; + } + + /** + * Options used to spawn multiple shards. + * @typedef {Object} MultipleShardSpawnOptions + * @property {number|string} [amount=this.totalShards] Number of shards to spawn + * @property {number} [delay=5500] How long to wait in between spawning each shard (in milliseconds) + * @property {number} [timeout=30000] The amount in milliseconds to wait until the {@link Client} has become ready + */ + + /** + * Spawns multiple shards. + * @param {MultipleShardSpawnOptions} [options] Options for spawning shards + * @returns {Promise<Collection<number, Shard>>} + */ + async spawn({ amount = this.totalShards, delay = 5500, timeout = 30_000 } = {}) { + // Obtain/verify the number of shards to spawn + if (amount === 'auto') { + amount = await fetchRecommendedShardCount(this.token); + } else { + if (typeof amount !== 'number' || isNaN(amount)) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'a number.'); + } + if (amount < 1) throw new DiscordjsRangeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'at least 1.'); + if (!Number.isInteger(amount)) { + throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'an integer.'); + } + } + + // Make sure this many shards haven't already been spawned + if (this.shards.size >= amount) throw new DiscordjsError(ErrorCodes.ShardingAlreadySpawned, this.shards.size); + if (this.shardList === 'auto' || this.totalShards === 'auto' || this.totalShards !== amount) { + this.shardList = [...Array(amount).keys()]; + } + if (this.totalShards === 'auto' || this.totalShards !== amount) { + this.totalShards = amount; + } + + if (this.shardList.some(shardId => shardId >= amount)) { + throw new DiscordjsRangeError( + ErrorCodes.ClientInvalidOption, + 'Amount of shards', + 'bigger than the highest shardId in the shardList option.', + ); + } + + // Spawn the shards + for (const shardId of this.shardList) { + const promises = []; + const shard = this.createShard(shardId); + promises.push(shard.spawn(timeout)); + if (delay > 0 && this.shards.size !== this.shardList.length) promises.push(sleep(delay)); + await Promise.all(promises); // eslint-disable-line no-await-in-loop + } + + return this.shards; + } + + /** + * Sends a message to all shards. + * @param {*} message Message to be sent to the shards + * @returns {Promise<Shard[]>} + */ + broadcast(message) { + const promises = []; + for (const shard of this.shards.values()) promises.push(shard.send(message)); + return Promise.all(promises); + } + + /** + * Options for {@link ShardingManager#broadcastEval} and {@link ShardClientUtil#broadcastEval}. + * @typedef {Object} BroadcastEvalOptions + * @property {number} [shard] Shard to run script on, all if undefined + * @property {*} [context] The JSON-serializable values to call the script with + */ + + /** + * Evaluates a script on all shards, or a given shard, in the context of the {@link Client}s. + * @param {Function} script JavaScript to run on each shard + * @param {BroadcastEvalOptions} [options={}] The options for the broadcast + * @returns {Promise<*|Array<*>>} Results of the script execution + */ + broadcastEval(script, options = {}) { + if (typeof script !== 'function') { + return Promise.reject(new DiscordjsTypeError(ErrorCodes.ShardingInvalidEvalBroadcast)); + } + return this._performOnShards('eval', [`(${script})(this, ${JSON.stringify(options.context)})`], options.shard); + } + + /** + * Fetches a client property value of each shard, or a given shard. + * @param {string} prop Name of the client property to get, using periods for nesting + * @param {number} [shard] Shard to fetch property from, all if undefined + * @returns {Promise<*|Array<*>>} + * @example + * manager.fetchClientValues('guilds.cache.size') + * .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`)) + * .catch(console.error); + */ + fetchClientValues(prop, shard) { + return this._performOnShards('fetchClientValue', [prop], shard); + } + + /** + * Runs a method with given arguments on all shards, or a given shard. + * @param {string} method Method name to run on each shard + * @param {Array<*>} args Arguments to pass through to the method call + * @param {number} [shard] Shard to run on, all if undefined + * @returns {Promise<*|Array<*>>} Results of the method execution + * @private + */ + _performOnShards(method, args, shard) { + if (this.shards.size === 0) return Promise.reject(new DiscordjsError(ErrorCodes.ShardingNoShards)); + + if (typeof shard === 'number') { + if (this.shards.has(shard)) return this.shards.get(shard)[method](...args); + return Promise.reject(new DiscordjsError(ErrorCodes.ShardingShardNotFound, shard)); + } + + if (this.shards.size !== this.shardList.length) { + return Promise.reject(new DiscordjsError(ErrorCodes.ShardingInProcess)); + } + + const promises = []; + for (const sh of this.shards.values()) promises.push(sh[method](...args)); + return Promise.all(promises); + } + + /** + * Options used to respawn all shards. + * @typedef {Object} MultipleShardRespawnOptions + * @property {number} [shardDelay=5000] How long to wait between shards (in milliseconds) + * @property {number} [respawnDelay=500] How long to wait between killing a shard's process and restarting it + * (in milliseconds) + * @property {number} [timeout=30000] The amount in milliseconds to wait for a shard to become ready before + * continuing to another (`-1` or `Infinity` for no wait) + */ + + /** + * Kills all running shards and respawns them. + * @param {MultipleShardRespawnOptions} [options] Options for respawning shards + * @returns {Promise<Collection<number, Shard>>} + */ + async respawnAll({ shardDelay = 5_000, respawnDelay = 500, timeout = 30_000 } = {}) { + let s = 0; + for (const shard of this.shards.values()) { + const promises = [shard.respawn({ delay: respawnDelay, timeout })]; + if (++s < this.shards.size && shardDelay > 0) promises.push(sleep(shardDelay)); + await Promise.all(promises); // eslint-disable-line no-await-in-loop + } + return this.shards; + } +} + +module.exports = ShardingManager; diff --git a/node_modules/discord.js/src/structures/ActionRow.js b/node_modules/discord.js/src/structures/ActionRow.js new file mode 100644 index 0000000..3f39691 --- /dev/null +++ b/node_modules/discord.js/src/structures/ActionRow.js @@ -0,0 +1,46 @@ +'use strict'; + +const { deprecate } = require('node:util'); +const { isJSONEncodable } = require('@discordjs/util'); +const Component = require('./Component'); +const { createComponent } = require('../util/Components'); + +/** + * Represents an action row + * @extends {Component} + */ +class ActionRow extends Component { + constructor({ components, ...data }) { + super(data); + + /** + * The components in this action row + * @type {Component[]} + * @readonly + */ + this.components = components.map(c => createComponent(c)); + } + + /** + * Creates a new action row builder from JSON data + * @method from + * @memberof ActionRow + * @param {ActionRowBuilder|ActionRow|APIActionRowComponent} other The other data + * @returns {ActionRowBuilder} + * @deprecated Use {@link ActionRowBuilder.from} instead. + */ + static from = deprecate( + other => new this(isJSONEncodable(other) ? other.toJSON() : other), + 'ActionRow.from() is deprecated. Use ActionRowBuilder.from() instead.', + ); + + /** + * Returns the API-compatible JSON for this component + * @returns {APIActionRowComponent} + */ + toJSON() { + return { ...this.data, components: this.components.map(c => c.toJSON()) }; + } +} + +module.exports = ActionRow; diff --git a/node_modules/discord.js/src/structures/ActionRowBuilder.js b/node_modules/discord.js/src/structures/ActionRowBuilder.js new file mode 100644 index 0000000..962a378 --- /dev/null +++ b/node_modules/discord.js/src/structures/ActionRowBuilder.js @@ -0,0 +1,35 @@ +'use strict'; + +const { ActionRowBuilder: BuildersActionRow } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { createComponentBuilder } = require('../util/Components'); +const { toSnakeCase } = require('../util/Transformers'); + +/** + * Represents an action row builder. + * @extends {BuildersActionRow} + */ +class ActionRowBuilder extends BuildersActionRow { + constructor({ components, ...data } = {}) { + super({ + ...toSnakeCase(data), + components: components?.map(c => createComponentBuilder(c)), + }); + } + + /** + * Creates a new action row builder from JSON data + * @param {ActionRow|ActionRowBuilder|APIActionRowComponent} other The other data + * @returns {ActionRowBuilder} + */ + static from(other) { + return new this(isJSONEncodable(other) ? other.toJSON() : other); + } +} + +module.exports = ActionRowBuilder; + +/** + * @external BuildersActionRow + * @see {@link https://discord.js.org/docs/packages/builders/stable/ActionRowBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/AnonymousGuild.js b/node_modules/discord.js/src/structures/AnonymousGuild.js new file mode 100644 index 0000000..70931bd --- /dev/null +++ b/node_modules/discord.js/src/structures/AnonymousGuild.js @@ -0,0 +1,97 @@ +'use strict'; + +const BaseGuild = require('./BaseGuild'); + +/** + * Bundles common attributes and methods between {@link Guild} and {@link InviteGuild} + * @extends {BaseGuild} + * @abstract + */ +class AnonymousGuild extends BaseGuild { + constructor(client, data, immediatePatch = true) { + super(client, data); + if (immediatePatch) this._patch(data); + } + + _patch(data) { + if ('features' in data) this.features = data.features; + + if ('splash' in data) { + /** + * The hash of the guild invite splash image + * @type {?string} + */ + this.splash = data.splash; + } + + if ('banner' in data) { + /** + * The hash of the guild banner + * @type {?string} + */ + this.banner = data.banner; + } + + if ('description' in data) { + /** + * The description of the guild, if any + * @type {?string} + */ + this.description = data.description; + } + + if ('verification_level' in data) { + /** + * The verification level of the guild + * @type {GuildVerificationLevel} + */ + this.verificationLevel = data.verification_level; + } + + if ('vanity_url_code' in data) { + /** + * The vanity invite code of the guild, if any + * @type {?string} + */ + this.vanityURLCode = data.vanity_url_code; + } + + if ('nsfw_level' in data) { + /** + * The NSFW level of this guild + * @type {GuildNSFWLevel} + */ + this.nsfwLevel = data.nsfw_level; + } + + if ('premium_subscription_count' in data) { + /** + * The total number of boosts for this server + * @type {?number} + */ + this.premiumSubscriptionCount = data.premium_subscription_count; + } else { + this.premiumSubscriptionCount ??= null; + } + } + + /** + * The URL to this guild's banner. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + bannerURL(options = {}) { + return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options); + } + + /** + * The URL to this guild's invite splash image. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + splashURL(options = {}) { + return this.splash && this.client.rest.cdn.splash(this.id, this.splash, options); + } +} + +module.exports = AnonymousGuild; diff --git a/node_modules/discord.js/src/structures/ApplicationCommand.js b/node_modules/discord.js/src/structures/ApplicationCommand.js new file mode 100644 index 0000000..bd87281 --- /dev/null +++ b/node_modules/discord.js/src/structures/ApplicationCommand.js @@ -0,0 +1,606 @@ +'use strict'; + +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { ApplicationCommandOptionType } = require('discord-api-types/v10'); +const isEqual = require('fast-deep-equal'); +const Base = require('./Base'); +const ApplicationCommandPermissionsManager = require('../managers/ApplicationCommandPermissionsManager'); +const PermissionsBitField = require('../util/PermissionsBitField'); + +/** + * Represents an application command. + * @extends {Base} + */ +class ApplicationCommand extends Base { + constructor(client, data, guild, guildId) { + super(client); + + /** + * The command's id + * @type {Snowflake} + */ + this.id = data.id; + + /** + * The parent application's id + * @type {Snowflake} + */ + this.applicationId = data.application_id; + + /** + * The guild this command is part of + * @type {?Guild} + */ + this.guild = guild ?? null; + + /** + * The guild's id this command is part of, this may be non-null when `guild` is `null` if the command + * was fetched from the `ApplicationCommandManager` + * @type {?Snowflake} + */ + this.guildId = guild?.id ?? guildId ?? null; + + /** + * The manager for permissions of this command on its guild or arbitrary guilds when the command is global + * @type {ApplicationCommandPermissionsManager} + */ + this.permissions = new ApplicationCommandPermissionsManager(this); + + /** + * The type of this application command + * @type {ApplicationCommandType} + */ + this.type = data.type; + + /** + * Whether this command is age-restricted (18+) + * @type {boolean} + */ + this.nsfw = data.nsfw ?? false; + + this._patch(data); + } + + _patch(data) { + if ('name' in data) { + /** + * The name of this command + * @type {string} + */ + this.name = data.name; + } + + if ('name_localizations' in data) { + /** + * The name localizations for this command + * @type {?Object<Locale, string>} + */ + this.nameLocalizations = data.name_localizations; + } else { + this.nameLocalizations ??= null; + } + + if ('name_localized' in data) { + /** + * The localized name for this command + * @type {?string} + */ + this.nameLocalized = data.name_localized; + } else { + this.nameLocalized ??= null; + } + + if ('description' in data) { + /** + * The description of this command + * @type {string} + */ + this.description = data.description; + } + + if ('description_localizations' in data) { + /** + * The description localizations for this command + * @type {?Object<Locale, string>} + */ + this.descriptionLocalizations = data.description_localizations; + } else { + this.descriptionLocalizations ??= null; + } + + if ('description_localized' in data) { + /** + * The localized description for this command + * @type {?string} + */ + this.descriptionLocalized = data.description_localized; + } else { + this.descriptionLocalized ??= null; + } + + if ('options' in data) { + /** + * The options of this command + * @type {ApplicationCommandOption[]} + */ + this.options = data.options.map(o => this.constructor.transformOption(o, true)); + } else { + this.options ??= []; + } + + if ('default_member_permissions' in data) { + /** + * The default bitfield used to determine whether this command be used in a guild + * @type {?Readonly<PermissionsBitField>} + */ + this.defaultMemberPermissions = data.default_member_permissions + ? new PermissionsBitField(BigInt(data.default_member_permissions)).freeze() + : null; + } else { + this.defaultMemberPermissions ??= null; + } + + if ('dm_permission' in data) { + /** + * Whether the command can be used in DMs + * <info>This property is always `null` on guild commands</info> + * @type {boolean|null} + */ + this.dmPermission = data.dm_permission; + } else { + this.dmPermission ??= null; + } + + if ('version' in data) { + /** + * Autoincrementing version identifier updated during substantial record changes + * @type {Snowflake} + */ + this.version = data.version; + } + } + + /** + * The timestamp the command was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the command was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The manager that this command belongs to + * @type {ApplicationCommandManager} + * @readonly + */ + get manager() { + return (this.guild ?? this.client.application).commands; + } + + /** + * Data for creating or editing an application command. + * @typedef {Object} ApplicationCommandData + * @property {string} name The name of the command, must be in all lowercase if type is + * {@link ApplicationCommandType.ChatInput} + * @property {Object<Locale, string>} [nameLocalizations] The localizations for the command name + * @property {string} description The description of the command, if type is {@link ApplicationCommandType.ChatInput} + * @property {boolean} [nsfw] Whether the command is age-restricted + * @property {Object<Locale, string>} [descriptionLocalizations] The localizations for the command description, + * if type is {@link ApplicationCommandType.ChatInput} + * @property {ApplicationCommandType} [type=ApplicationCommandType.ChatInput] The type of the command + * @property {ApplicationCommandOptionData[]} [options] Options for the command + * @property {?PermissionResolvable} [defaultMemberPermissions] The bitfield used to determine the default permissions + * a member needs in order to run the command + * @property {boolean} [dmPermission] Whether the command is enabled in DMs + */ + + /** + * An option for an application command or subcommand. + * <info>In addition to the listed properties, when used as a parameter, + * API style `snake_case` properties can be used for compatibility with generators like `@discordjs/builders`.</info> + * <warn>Note that providing a value for the `camelCase` counterpart for any `snake_case` property + * will discard the provided `snake_case` property.</warn> + * @typedef {Object} ApplicationCommandOptionData + * @property {ApplicationCommandOptionType} type The type of the option + * @property {string} name The name of the option + * @property {Object<Locale, string>} [nameLocalizations] The name localizations for the option + * @property {string} description The description of the option + * @property {Object<Locale, string>} [descriptionLocalizations] The description localizations for the option + * @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a + * {@link ApplicationCommandOptionType.String}, {@link ApplicationCommandOptionType.Integer} or + * {@link ApplicationCommandOptionType.Number} option + * @property {boolean} [required] Whether the option is required + * @property {ApplicationCommandOptionChoiceData[]} [choices] The choices of the option for the user to pick from + * @property {ApplicationCommandOptionData[]} [options] Additional options if this option is a subcommand (group) + * @property {ChannelType[]} [channelTypes] When the option type is channel, + * the allowed types of channels that can be selected + * @property {number} [minValue] The minimum value for an {@link ApplicationCommandOptionType.Integer} or + * {@link ApplicationCommandOptionType.Number} option + * @property {number} [maxValue] The maximum value for an {@link ApplicationCommandOptionType.Integer} or + * {@link ApplicationCommandOptionType.Number} option + * @property {number} [minLength] The minimum length for an {@link ApplicationCommandOptionType.String} option + * (maximum of `6000`) + * @property {number} [maxLength] The maximum length for an {@link ApplicationCommandOptionType.String} option + * (maximum of `6000`) + */ + + /** + * @typedef {Object} ApplicationCommandOptionChoiceData + * @property {string} name The name of the choice + * @property {Object<Locale, string>} [nameLocalizations] The localized names for this choice + * @property {string|number} value The value of the choice + */ + + /** + * Edits this application command. + * @param {Partial<ApplicationCommandData>} data The data to update the command with + * @returns {Promise<ApplicationCommand>} + * @example + * // Edit the description of this command + * command.edit({ + * description: 'New description', + * }) + * .then(console.log) + * .catch(console.error); + */ + edit(data) { + return this.manager.edit(this, data, this.guildId); + } + + /** + * Edits the name of this ApplicationCommand + * @param {string} name The new name of the command + * @returns {Promise<ApplicationCommand>} + */ + setName(name) { + return this.edit({ name }); + } + + /** + * Edits the localized names of this ApplicationCommand + * @param {Object<Locale, string>} nameLocalizations The new localized names for the command + * @returns {Promise<ApplicationCommand>} + * @example + * // Edit the name localizations of this command + * command.setLocalizedNames({ + * 'en-GB': 'test', + * 'pt-BR': 'teste', + * }) + * .then(console.log) + * .catch(console.error) + */ + setNameLocalizations(nameLocalizations) { + return this.edit({ nameLocalizations }); + } + + /** + * Edits the description of this ApplicationCommand + * @param {string} description The new description of the command + * @returns {Promise<ApplicationCommand>} + */ + setDescription(description) { + return this.edit({ description }); + } + + /** + * Edits the localized descriptions of this ApplicationCommand + * @param {Object<Locale, string>} descriptionLocalizations The new localized descriptions for the command + * @returns {Promise<ApplicationCommand>} + * @example + * // Edit the description localizations of this command + * command.setDescriptionLocalizations({ + * 'en-GB': 'A test command', + * 'pt-BR': 'Um comando de teste', + * }) + * .then(console.log) + * .catch(console.error) + */ + setDescriptionLocalizations(descriptionLocalizations) { + return this.edit({ descriptionLocalizations }); + } + + /** + * Edits the default member permissions of this ApplicationCommand + * @param {?PermissionResolvable} defaultMemberPermissions The default member permissions required to run this command + * @returns {Promise<ApplicationCommand>} + */ + setDefaultMemberPermissions(defaultMemberPermissions) { + return this.edit({ defaultMemberPermissions }); + } + + /** + * Edits the DM permission of this ApplicationCommand + * @param {boolean} [dmPermission=true] Whether the command can be used in DMs + * @returns {Promise<ApplicationCommand>} + */ + setDMPermission(dmPermission = true) { + return this.edit({ dmPermission }); + } + + /** + * Edits the options of this ApplicationCommand + * @param {ApplicationCommandOptionData[]} options The options to set for this command + * @returns {Promise<ApplicationCommand>} + */ + setOptions(options) { + return this.edit({ options }); + } + + /** + * Deletes this command. + * @returns {Promise<ApplicationCommand>} + * @example + * // Delete this command + * command.delete() + * .then(console.log) + * .catch(console.error); + */ + delete() { + return this.manager.delete(this, this.guildId); + } + + /** + * Whether this command equals another command. It compares all properties, so for most operations + * it is advisable to just compare `command.id === command2.id` as it is much faster and is often + * what most users need. + * @param {ApplicationCommand|ApplicationCommandData|APIApplicationCommand} command The command to compare with + * @param {boolean} [enforceOptionOrder=false] Whether to strictly check that options and choices are in the same + * order in the array <info>The client may not always respect this ordering!</info> + * @returns {boolean} + */ + equals(command, enforceOptionOrder = false) { + // If given an id, check if the id matches + if (command.id && this.id !== command.id) return false; + + let defaultMemberPermissions = null; + let dmPermission = command.dmPermission ?? command.dm_permission; + + if ('default_member_permissions' in command) { + defaultMemberPermissions = command.default_member_permissions + ? new PermissionsBitField(BigInt(command.default_member_permissions)).bitfield + : null; + } + + if ('defaultMemberPermissions' in command) { + defaultMemberPermissions = + command.defaultMemberPermissions !== null + ? new PermissionsBitField(command.defaultMemberPermissions).bitfield + : null; + } + + // Check top level parameters + if ( + command.name !== this.name || + ('description' in command && command.description !== this.description) || + ('version' in command && command.version !== this.version) || + (command.type && command.type !== this.type) || + ('nsfw' in command && command.nsfw !== this.nsfw) || + // Future proof for options being nullable + // TODO: remove ?? 0 on each when nullable + (command.options?.length ?? 0) !== (this.options?.length ?? 0) || + defaultMemberPermissions !== (this.defaultMemberPermissions?.bitfield ?? null) || + (dmPermission !== undefined && dmPermission !== this.dmPermission) || + !isEqual(command.nameLocalizations ?? command.name_localizations ?? {}, this.nameLocalizations ?? {}) || + !isEqual( + command.descriptionLocalizations ?? command.description_localizations ?? {}, + this.descriptionLocalizations ?? {}, + ) + ) { + return false; + } + + if (command.options) { + return this.constructor.optionsEqual(this.options, command.options, enforceOptionOrder); + } + return true; + } + + /** + * Recursively checks that all options for an {@link ApplicationCommand} are equal to the provided options. + * In most cases it is better to compare using {@link ApplicationCommand#equals} + * @param {ApplicationCommandOptionData[]} existing The options on the existing command, + * should be {@link ApplicationCommand#options} + * @param {ApplicationCommandOptionData[]|APIApplicationCommandOption[]} options The options to compare against + * @param {boolean} [enforceOptionOrder=false] Whether to strictly check that options and choices are in the same + * order in the array <info>The client may not always respect this ordering!</info> + * @returns {boolean} + */ + static optionsEqual(existing, options, enforceOptionOrder = false) { + if (existing.length !== options.length) return false; + if (enforceOptionOrder) { + return existing.every((option, index) => this._optionEquals(option, options[index], enforceOptionOrder)); + } + const newOptions = new Map(options.map(option => [option.name, option])); + for (const option of existing) { + const foundOption = newOptions.get(option.name); + if (!foundOption || !this._optionEquals(option, foundOption)) return false; + } + return true; + } + + /** + * Checks that an option for an {@link ApplicationCommand} is equal to the provided option + * In most cases it is better to compare using {@link ApplicationCommand#equals} + * @param {ApplicationCommandOptionData} existing The option on the existing command, + * should be from {@link ApplicationCommand#options} + * @param {ApplicationCommandOptionData|APIApplicationCommandOption} option The option to compare against + * @param {boolean} [enforceOptionOrder=false] Whether to strictly check that options or choices are in the same + * order in their array <info>The client may not always respect this ordering!</info> + * @returns {boolean} + * @private + */ + static _optionEquals(existing, option, enforceOptionOrder = false) { + if ( + option.name !== existing.name || + option.type !== existing.type || + option.description !== existing.description || + option.autocomplete !== existing.autocomplete || + (option.required ?? + ([ApplicationCommandOptionType.Subcommand, ApplicationCommandOptionType.SubcommandGroup].includes(option.type) + ? undefined + : false)) !== existing.required || + option.choices?.length !== existing.choices?.length || + option.options?.length !== existing.options?.length || + (option.channelTypes ?? option.channel_types)?.length !== existing.channelTypes?.length || + (option.minValue ?? option.min_value) !== existing.minValue || + (option.maxValue ?? option.max_value) !== existing.maxValue || + (option.minLength ?? option.min_length) !== existing.minLength || + (option.maxLength ?? option.max_length) !== existing.maxLength || + !isEqual(option.nameLocalizations ?? option.name_localizations ?? {}, existing.nameLocalizations ?? {}) || + !isEqual( + option.descriptionLocalizations ?? option.description_localizations ?? {}, + existing.descriptionLocalizations ?? {}, + ) + ) { + return false; + } + + if (existing.choices) { + if ( + enforceOptionOrder && + !existing.choices.every( + (choice, index) => + choice.name === option.choices[index].name && + choice.value === option.choices[index].value && + isEqual( + choice.nameLocalizations ?? {}, + option.choices[index].nameLocalizations ?? option.choices[index].name_localizations ?? {}, + ), + ) + ) { + return false; + } + if (!enforceOptionOrder) { + const newChoices = new Map(option.choices.map(choice => [choice.name, choice])); + for (const choice of existing.choices) { + const foundChoice = newChoices.get(choice.name); + if (!foundChoice || foundChoice.value !== choice.value) return false; + } + } + } + + if (existing.channelTypes) { + const newTypes = option.channelTypes ?? option.channel_types; + for (const type of existing.channelTypes) { + if (!newTypes.includes(type)) return false; + } + } + + if (existing.options) { + return this.optionsEqual(existing.options, option.options, enforceOptionOrder); + } + return true; + } + + /** + * An option for an application command or subcommand. + * @typedef {Object} ApplicationCommandOption + * @property {ApplicationCommandOptionType} type The type of the option + * @property {string} name The name of the option + * @property {Object<Locale, string>} [nameLocalizations] The localizations for the option name + * @property {string} [nameLocalized] The localized name for this option + * @property {string} description The description of the option + * @property {Object<Locale, string>} [descriptionLocalizations] The localizations for the option description + * @property {string} [descriptionLocalized] The localized description for this option + * @property {boolean} [required] Whether the option is required + * @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a + * {@link ApplicationCommandOptionType.String}, {@link ApplicationCommandOptionType.Integer} or + * {@link ApplicationCommandOptionType.Number} option + * @property {ApplicationCommandOptionChoice[]} [choices] The choices of the option for the user to pick from + * @property {ApplicationCommandOption[]} [options] Additional options if this option is a subcommand (group) + * @property {ApplicationCommandOptionAllowedChannelTypes[]} [channelTypes] When the option type is channel, + * the allowed types of channels that can be selected + * @property {number} [minValue] The minimum value for an {@link ApplicationCommandOptionType.Integer} or + * {@link ApplicationCommandOptionType.Number} option + * @property {number} [maxValue] The maximum value for an {@link ApplicationCommandOptionType.Integer} or + * {@link ApplicationCommandOptionType.Number} option + * @property {number} [minLength] The minimum length for an {@link ApplicationCommandOptionType.String} option + * (maximum of `6000`) + * @property {number} [maxLength] The maximum length for an {@link ApplicationCommandOptionType.String} option + * (maximum of `6000`) + */ + + /** + * A choice for an application command option. + * @typedef {Object} ApplicationCommandOptionChoice + * @property {string} name The name of the choice + * @property {?string} nameLocalized The localized name of the choice in the provided locale, if any + * @property {?Object<string, string>} [nameLocalizations] The localized names for this choice + * @property {string|number} value The value of the choice + */ + + /** + * Transforms an {@link ApplicationCommandOptionData} object into something that can be used with the API. + * @param {ApplicationCommandOptionData|ApplicationCommandOption} option The option to transform + * @param {boolean} [received] Whether this option has been received from Discord + * @returns {APIApplicationCommandOption} + * @private + */ + static transformOption(option, received) { + const channelTypesKey = received ? 'channelTypes' : 'channel_types'; + const minValueKey = received ? 'minValue' : 'min_value'; + const maxValueKey = received ? 'maxValue' : 'max_value'; + const minLengthKey = received ? 'minLength' : 'min_length'; + const maxLengthKey = received ? 'maxLength' : 'max_length'; + const nameLocalizationsKey = received ? 'nameLocalizations' : 'name_localizations'; + const nameLocalizedKey = received ? 'nameLocalized' : 'name_localized'; + const descriptionLocalizationsKey = received ? 'descriptionLocalizations' : 'description_localizations'; + const descriptionLocalizedKey = received ? 'descriptionLocalized' : 'description_localized'; + return { + type: option.type, + name: option.name, + [nameLocalizationsKey]: option.nameLocalizations ?? option.name_localizations, + [nameLocalizedKey]: option.nameLocalized ?? option.name_localized, + description: option.description, + [descriptionLocalizationsKey]: option.descriptionLocalizations ?? option.description_localizations, + [descriptionLocalizedKey]: option.descriptionLocalized ?? option.description_localized, + required: + option.required ?? + (option.type === ApplicationCommandOptionType.Subcommand || + option.type === ApplicationCommandOptionType.SubcommandGroup + ? undefined + : false), + autocomplete: option.autocomplete, + choices: option.choices?.map(choice => ({ + name: choice.name, + [nameLocalizedKey]: choice.nameLocalized ?? choice.name_localized, + [nameLocalizationsKey]: choice.nameLocalizations ?? choice.name_localizations, + value: choice.value, + })), + options: option.options?.map(o => this.transformOption(o, received)), + [channelTypesKey]: option.channelTypes ?? option.channel_types, + [minValueKey]: option.minValue ?? option.min_value, + [maxValueKey]: option.maxValue ?? option.max_value, + [minLengthKey]: option.minLength ?? option.min_length, + [maxLengthKey]: option.maxLength ?? option.max_length, + }; + } +} + +module.exports = ApplicationCommand; + +/* eslint-disable max-len */ +/** + * @external APIApplicationCommand + * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-structure} + */ + +/** + * @external APIApplicationCommandOption + * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure} + */ + +/** + * @external ApplicationCommandOptionAllowedChannelTypes + * @see {@link https://discord.js.org/docs/packages/builders/stable/ApplicationCommandOptionAllowedChannelTypes:TypeAlias} + */ diff --git a/node_modules/discord.js/src/structures/ApplicationRoleConnectionMetadata.js b/node_modules/discord.js/src/structures/ApplicationRoleConnectionMetadata.js new file mode 100644 index 0000000..7ed9b33 --- /dev/null +++ b/node_modules/discord.js/src/structures/ApplicationRoleConnectionMetadata.js @@ -0,0 +1,46 @@ +'use strict'; + +/** + * Role connection metadata object for an application. + */ +class ApplicationRoleConnectionMetadata { + constructor(data) { + /** + * The name of this metadata field + * @type {string} + */ + this.name = data.name; + + /** + * The name localizations for this metadata field + * @type {?Object<Locale, string>} + */ + this.nameLocalizations = data.name_localizations ?? null; + + /** + * The description of this metadata field + * @type {string} + */ + this.description = data.description; + + /** + * The description localizations for this metadata field + * @type {?Object<Locale, string>} + */ + this.descriptionLocalizations = data.description_localizations ?? null; + + /** + * The dictionary key for this metadata field + * @type {string} + */ + this.key = data.key; + + /** + * The type of this metadata field + * @type {ApplicationRoleConnectionMetadataType} + */ + this.type = data.type; + } +} + +exports.ApplicationRoleConnectionMetadata = ApplicationRoleConnectionMetadata; diff --git a/node_modules/discord.js/src/structures/Attachment.js b/node_modules/discord.js/src/structures/Attachment.js new file mode 100644 index 0000000..2576ff5 --- /dev/null +++ b/node_modules/discord.js/src/structures/Attachment.js @@ -0,0 +1,151 @@ +'use strict'; + +const AttachmentFlagsBitField = require('../util/AttachmentFlagsBitField.js'); +const { basename, flatten } = require('../util/Util'); + +/** + * @typedef {Object} AttachmentPayload + * @property {?string} name The name of the attachment + * @property {Stream|BufferResolvable} attachment The attachment in this payload + * @property {?string} description The description of the attachment + */ + +/** + * Represents an attachment + */ +class Attachment { + constructor(data) { + this.attachment = data.url; + /** + * The name of this attachment + * @type {string} + */ + this.name = data.filename; + this._patch(data); + } + + _patch(data) { + /** + * The attachment's id + * @type {Snowflake} + */ + this.id = data.id; + + if ('size' in data) { + /** + * The size of this attachment in bytes + * @type {number} + */ + this.size = data.size; + } + + if ('url' in data) { + /** + * The URL to this attachment + * @type {string} + */ + this.url = data.url; + } + + if ('proxy_url' in data) { + /** + * The Proxy URL to this attachment + * @type {string} + */ + this.proxyURL = data.proxy_url; + } + + if ('height' in data) { + /** + * The height of this attachment (if an image or video) + * @type {?number} + */ + this.height = data.height; + } else { + this.height ??= null; + } + + if ('width' in data) { + /** + * The width of this attachment (if an image or video) + * @type {?number} + */ + this.width = data.width; + } else { + this.width ??= null; + } + + if ('content_type' in data) { + /** + * The media type of this attachment + * @type {?string} + */ + this.contentType = data.content_type; + } else { + this.contentType ??= null; + } + + if ('description' in data) { + /** + * The description (alt text) of this attachment + * @type {?string} + */ + this.description = data.description; + } else { + this.description ??= null; + } + + /** + * Whether this attachment is ephemeral + * @type {boolean} + */ + this.ephemeral = data.ephemeral ?? false; + + if ('duration_secs' in data) { + /** + * The duration of this attachment in seconds + * <info>This will only be available if the attachment is an audio file.</info> + * @type {?number} + */ + this.duration = data.duration_secs; + } else { + this.duration ??= null; + } + + if ('waveform' in data) { + /** + * The base64 encoded byte array representing a sampled waveform + * <info>This will only be available if the attachment is an audio file.</info> + * @type {?string} + */ + this.waveform = data.waveform; + } else { + this.waveform ??= null; + } + + if ('flags' in data) { + /** + * The flags of this attachment + * @type {Readonly<AttachmentFlagsBitField>} + */ + this.flags = new AttachmentFlagsBitField(data.flags).freeze(); + } else { + this.flags ??= new AttachmentFlagsBitField().freeze(); + } + } + + /** + * Whether or not this attachment has been marked as a spoiler + * @type {boolean} + * @readonly + */ + get spoiler() { + return basename(this.url ?? this.name).startsWith('SPOILER_'); + } + + toJSON() { + return flatten(this); + } +} + +module.exports = Attachment; diff --git a/node_modules/discord.js/src/structures/AttachmentBuilder.js b/node_modules/discord.js/src/structures/AttachmentBuilder.js new file mode 100644 index 0000000..6c63810 --- /dev/null +++ b/node_modules/discord.js/src/structures/AttachmentBuilder.js @@ -0,0 +1,116 @@ +'use strict'; + +const { basename, flatten } = require('../util/Util'); + +/** + * Represents an attachment builder + */ +class AttachmentBuilder { + /** + * @param {BufferResolvable|Stream} attachment The file + * @param {AttachmentData} [data] Extra data + */ + constructor(attachment, data = {}) { + /** + * The file associated with this attachment. + * @type {BufferResolvable|Stream} + */ + this.attachment = attachment; + /** + * The name of this attachment + * @type {?string} + */ + this.name = data.name; + /** + * The description of the attachment + * @type {?string} + */ + this.description = data.description; + } + + /** + * Sets the description of this attachment. + * @param {string} description The description of the file + * @returns {AttachmentBuilder} This attachment + */ + setDescription(description) { + this.description = description; + return this; + } + + /** + * Sets the file of this attachment. + * @param {BufferResolvable|Stream} attachment The file + * @returns {AttachmentBuilder} This attachment + */ + setFile(attachment) { + this.attachment = attachment; + return this; + } + + /** + * Sets the name of this attachment. + * @param {string} name The name of the file + * @returns {AttachmentBuilder} This attachment + */ + setName(name) { + this.name = name; + return this; + } + + /** + * Sets whether this attachment is a spoiler + * @param {boolean} [spoiler=true] Whether the attachment should be marked as a spoiler + * @returns {AttachmentBuilder} This attachment + */ + setSpoiler(spoiler = true) { + if (spoiler === this.spoiler) return this; + + if (!spoiler) { + while (this.spoiler) { + this.name = this.name.slice('SPOILER_'.length); + } + return this; + } + this.name = `SPOILER_${this.name}`; + return this; + } + + /** + * Whether or not this attachment has been marked as a spoiler + * @type {boolean} + * @readonly + */ + get spoiler() { + return basename(this.name).startsWith('SPOILER_'); + } + + toJSON() { + return flatten(this); + } + + /** + * Makes a new builder instance from a preexisting attachment structure. + * @param {AttachmentBuilder|Attachment|AttachmentPayload} other The builder to construct a new instance from + * @returns {AttachmentBuilder} + */ + static from(other) { + return new AttachmentBuilder(other.attachment, { + name: other.name, + description: other.description, + }); + } +} + +module.exports = AttachmentBuilder; + +/** + * @external APIAttachment + * @see {@link https://discord.com/developers/docs/resources/channel#attachment-object} + */ + +/** + * @typedef {Object} AttachmentData + * @property {string} [name] The name of the attachment + * @property {string} [description] The description of the attachment + */ diff --git a/node_modules/discord.js/src/structures/AutoModerationActionExecution.js b/node_modules/discord.js/src/structures/AutoModerationActionExecution.js new file mode 100644 index 0000000..fcbc617 --- /dev/null +++ b/node_modules/discord.js/src/structures/AutoModerationActionExecution.js @@ -0,0 +1,116 @@ +'use strict'; + +const { _transformAPIAutoModerationAction } = require('../util/Transformers'); + +/** + * Represents the structure of an executed action when an {@link AutoModerationRule} is triggered. + */ +class AutoModerationActionExecution { + constructor(data, guild) { + /** + * The guild where this action was executed from. + * @type {Guild} + */ + this.guild = guild; + + /** + * The action that was executed. + * @type {AutoModerationAction} + */ + this.action = _transformAPIAutoModerationAction(data.action); + + /** + * The id of the auto moderation rule this action belongs to. + * @type {Snowflake} + */ + this.ruleId = data.rule_id; + + /** + * The trigger type of the auto moderation rule which was triggered. + * @type {AutoModerationRuleTriggerType} + */ + this.ruleTriggerType = data.rule_trigger_type; + + /** + * The id of the user that triggered this action. + * @type {Snowflake} + */ + this.userId = data.user_id; + + /** + * The id of the channel where this action was triggered from. + * @type {?Snowflake} + */ + this.channelId = data.channel_id ?? null; + + /** + * The id of the message that triggered this action. + * <info>This will not be present if the message was blocked or the content was not part of any message.</info> + * @type {?Snowflake} + */ + this.messageId = data.message_id ?? null; + + /** + * The id of any system auto moderation messages posted as a result of this action. + * @type {?Snowflake} + */ + this.alertSystemMessageId = data.alert_system_message_id ?? null; + + /** + * The content that triggered this action. + * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged gateway intent.</info> + * @type {string} + */ + this.content = data.content; + + /** + * The word or phrase configured in the rule that triggered this action. + * @type {?string} + */ + this.matchedKeyword = data.matched_keyword ?? null; + + /** + * The substring in content that triggered this action. + * @type {?string} + */ + this.matchedContent = data.matched_content ?? null; + } + + /** + * The auto moderation rule this action belongs to. + * @type {?AutoModerationRule} + * @readonly + */ + get autoModerationRule() { + return this.guild.autoModerationRules.cache.get(this.ruleId) ?? null; + } + + /** + * The channel where this action was triggered from. + * @type {?(GuildTextBasedChannel|ForumChannel)} + * @readonly + */ + get channel() { + return this.guild.channels.cache.get(this.channelId) ?? null; + } + + /** + * The user that triggered this action. + * @type {?User} + * @readonly + */ + get user() { + return this.guild.client.users.cache.get(this.userId) ?? null; + } + + /** + * The guild member that triggered this action. + * @type {?GuildMember} + * @readonly + */ + get member() { + return this.guild.members.cache.get(this.userId) ?? null; + } +} + +module.exports = AutoModerationActionExecution; diff --git a/node_modules/discord.js/src/structures/AutoModerationRule.js b/node_modules/discord.js/src/structures/AutoModerationRule.js new file mode 100644 index 0000000..e87f547 --- /dev/null +++ b/node_modules/discord.js/src/structures/AutoModerationRule.js @@ -0,0 +1,284 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Base = require('./Base'); +const { _transformAPIAutoModerationAction } = require('../util/Transformers'); + +/** + * Represents an auto moderation rule. + * @extends {Base} + */ +class AutoModerationRule extends Base { + constructor(client, data, guild) { + super(client); + + /** + * The id of this auto moderation rule. + * @type {Snowflake} + */ + this.id = data.id; + + /** + * The guild this auto moderation rule is for. + * @type {Guild} + */ + this.guild = guild; + + /** + * The user that created this auto moderation rule. + * @type {Snowflake} + */ + this.creatorId = data.creator_id; + + /** + * The trigger type of this auto moderation rule. + * @type {AutoModerationRuleTriggerType} + */ + this.triggerType = data.trigger_type; + + this._patch(data); + } + + _patch(data) { + if ('name' in data) { + /** + * The name of this auto moderation rule. + * @type {string} + */ + this.name = data.name; + } + + if ('event_type' in data) { + /** + * The event type of this auto moderation rule. + * @type {AutoModerationRuleEventType} + */ + this.eventType = data.event_type; + } + + if ('trigger_metadata' in data) { + /** + * Additional data used to determine whether an auto moderation rule should be triggered. + * @typedef {Object} AutoModerationTriggerMetadata + * @property {string[]} keywordFilter The substrings that will be searched for in the content + * @property {string[]} regexPatterns The regular expression patterns which will be matched against the content + * <info>Only Rust-flavored regular expressions are supported.</info> + * @property {AutoModerationRuleKeywordPresetType[]} presets + * The internally pre-defined wordsets which will be searched for in the content + * @property {string[]} allowList The substrings that will be exempt from triggering + * {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.KeywordPreset} + * @property {?number} mentionTotalLimit The total number of role & user mentions allowed per message + * @property {boolean} mentionRaidProtectionEnabled Whether mention raid protection is enabled + */ + + /** + * The trigger metadata of the rule. + * @type {AutoModerationTriggerMetadata} + */ + this.triggerMetadata = { + keywordFilter: data.trigger_metadata.keyword_filter ?? [], + regexPatterns: data.trigger_metadata.regex_patterns ?? [], + presets: data.trigger_metadata.presets ?? [], + allowList: data.trigger_metadata.allow_list ?? [], + mentionTotalLimit: data.trigger_metadata.mention_total_limit ?? null, + mentionRaidProtectionEnabled: data.trigger_metadata.mention_raid_protection_enabled ?? false, + }; + } + + if ('actions' in data) { + /** + * An object containing information about an auto moderation rule action. + * @typedef {Object} AutoModerationAction + * @property {AutoModerationActionType} type The type of this auto moderation rule action + * @property {AutoModerationActionMetadata} metadata Additional metadata needed during execution + */ + + /** + * Additional data used when an auto moderation rule is executed. + * @typedef {Object} AutoModerationActionMetadata + * @property {?Snowflake} channelId The id of the channel to which content will be logged + * @property {?number} durationSeconds The timeout duration in seconds + * @property {?string} customMessage The custom message that is shown whenever a message is blocked + */ + + /** + * The actions of this auto moderation rule. + * @type {AutoModerationAction[]} + */ + this.actions = data.actions.map(action => _transformAPIAutoModerationAction(action)); + } + + if ('enabled' in data) { + /** + * Whether this auto moderation rule is enabled. + * @type {boolean} + */ + this.enabled = data.enabled; + } + + if ('exempt_roles' in data) { + /** + * The roles exempt by this auto moderation rule. + * @type {Collection<Snowflake, Role>} + */ + this.exemptRoles = new Collection( + data.exempt_roles.map(exemptRole => [exemptRole, this.guild.roles.cache.get(exemptRole)]), + ); + } + + if ('exempt_channels' in data) { + /** + * The channels exempt by this auto moderation rule. + * @type {Collection<Snowflake, GuildChannel|ThreadChannel>} + */ + this.exemptChannels = new Collection( + data.exempt_channels.map(exemptChannel => [exemptChannel, this.guild.channels.cache.get(exemptChannel)]), + ); + } + } + + /** + * Edits this auto moderation rule. + * @param {AutoModerationRuleEditOptions} options Options for editing this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + edit(options) { + return this.guild.autoModerationRules.edit(this.id, options); + } + + /** + * Deletes this auto moderation rule. + * @param {string} [reason] The reason for deleting this auto moderation rule + * @returns {Promise<void>} + */ + delete(reason) { + return this.guild.autoModerationRules.delete(this.id, reason); + } + + /** + * Sets the name for this auto moderation rule. + * @param {string} name The name of this auto moderation rule + * @param {string} [reason] The reason for changing the name of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setName(name, reason) { + return this.edit({ name, reason }); + } + + /** + * Sets the event type for this auto moderation rule. + * @param {AutoModerationRuleEventType} eventType The event type of this auto moderation rule + * @param {string} [reason] The reason for changing the event type of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setEventType(eventType, reason) { + return this.edit({ eventType, reason }); + } + + /** + * Sets the keyword filter for this auto moderation rule. + * @param {string[]} keywordFilter The keyword filter of this auto moderation rule + * @param {string} [reason] The reason for changing the keyword filter of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setKeywordFilter(keywordFilter, reason) { + return this.edit({ triggerMetadata: { ...this.triggerMetadata, keywordFilter }, reason }); + } + + /** + * Sets the regular expression patterns for this auto moderation rule. + * @param {string[]} regexPatterns The regular expression patterns of this auto moderation rule + * <info>Only Rust-flavored regular expressions are supported.</info> + * @param {string} [reason] The reason for changing the regular expression patterns of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setRegexPatterns(regexPatterns, reason) { + return this.edit({ triggerMetadata: { ...this.triggerMetadata, regexPatterns }, reason }); + } + + /** + * Sets the presets for this auto moderation rule. + * @param {AutoModerationRuleKeywordPresetType[]} presets The presets of this auto moderation rule + * @param {string} [reason] The reason for changing the presets of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setPresets(presets, reason) { + return this.edit({ triggerMetadata: { ...this.triggerMetadata, presets }, reason }); + } + + /** + * Sets the allow list for this auto moderation rule. + * @param {string[]} allowList The substrings that will be exempt from triggering + * {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.KeywordPreset} + * @param {string} [reason] The reason for changing the allow list of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setAllowList(allowList, reason) { + return this.edit({ triggerMetadata: { ...this.triggerMetadata, allowList }, reason }); + } + + /** + * Sets the mention total limit for this auto moderation rule. + * @param {number} mentionTotalLimit The total number of unique role and user mentions allowed per message + * @param {string} [reason] The reason for changing the mention total limit of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setMentionTotalLimit(mentionTotalLimit, reason) { + return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionTotalLimit }, reason }); + } + + /** + * Sets whether to enable mention raid protection for this auto moderation rule. + * @param {boolean} mentionRaidProtectionEnabled + * Whether to enable mention raid protection for this auto moderation rule + * @param {string} [reason] The reason for changing the mention raid protection of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setMentionRaidProtectionEnabled(mentionRaidProtectionEnabled, reason) { + return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionRaidProtectionEnabled }, reason }); + } + + /** + * Sets the actions for this auto moderation rule. + * @param {AutoModerationActionOptions[]} actions The actions of this auto moderation rule + * @param {string} [reason] The reason for changing the actions of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setActions(actions, reason) { + return this.edit({ actions, reason }); + } + + /** + * Sets whether this auto moderation rule should be enabled. + * @param {boolean} [enabled=true] Whether to enable this auto moderation rule + * @param {string} [reason] The reason for enabling or disabling this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setEnabled(enabled = true, reason) { + return this.edit({ enabled, reason }); + } + + /** + * Sets the exempt roles for this auto moderation rule. + * @param {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles] + * The roles that should not be affected by the auto moderation rule + * @param {string} [reason] The reason for changing the exempt roles of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setExemptRoles(exemptRoles, reason) { + return this.edit({ exemptRoles, reason }); + } + + /** + * Sets the exempt channels for this auto moderation rule. + * @param {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels] + * The channels that should not be affected by the auto moderation rule + * @param {string} [reason] The reason for changing the exempt channels of this auto moderation rule + * @returns {Promise<AutoModerationRule>} + */ + setExemptChannels(exemptChannels, reason) { + return this.edit({ exemptChannels, reason }); + } +} + +module.exports = AutoModerationRule; diff --git a/node_modules/discord.js/src/structures/AutocompleteInteraction.js b/node_modules/discord.js/src/structures/AutocompleteInteraction.js new file mode 100644 index 0000000..4b7e39e --- /dev/null +++ b/node_modules/discord.js/src/structures/AutocompleteInteraction.js @@ -0,0 +1,102 @@ +'use strict'; + +const { InteractionResponseType, Routes } = require('discord-api-types/v10'); +const BaseInteraction = require('./BaseInteraction'); +const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver'); +const { DiscordjsError, ErrorCodes } = require('../errors'); + +/** + * Represents an autocomplete interaction. + * @extends {BaseInteraction} + */ +class AutocompleteInteraction extends BaseInteraction { + constructor(client, data) { + super(client, data); + + /** + * The id of the channel this interaction was sent in + * @type {Snowflake} + * @name AutocompleteInteraction#channelId + */ + + /** + * The invoked application command's id + * @type {Snowflake} + */ + this.commandId = data.data.id; + + /** + * The invoked application command's name + * @type {string} + */ + this.commandName = data.data.name; + + /** + * The invoked application command's type + * @type {ApplicationCommandType} + */ + this.commandType = data.data.type; + + /** + * The id of the guild the invoked application command is registered to + * @type {?Snowflake} + */ + this.commandGuildId = data.data.guild_id ?? null; + + /** + * Whether this interaction has already received a response + * @type {boolean} + */ + this.responded = false; + + /** + * The options passed to the command + * @type {CommandInteractionOptionResolver} + */ + this.options = new CommandInteractionOptionResolver(this.client, data.data.options ?? []); + } + + /** + * The invoked application command, if it was fetched before + * @type {?ApplicationCommand} + */ + get command() { + const id = this.commandId; + return this.guild?.commands.cache.get(id) ?? this.client.application.commands.cache.get(id) ?? null; + } + + /** + * Sends results for the autocomplete of this interaction. + * @param {ApplicationCommandOptionChoiceData[]} options The options for the autocomplete + * @returns {Promise<void>} + * @example + * // respond to autocomplete interaction + * interaction.respond([ + * { + * name: 'Option 1', + * value: 'option1', + * }, + * ]) + * .then(() => console.log('Successfully responded to the autocomplete interaction')) + * .catch(console.error); + */ + async respond(options) { + if (this.responded) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied); + + await this.client.rest.post(Routes.interactionCallback(this.id, this.token), { + body: { + type: InteractionResponseType.ApplicationCommandAutocompleteResult, + data: { + choices: options.map(({ nameLocalizations, ...option }) => ({ + ...this.client.options.jsonTransformer(option), + name_localizations: nameLocalizations, + })), + }, + }, + auth: false, + }); + this.responded = true; + } +} + +module.exports = AutocompleteInteraction; diff --git a/node_modules/discord.js/src/structures/Base.js b/node_modules/discord.js/src/structures/Base.js new file mode 100644 index 0000000..102fb21 --- /dev/null +++ b/node_modules/discord.js/src/structures/Base.js @@ -0,0 +1,43 @@ +'use strict'; + +const { flatten } = require('../util/Util'); + +/** + * Represents a data model that is identifiable by a Snowflake (i.e. Discord API data models). + * @abstract + */ +class Base { + constructor(client) { + /** + * The client that instantiated this + * @name Base#client + * @type {Client} + * @readonly + */ + Object.defineProperty(this, 'client', { value: client }); + } + + _clone() { + return Object.assign(Object.create(this), this); + } + + _patch(data) { + return data; + } + + _update(data) { + const clone = this._clone(); + this._patch(data); + return clone; + } + + toJSON(...props) { + return flatten(this, ...props); + } + + valueOf() { + return this.id; + } +} + +module.exports = Base; diff --git a/node_modules/discord.js/src/structures/BaseChannel.js b/node_modules/discord.js/src/structures/BaseChannel.js new file mode 100644 index 0000000..346f763 --- /dev/null +++ b/node_modules/discord.js/src/structures/BaseChannel.js @@ -0,0 +1,155 @@ +'use strict'; + +const { channelLink } = require('@discordjs/builders'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { ChannelType, Routes } = require('discord-api-types/v10'); +const Base = require('./Base'); +const ChannelFlagsBitField = require('../util/ChannelFlagsBitField'); +const { ThreadChannelTypes } = require('../util/Constants'); + +/** + * Represents any channel on Discord. + * @extends {Base} + * @abstract + */ +class BaseChannel extends Base { + constructor(client, data, immediatePatch = true) { + super(client); + + /** + * The type of the channel + * @type {ChannelType} + */ + this.type = data.type; + + if (data && immediatePatch) this._patch(data); + } + + _patch(data) { + if ('flags' in data) { + /** + * The flags that are applied to the channel. + * <info>This is only `null` in a {@link PartialGroupDMChannel}. In all other cases, it is not `null`.</info> + * @type {?Readonly<ChannelFlagsBitField>} + */ + this.flags = new ChannelFlagsBitField(data.flags).freeze(); + } else { + this.flags ??= new ChannelFlagsBitField().freeze(); + } + + /** + * The channel's id + * @type {Snowflake} + */ + this.id = data.id; + } + + /** + * The timestamp the channel was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the channel was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The URL to the channel + * @type {string} + * @readonly + */ + get url() { + return this.isDMBased() ? channelLink(this.id) : channelLink(this.id, this.guildId); + } + + /** + * Whether this Channel is a partial + * <info>This is always false outside of DM channels.</info> + * @type {boolean} + * @readonly + */ + get partial() { + return false; + } + + /** + * When concatenated with a string, this automatically returns the channel's mention instead of the Channel object. + * @returns {string} + * @example + * // Logs: Hello from <#123456789012345678>! + * console.log(`Hello from ${channel}!`); + */ + toString() { + return `<#${this.id}>`; + } + + /** + * Deletes this channel. + * @returns {Promise<BaseChannel>} + * @example + * // Delete the channel + * channel.delete() + * .then(console.log) + * .catch(console.error); + */ + async delete() { + await this.client.rest.delete(Routes.channel(this.id)); + return this; + } + + /** + * Fetches this channel. + * @param {boolean} [force=true] Whether to skip the cache check and request the API + * @returns {Promise<BaseChannel>} + */ + fetch(force = true) { + return this.client.channels.fetch(this.id, { force }); + } + + /** + * Indicates whether this channel is a {@link ThreadChannel}. + * @returns {boolean} + */ + isThread() { + return ThreadChannelTypes.includes(this.type); + } + + /** + * Indicates whether this channel is {@link TextBasedChannels text-based}. + * @returns {boolean} + */ + isTextBased() { + return 'messages' in this; + } + + /** + * Indicates whether this channel is DM-based (either a {@link DMChannel} or a {@link PartialGroupDMChannel}). + * @returns {boolean} + */ + isDMBased() { + return [ChannelType.DM, ChannelType.GroupDM].includes(this.type); + } + + /** + * Indicates whether this channel is {@link BaseGuildVoiceChannel voice-based}. + * @returns {boolean} + */ + isVoiceBased() { + return 'bitrate' in this; + } + + toJSON(...props) { + return super.toJSON({ createdTimestamp: true }, ...props); + } +} + +exports.BaseChannel = BaseChannel; diff --git a/node_modules/discord.js/src/structures/BaseGuild.js b/node_modules/discord.js/src/structures/BaseGuild.js new file mode 100644 index 0000000..b12ca44 --- /dev/null +++ b/node_modules/discord.js/src/structures/BaseGuild.js @@ -0,0 +1,119 @@ +'use strict'; + +const { makeURLSearchParams } = require('@discordjs/rest'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { Routes, GuildFeature } = require('discord-api-types/v10'); +const Base = require('./Base'); + +/** + * The base class for {@link Guild}, {@link OAuth2Guild} and {@link InviteGuild}. + * @extends {Base} + * @abstract + */ +class BaseGuild extends Base { + constructor(client, data) { + super(client); + + /** + * The guild's id + * @type {Snowflake} + */ + this.id = data.id; + + /** + * The name of this guild + * @type {string} + */ + this.name = data.name; + + /** + * The icon hash of this guild + * @type {?string} + */ + this.icon = data.icon; + + /** + * An array of features available to this guild + * @type {GuildFeature[]} + */ + this.features = data.features; + } + + /** + * The timestamp this guild was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time this guild was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The acronym that shows up in place of a guild icon + * @type {string} + * @readonly + */ + get nameAcronym() { + return this.name + .replace(/'s /g, ' ') + .replace(/\w+/g, e => e[0]) + .replace(/\s/g, ''); + } + + /** + * Whether this guild is partnered + * @type {boolean} + * @readonly + */ + get partnered() { + return this.features.includes(GuildFeature.Partnered); + } + + /** + * Whether this guild is verified + * @type {boolean} + * @readonly + */ + get verified() { + return this.features.includes(GuildFeature.Verified); + } + + /** + * The URL to this guild's icon. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + iconURL(options = {}) { + return this.icon && this.client.rest.cdn.icon(this.id, this.icon, options); + } + + /** + * Fetches this guild. + * @returns {Promise<Guild>} + */ + async fetch() { + const data = await this.client.rest.get(Routes.guild(this.id), { + query: makeURLSearchParams({ with_counts: true }), + }); + return this.client.guilds._add(data); + } + + /** + * When concatenated with a string, this automatically returns the guild's name instead of the Guild object. + * @returns {string} + */ + toString() { + return this.name; + } +} + +module.exports = BaseGuild; diff --git a/node_modules/discord.js/src/structures/BaseGuildEmoji.js b/node_modules/discord.js/src/structures/BaseGuildEmoji.js new file mode 100644 index 0000000..5a12bd9 --- /dev/null +++ b/node_modules/discord.js/src/structures/BaseGuildEmoji.js @@ -0,0 +1,56 @@ +'use strict'; + +const { Emoji } = require('./Emoji'); + +/** + * Parent class for {@link GuildEmoji} and {@link GuildPreviewEmoji}. + * @extends {Emoji} + * @abstract + */ +class BaseGuildEmoji extends Emoji { + constructor(client, data, guild) { + super(client, data); + + /** + * The guild this emoji is a part of + * @type {Guild|GuildPreview} + */ + this.guild = guild; + + this.requiresColons = null; + this.managed = null; + this.available = null; + + this._patch(data); + } + + _patch(data) { + if ('name' in data) this.name = data.name; + + if ('require_colons' in data) { + /** + * Whether or not this emoji requires colons surrounding it + * @type {?boolean} + */ + this.requiresColons = data.require_colons; + } + + if ('managed' in data) { + /** + * Whether this emoji is managed by an external service + * @type {?boolean} + */ + this.managed = data.managed; + } + + if ('available' in data) { + /** + * Whether this emoji is available + * @type {?boolean} + */ + this.available = data.available; + } + } +} + +module.exports = BaseGuildEmoji; diff --git a/node_modules/discord.js/src/structures/BaseGuildTextChannel.js b/node_modules/discord.js/src/structures/BaseGuildTextChannel.js new file mode 100644 index 0000000..f7d9d69 --- /dev/null +++ b/node_modules/discord.js/src/structures/BaseGuildTextChannel.js @@ -0,0 +1,186 @@ +'use strict'; + +const GuildChannel = require('./GuildChannel'); +const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const GuildMessageManager = require('../managers/GuildMessageManager'); +const GuildTextThreadManager = require('../managers/GuildTextThreadManager'); + +/** + * Represents a text-based guild channel on Discord. + * @extends {GuildChannel} + * @implements {TextBasedChannel} + */ +class BaseGuildTextChannel extends GuildChannel { + constructor(guild, data, client) { + super(guild, data, client, false); + + /** + * A manager of the messages sent to this channel + * @type {GuildMessageManager} + */ + this.messages = new GuildMessageManager(this); + + /** + * A manager of the threads belonging to this channel + * @type {GuildTextThreadManager} + */ + this.threads = new GuildTextThreadManager(this); + + /** + * If the guild considers this channel NSFW + * @type {boolean} + */ + this.nsfw = Boolean(data.nsfw); + + this._patch(data); + } + + _patch(data) { + super._patch(data); + + if ('topic' in data) { + /** + * The topic of the text channel + * @type {?string} + */ + this.topic = data.topic; + } + + if ('nsfw' in data) { + this.nsfw = Boolean(data.nsfw); + } + + if ('last_message_id' in data) { + /** + * The last message id sent in the channel, if one was sent + * @type {?Snowflake} + */ + this.lastMessageId = data.last_message_id; + } + + if ('last_pin_timestamp' in data) { + /** + * The timestamp when the last pinned message was pinned, if there was one + * @type {?number} + */ + this.lastPinTimestamp = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null; + } + + if ('default_auto_archive_duration' in data) { + /** + * The default auto archive duration for newly created threads in this channel + * @type {?ThreadAutoArchiveDuration} + */ + this.defaultAutoArchiveDuration = data.default_auto_archive_duration; + } + + if ('messages' in data) { + for (const message of data.messages) this.messages._add(message); + } + } + + /** + * Sets the default auto archive duration for all newly created threads in this channel. + * @param {ThreadAutoArchiveDuration} defaultAutoArchiveDuration The new default auto archive duration + * @param {string} [reason] Reason for changing the channel's default auto archive duration + * @returns {Promise<TextChannel>} + */ + setDefaultAutoArchiveDuration(defaultAutoArchiveDuration, reason) { + return this.edit({ defaultAutoArchiveDuration, reason }); + } + + /** + * Sets the type of this channel. + * <info>Only conversion between {@link TextChannel} and {@link NewsChannel} is supported.</info> + * @param {ChannelType.GuildText|ChannelType.GuildAnnouncement} type The new channel type + * @param {string} [reason] Reason for changing the channel's type + * @returns {Promise<GuildChannel>} + */ + setType(type, reason) { + return this.edit({ type, reason }); + } + + /** + * Sets a new topic for the guild channel. + * @param {?string} topic The new topic for the guild channel + * @param {string} [reason] Reason for changing the guild channel's topic + * @returns {Promise<GuildChannel>} + * @example + * // Set a new channel topic + * channel.setTopic('needs more rate limiting') + * .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`)) + * .catch(console.error); + */ + setTopic(topic, reason) { + return this.edit({ topic, reason }); + } + + /** + * Data that can be resolved to an Application. This can be: + * * An Application + * * An Activity with associated Application + * * A Snowflake + * @typedef {Application|Snowflake} ApplicationResolvable + */ + + /** + * Options used to create an invite to a guild channel. + * @typedef {Object} InviteCreateOptions + * @property {boolean} [temporary] Whether members that joined via the invite should be automatically + * kicked after 24 hours if they have not yet received a role + * @property {number} [maxAge] How long the invite should last (in seconds, 0 for forever) + * @property {number} [maxUses] Maximum number of uses + * @property {boolean} [unique] Create a unique invite, or use an existing one with similar settings + * @property {UserResolvable} [targetUser] The user whose stream to display for this invite, + * required if `targetType` is {@link InviteTargetType.Stream}, the user must be streaming in the channel + * @property {ApplicationResolvable} [targetApplication] The embedded application to open for this invite, + * required if `targetType` is {@link InviteTargetType.Stream}, the application must have the + * {@link InviteTargetType.EmbeddedApplication} flag + * @property {InviteTargetType} [targetType] The type of the target for this voice channel invite + * @property {string} [reason] The reason for creating the invite + */ + + /** + * Creates an invite to this guild channel. + * @param {InviteCreateOptions} [options={}] The options for creating the invite + * @returns {Promise<Invite>} + * @example + * // Create an invite to a channel + * channel.createInvite() + * .then(invite => console.log(`Created an invite with a code of ${invite.code}`)) + * .catch(console.error); + */ + createInvite(options) { + return this.guild.invites.create(this.id, options); + } + + /** + * Fetches a collection of invites to this guild channel. + * Resolves with a collection mapping invites by their codes. + * @param {boolean} [cache=true] Whether or not to cache the fetched invites + * @returns {Promise<Collection<string, Invite>>} + */ + fetchInvites(cache = true) { + return this.guild.invites.fetch({ channelId: this.id, cache }); + } + + // These are here only for documentation purposes - they are implemented by TextBasedChannel + /* eslint-disable no-empty-function */ + get lastMessage() {} + get lastPinAt() {} + send() {} + sendTyping() {} + createMessageCollector() {} + awaitMessages() {} + createMessageComponentCollector() {} + awaitMessageComponent() {} + bulkDelete() {} + fetchWebhooks() {} + createWebhook() {} + setRateLimitPerUser() {} + setNSFW() {} +} + +TextBasedChannel.applyToClass(BaseGuildTextChannel, true); + +module.exports = BaseGuildTextChannel; diff --git a/node_modules/discord.js/src/structures/BaseGuildVoiceChannel.js b/node_modules/discord.js/src/structures/BaseGuildVoiceChannel.js new file mode 100644 index 0000000..220ac6c --- /dev/null +++ b/node_modules/discord.js/src/structures/BaseGuildVoiceChannel.js @@ -0,0 +1,234 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { PermissionFlagsBits } = require('discord-api-types/v10'); +const GuildChannel = require('./GuildChannel'); +const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const GuildMessageManager = require('../managers/GuildMessageManager'); + +/** + * Represents a voice-based guild channel on Discord. + * @extends {GuildChannel} + * @implements {TextBasedChannel} + */ +class BaseGuildVoiceChannel extends GuildChannel { + constructor(guild, data, client) { + super(guild, data, client, false); + /** + * A manager of the messages sent to this channel + * @type {GuildMessageManager} + */ + this.messages = new GuildMessageManager(this); + + /** + * If the guild considers this channel NSFW + * @type {boolean} + */ + this.nsfw = Boolean(data.nsfw); + + this._patch(data); + } + + _patch(data) { + super._patch(data); + + if ('rtc_region' in data) { + /** + * The RTC region for this voice-based channel. This region is automatically selected if `null`. + * @type {?string} + */ + this.rtcRegion = data.rtc_region; + } + + if ('bitrate' in data) { + /** + * The bitrate of this voice-based channel + * @type {number} + */ + this.bitrate = data.bitrate; + } + + if ('user_limit' in data) { + /** + * The maximum amount of users allowed in this channel. + * @type {number} + */ + this.userLimit = data.user_limit; + } + + if ('video_quality_mode' in data) { + /** + * The camera video quality mode of the channel. + * @type {?VideoQualityMode} + */ + this.videoQualityMode = data.video_quality_mode; + } else { + this.videoQualityMode ??= null; + } + + if ('last_message_id' in data) { + /** + * The last message id sent in the channel, if one was sent + * @type {?Snowflake} + */ + this.lastMessageId = data.last_message_id; + } + + if ('messages' in data) { + for (const message of data.messages) this.messages._add(message); + } + + if ('rate_limit_per_user' in data) { + /** + * The rate limit per user (slowmode) for this channel in seconds + * @type {number} + */ + this.rateLimitPerUser = data.rate_limit_per_user; + } + + if ('nsfw' in data) { + this.nsfw = data.nsfw; + } + } + + /** + * The members in this voice-based channel + * @type {Collection<Snowflake, GuildMember>} + * @readonly + */ + get members() { + const coll = new Collection(); + for (const state of this.guild.voiceStates.cache.values()) { + if (state.channelId === this.id && state.member) { + coll.set(state.id, state.member); + } + } + return coll; + } + + /** + * Checks if the voice-based channel is full + * @type {boolean} + * @readonly + */ + get full() { + return this.userLimit > 0 && this.members.size >= this.userLimit; + } + + /** + * Whether the channel is joinable by the client user + * @type {boolean} + * @readonly + */ + get joinable() { + if (!this.viewable) return false; + const permissions = this.permissionsFor(this.client.user); + if (!permissions) return false; + + // This flag allows joining even if timed out + if (permissions.has(PermissionFlagsBits.Administrator, false)) return true; + + return ( + this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() && + permissions.has(PermissionFlagsBits.Connect, false) + ); + } + + /** + * Creates an invite to this guild channel. + * @param {InviteCreateOptions} [options={}] The options for creating the invite + * @returns {Promise<Invite>} + * @example + * // Create an invite to a channel + * channel.createInvite() + * .then(invite => console.log(`Created an invite with a code of ${invite.code}`)) + * .catch(console.error); + */ + createInvite(options) { + return this.guild.invites.create(this.id, options); + } + + /** + * Fetches a collection of invites to this guild channel. + * @param {boolean} [cache=true] Whether to cache the fetched invites + * @returns {Promise<Collection<string, Invite>>} + */ + fetchInvites(cache = true) { + return this.guild.invites.fetch({ channelId: this.id, cache }); + } + + /** + * Sets the bitrate of the channel. + * @param {number} bitrate The new bitrate + * @param {string} [reason] Reason for changing the channel's bitrate + * @returns {Promise<BaseGuildVoiceChannel>} + * @example + * // Set the bitrate of a voice channel + * channel.setBitrate(48_000) + * .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`)) + * .catch(console.error); + */ + setBitrate(bitrate, reason) { + return this.edit({ bitrate, reason }); + } + + /** + * Sets the RTC region of the channel. + * @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel + * @param {string} [reason] The reason for modifying this region. + * @returns {Promise<BaseGuildVoiceChannel>} + * @example + * // Set the RTC region to sydney + * channel.setRTCRegion('sydney'); + * @example + * // Remove a fixed region for this channel - let Discord decide automatically + * channel.setRTCRegion(null, 'We want to let Discord decide.'); + */ + setRTCRegion(rtcRegion, reason) { + return this.edit({ rtcRegion, reason }); + } + + /** + * Sets the user limit of the channel. + * @param {number} userLimit The new user limit + * @param {string} [reason] Reason for changing the user limit + * @returns {Promise<BaseGuildVoiceChannel>} + * @example + * // Set the user limit of a voice channel + * channel.setUserLimit(42) + * .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`)) + * .catch(console.error); + */ + setUserLimit(userLimit, reason) { + return this.edit({ userLimit, reason }); + } + + /** + * Sets the camera video quality mode of the channel. + * @param {VideoQualityMode} videoQualityMode The new camera video quality mode. + * @param {string} [reason] Reason for changing the camera video quality mode. + * @returns {Promise<BaseGuildVoiceChannel>} + */ + setVideoQualityMode(videoQualityMode, reason) { + return this.edit({ videoQualityMode, reason }); + } + + // These are here only for documentation purposes - they are implemented by TextBasedChannel + /* eslint-disable no-empty-function */ + get lastMessage() {} + send() {} + sendTyping() {} + createMessageCollector() {} + awaitMessages() {} + createMessageComponentCollector() {} + awaitMessageComponent() {} + bulkDelete() {} + fetchWebhooks() {} + createWebhook() {} + setRateLimitPerUser() {} + setNSFW() {} +} + +TextBasedChannel.applyToClass(BaseGuildVoiceChannel, true, ['lastPinAt']); + +module.exports = BaseGuildVoiceChannel; diff --git a/node_modules/discord.js/src/structures/BaseInteraction.js b/node_modules/discord.js/src/structures/BaseInteraction.js new file mode 100644 index 0000000..967350f --- /dev/null +++ b/node_modules/discord.js/src/structures/BaseInteraction.js @@ -0,0 +1,344 @@ +'use strict'; + +const { deprecate } = require('node:util'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { InteractionType, ApplicationCommandType, ComponentType } = require('discord-api-types/v10'); +const Base = require('./Base'); +const { SelectMenuTypes } = require('../util/Constants'); +const PermissionsBitField = require('../util/PermissionsBitField'); + +/** + * Represents an interaction. + * @extends {Base} + * @abstract + */ +class BaseInteraction extends Base { + constructor(client, data) { + super(client); + + /** + * The interaction's type + * @type {InteractionType} + */ + this.type = data.type; + + /** + * The interaction's id + * @type {Snowflake} + */ + this.id = data.id; + + /** + * The interaction's token + * @type {string} + * @name BaseInteraction#token + * @readonly + */ + Object.defineProperty(this, 'token', { value: data.token }); + + /** + * The application's id + * @type {Snowflake} + */ + this.applicationId = data.application_id; + + /** + * The id of the channel this interaction was sent in + * @type {?Snowflake} + */ + this.channelId = data.channel?.id ?? null; + + /** + * The id of the guild this interaction was sent in + * @type {?Snowflake} + */ + this.guildId = data.guild_id ?? null; + + /** + * The user who created this interaction + * @type {User} + */ + this.user = this.client.users._add(data.user ?? data.member.user); + + /** + * If this interaction was sent in a guild, the member which sent it + * @type {?(GuildMember|APIGuildMember)} + */ + this.member = data.member ? this.guild?.members._add(data.member) ?? data.member : null; + + /** + * The version + * @type {number} + */ + this.version = data.version; + + /** + * Set of permissions the application or bot has within the channel the interaction was sent from + * @type {?Readonly<PermissionsBitField>} + */ + this.appPermissions = data.app_permissions ? new PermissionsBitField(data.app_permissions).freeze() : null; + + /** + * The permissions of the member, if one exists, in the channel this interaction was executed in + * @type {?Readonly<PermissionsBitField>} + */ + this.memberPermissions = data.member?.permissions + ? new PermissionsBitField(data.member.permissions).freeze() + : null; + + /** + * A Discord locale string, possible values are: + * * en-US (English, US) + * * en-GB (English, UK) + * * bg (Bulgarian) + * * zh-CN (Chinese, China) + * * zh-TW (Chinese, Taiwan) + * * hr (Croatian) + * * cs (Czech) + * * da (Danish) + * * nl (Dutch) + * * fi (Finnish) + * * fr (French) + * * de (German) + * * el (Greek) + * * hi (Hindi) + * * hu (Hungarian) + * * it (Italian) + * * ja (Japanese) + * * ko (Korean) + * * lt (Lithuanian) + * * no (Norwegian) + * * pl (Polish) + * * pt-BR (Portuguese, Brazilian) + * * ro (Romanian, Romania) + * * ru (Russian) + * * es-ES (Spanish) + * * sv-SE (Swedish) + * * th (Thai) + * * tr (Turkish) + * * uk (Ukrainian) + * * vi (Vietnamese) + * @see {@link https://discord.com/developers/docs/reference#locales} + * @typedef {string} Locale + */ + + /** + * The locale of the user who invoked this interaction + * @type {Locale} + */ + this.locale = data.locale; + + /** + * The preferred locale from the guild this interaction was sent in + * @type {?Locale} + */ + this.guildLocale = data.guild_locale ?? null; + } + + /** + * The timestamp the interaction was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the interaction was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The channel this interaction was sent in + * @type {?TextBasedChannels} + * @readonly + */ + get channel() { + return this.client.channels.cache.get(this.channelId) ?? null; + } + + /** + * The guild this interaction was sent in + * @type {?Guild} + * @readonly + */ + get guild() { + return this.client.guilds.cache.get(this.guildId) ?? null; + } + + /** + * Indicates whether this interaction is received from a guild. + * @returns {boolean} + */ + inGuild() { + return Boolean(this.guildId && this.member); + } + + /** + * Indicates whether or not this interaction is both cached and received from a guild. + * @returns {boolean} + */ + inCachedGuild() { + return Boolean(this.guild && this.member); + } + + /** + * Indicates whether or not this interaction is received from an uncached guild. + * @returns {boolean} + */ + inRawGuild() { + return Boolean(this.guildId && !this.guild && this.member); + } + + /** + * Indicates whether this interaction is an {@link AutocompleteInteraction} + * @returns {boolean} + */ + isAutocomplete() { + return this.type === InteractionType.ApplicationCommandAutocomplete; + } + + /** + * Indicates whether this interaction is a {@link CommandInteraction} + * @returns {boolean} + */ + isCommand() { + return this.type === InteractionType.ApplicationCommand; + } + + /** + * Indicates whether this interaction is a {@link ChatInputCommandInteraction}. + * @returns {boolean} + */ + isChatInputCommand() { + return this.type === InteractionType.ApplicationCommand && this.commandType === ApplicationCommandType.ChatInput; + } + + /** + * Indicates whether this interaction is a {@link ContextMenuCommandInteraction} + * @returns {boolean} + */ + isContextMenuCommand() { + return ( + this.type === InteractionType.ApplicationCommand && + [ApplicationCommandType.User, ApplicationCommandType.Message].includes(this.commandType) + ); + } + + /** + * Indicates whether this interaction is a {@link MessageComponentInteraction} + * @returns {boolean} + */ + isMessageComponent() { + return this.type === InteractionType.MessageComponent; + } + + /** + * Indicates whether this interaction is a {@link ModalSubmitInteraction} + * @returns {boolean} + */ + isModalSubmit() { + return this.type === InteractionType.ModalSubmit; + } + + /** + * Indicates whether this interaction is a {@link UserContextMenuCommandInteraction} + * @returns {boolean} + */ + isUserContextMenuCommand() { + return this.isContextMenuCommand() && this.commandType === ApplicationCommandType.User; + } + + /** + * Indicates whether this interaction is a {@link MessageContextMenuCommandInteraction} + * @returns {boolean} + */ + isMessageContextMenuCommand() { + return this.isContextMenuCommand() && this.commandType === ApplicationCommandType.Message; + } + + /** + * Indicates whether this interaction is a {@link ButtonInteraction}. + * @returns {boolean} + */ + isButton() { + return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.Button; + } + + /** + * Indicates whether this interaction is a {@link StringSelectMenuInteraction}. + * @returns {boolean} + * @deprecated Use {@link BaseInteraction#isStringSelectMenu} instead. + */ + isSelectMenu() { + return this.isStringSelectMenu(); + } + + /** + * Indicates whether this interaction is a select menu of any known type. + * @returns {boolean} + */ + isAnySelectMenu() { + return this.type === InteractionType.MessageComponent && SelectMenuTypes.includes(this.componentType); + } + + /** + * Indicates whether this interaction is a {@link StringSelectMenuInteraction}. + * @returns {boolean} + */ + isStringSelectMenu() { + return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.StringSelect; + } + + /** + * Indicates whether this interaction is a {@link UserSelectMenuInteraction} + * @returns {boolean} + */ + isUserSelectMenu() { + return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.UserSelect; + } + + /** + * Indicates whether this interaction is a {@link RoleSelectMenuInteraction} + * @returns {boolean} + */ + isRoleSelectMenu() { + return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.RoleSelect; + } + + /** + * Indicates whether this interaction is a {@link ChannelSelectMenuInteraction} + * @returns {boolean} + */ + isChannelSelectMenu() { + return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.ChannelSelect; + } + + /** + * Indicates whether this interaction is a {@link MentionableSelectMenuInteraction} + * @returns {boolean} + */ + isMentionableSelectMenu() { + return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.MentionableSelect; + } + + /** + * Indicates whether this interaction can be replied to. + * @returns {boolean} + */ + isRepliable() { + return ![InteractionType.Ping, InteractionType.ApplicationCommandAutocomplete].includes(this.type); + } +} + +BaseInteraction.prototype.isSelectMenu = deprecate( + BaseInteraction.prototype.isSelectMenu, + 'BaseInteraction#isSelectMenu() is deprecated. Use BaseInteraction#isStringSelectMenu() instead.', +); + +module.exports = BaseInteraction; diff --git a/node_modules/discord.js/src/structures/BaseSelectMenuComponent.js b/node_modules/discord.js/src/structures/BaseSelectMenuComponent.js new file mode 100644 index 0000000..7177f43 --- /dev/null +++ b/node_modules/discord.js/src/structures/BaseSelectMenuComponent.js @@ -0,0 +1,56 @@ +'use strict'; + +const Component = require('./Component'); + +/** + * Represents a select menu component + * @extends {Component} + */ +class BaseSelectMenuComponent extends Component { + /** + * The placeholder for this select menu + * @type {?string} + * @readonly + */ + get placeholder() { + return this.data.placeholder ?? null; + } + + /** + * The maximum amount of options that can be selected + * @type {?number} + * @readonly + */ + get maxValues() { + return this.data.max_values ?? null; + } + + /** + * The minimum amount of options that must be selected + * @type {?number} + * @readonly + */ + get minValues() { + return this.data.min_values ?? null; + } + + /** + * The custom id of this select menu + * @type {string} + * @readonly + */ + get customId() { + return this.data.custom_id; + } + + /** + * Whether this select menu is disabled + * @type {boolean} + * @readonly + */ + get disabled() { + return this.data.disabled ?? false; + } +} + +module.exports = BaseSelectMenuComponent; diff --git a/node_modules/discord.js/src/structures/ButtonBuilder.js b/node_modules/discord.js/src/structures/ButtonBuilder.js new file mode 100644 index 0000000..ada4188 --- /dev/null +++ b/node_modules/discord.js/src/structures/ButtonBuilder.js @@ -0,0 +1,44 @@ +'use strict'; + +const { ButtonBuilder: BuildersButton } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { toSnakeCase } = require('../util/Transformers'); +const { resolvePartialEmoji } = require('../util/Util'); + +/** + * Represents a button builder. + * @extends {BuildersButton} + */ +class ButtonBuilder extends BuildersButton { + constructor({ emoji, ...data } = {}) { + super(toSnakeCase({ ...data, emoji: emoji && typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji })); + } + + /** + * Sets the emoji to display on this button + * @param {string|APIMessageComponentEmoji} emoji The emoji to display on this button + * @returns {ButtonBuilder} + */ + setEmoji(emoji) { + if (typeof emoji === 'string') { + return super.setEmoji(resolvePartialEmoji(emoji)); + } + return super.setEmoji(emoji); + } + + /** + * Creates a new button builder from JSON data + * @param {ButtonBuilder|ButtonComponent|APIButtonComponent} other The other data + * @returns {ButtonBuilder} + */ + static from(other) { + return new this(isJSONEncodable(other) ? other.toJSON() : other); + } +} + +module.exports = ButtonBuilder; + +/** + * @external BuildersButton + * @see {@link https://discord.js.org/docs/packages/builders/stable/ButtonBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/ButtonComponent.js b/node_modules/discord.js/src/structures/ButtonComponent.js new file mode 100644 index 0000000..7319c3a --- /dev/null +++ b/node_modules/discord.js/src/structures/ButtonComponent.js @@ -0,0 +1,65 @@ +'use strict'; + +const Component = require('./Component'); + +/** + * Represents a button component + * @extends {Component} + */ +class ButtonComponent extends Component { + /** + * The style of this button + * @type {ButtonStyle} + * @readonly + */ + get style() { + return this.data.style; + } + + /** + * The label of this button + * @type {?string} + * @readonly + */ + get label() { + return this.data.label ?? null; + } + + /** + * The emoji used in this button + * @type {?APIMessageComponentEmoji} + * @readonly + */ + get emoji() { + return this.data.emoji ?? null; + } + + /** + * Whether this button is disabled + * @type {boolean} + * @readonly + */ + get disabled() { + return this.data.disabled ?? false; + } + + /** + * The custom id of this button (only defined on non-link buttons) + * @type {?string} + * @readonly + */ + get customId() { + return this.data.custom_id ?? null; + } + + /** + * The URL of this button (only defined on link buttons) + * @type {?string} + * @readonly + */ + get url() { + return this.data.url ?? null; + } +} + +module.exports = ButtonComponent; diff --git a/node_modules/discord.js/src/structures/ButtonInteraction.js b/node_modules/discord.js/src/structures/ButtonInteraction.js new file mode 100644 index 0000000..db57592 --- /dev/null +++ b/node_modules/discord.js/src/structures/ButtonInteraction.js @@ -0,0 +1,11 @@ +'use strict'; + +const MessageComponentInteraction = require('./MessageComponentInteraction'); + +/** + * Represents a button interaction. + * @extends {MessageComponentInteraction} + */ +class ButtonInteraction extends MessageComponentInteraction {} + +module.exports = ButtonInteraction; diff --git a/node_modules/discord.js/src/structures/CategoryChannel.js b/node_modules/discord.js/src/structures/CategoryChannel.js new file mode 100644 index 0000000..d038044 --- /dev/null +++ b/node_modules/discord.js/src/structures/CategoryChannel.js @@ -0,0 +1,45 @@ +'use strict'; + +const GuildChannel = require('./GuildChannel'); +const CategoryChannelChildManager = require('../managers/CategoryChannelChildManager'); + +/** + * Represents a guild category channel on Discord. + * @extends {GuildChannel} + */ +class CategoryChannel extends GuildChannel { + /** + * The id of the parent of this channel. + * @name CategoryChannel#parentId + * @type {null} + */ + + /** + * The parent of this channel. + * @name CategoryChannel#parent + * @type {null} + * @readonly + */ + + /** + * Sets the category parent of this channel. + * <warn>It is not possible to set the parent of a CategoryChannel.</warn> + * @method setParent + * @memberof CategoryChannel + * @instance + * @param {?CategoryChannelResolvable} channel The channel to set as parent + * @param {SetParentOptions} [options={}] The options for setting the parent + * @returns {Promise<GuildChannel>} + */ + + /** + * A manager of the channels belonging to this category + * @type {CategoryChannelChildManager} + * @readonly + */ + get children() { + return new CategoryChannelChildManager(this); + } +} + +module.exports = CategoryChannel; diff --git a/node_modules/discord.js/src/structures/ChannelSelectMenuBuilder.js b/node_modules/discord.js/src/structures/ChannelSelectMenuBuilder.js new file mode 100644 index 0000000..6d99474 --- /dev/null +++ b/node_modules/discord.js/src/structures/ChannelSelectMenuBuilder.js @@ -0,0 +1,31 @@ +'use strict'; + +const { ChannelSelectMenuBuilder: BuildersChannelSelectMenu } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { toSnakeCase } = require('../util/Transformers'); + +/** + * Class used to build select menu components to be sent through the API + * @extends {BuildersChannelSelectMenu} + */ +class ChannelSelectMenuBuilder extends BuildersChannelSelectMenu { + constructor(data = {}) { + super(toSnakeCase(data)); + } + + /** + * Creates a new select menu builder from JSON data + * @param {ChannelSelectMenuBuilder|ChannelSelectMenuComponent|APIChannelSelectComponent} other The other data + * @returns {ChannelSelectMenuBuilder} + */ + static from(other) { + return new this(isJSONEncodable(other) ? other.toJSON() : other); + } +} + +module.exports = ChannelSelectMenuBuilder; + +/** + * @external BuildersChannelSelectMenu + * @see {@link https://discord.js.org/docs/packages/builders/stable/ChannelSelectMenuBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/ChannelSelectMenuComponent.js b/node_modules/discord.js/src/structures/ChannelSelectMenuComponent.js new file mode 100644 index 0000000..90a7063 --- /dev/null +++ b/node_modules/discord.js/src/structures/ChannelSelectMenuComponent.js @@ -0,0 +1,20 @@ +'use strict'; + +const BaseSelectMenuComponent = require('./BaseSelectMenuComponent'); + +/** + * Represents a channel select menu component + * @extends {BaseSelectMenuComponent} + */ +class ChannelSelectMenuComponent extends BaseSelectMenuComponent { + /** + * The options in this select menu + * @type {?(ChannelType[])} + * @readonly + */ + get channelTypes() { + return this.data.channel_types ?? null; + } +} + +module.exports = ChannelSelectMenuComponent; diff --git a/node_modules/discord.js/src/structures/ChannelSelectMenuInteraction.js b/node_modules/discord.js/src/structures/ChannelSelectMenuInteraction.js new file mode 100644 index 0000000..a5e9c99 --- /dev/null +++ b/node_modules/discord.js/src/structures/ChannelSelectMenuInteraction.js @@ -0,0 +1,33 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const MessageComponentInteraction = require('./MessageComponentInteraction'); + +/** + * Represents a {@link ComponentType.ChannelSelect} select menu interaction. + * @extends {MessageComponentInteraction} + */ +class ChannelSelectMenuInteraction extends MessageComponentInteraction { + constructor(client, data) { + super(client, data); + const { resolved, values } = data.data; + + /** + * An array of the selected channel ids + * @type {Snowflake[]} + */ + this.values = values ?? []; + + /** + * Collection of the selected channels + * @type {Collection<Snowflake, BaseChannel|APIChannel>} + */ + this.channels = new Collection(); + + for (const channel of Object.values(resolved?.channels ?? {})) { + this.channels.set(channel.id, this.client.channels._add(channel, this.guild) ?? channel); + } + } +} + +module.exports = ChannelSelectMenuInteraction; diff --git a/node_modules/discord.js/src/structures/ChatInputCommandInteraction.js b/node_modules/discord.js/src/structures/ChatInputCommandInteraction.js new file mode 100644 index 0000000..35175e4 --- /dev/null +++ b/node_modules/discord.js/src/structures/ChatInputCommandInteraction.js @@ -0,0 +1,41 @@ +'use strict'; + +const CommandInteraction = require('./CommandInteraction'); +const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver'); + +/** + * Represents a command interaction. + * @extends {CommandInteraction} + */ +class ChatInputCommandInteraction extends CommandInteraction { + constructor(client, data) { + super(client, data); + + /** + * The options passed to the command. + * @type {CommandInteractionOptionResolver} + */ + this.options = new CommandInteractionOptionResolver( + this.client, + data.data.options?.map(option => this.transformOption(option, data.data.resolved)) ?? [], + this.transformResolved(data.data.resolved ?? {}), + ); + } + + /** + * Returns a string representation of the command interaction. + * This can then be copied by a user and executed again in a new command while keeping the option order. + * @returns {string} + */ + toString() { + const properties = [ + this.commandName, + this.options._group, + this.options._subcommand, + ...this.options._hoistedOptions.map(o => `${o.name}:${o.value}`), + ]; + return `/${properties.filter(Boolean).join(' ')}`; + } +} + +module.exports = ChatInputCommandInteraction; diff --git a/node_modules/discord.js/src/structures/ClientApplication.js b/node_modules/discord.js/src/structures/ClientApplication.js new file mode 100644 index 0000000..69f5134 --- /dev/null +++ b/node_modules/discord.js/src/structures/ClientApplication.js @@ -0,0 +1,222 @@ +'use strict'; + +const { Routes } = require('discord-api-types/v10'); +const { ApplicationRoleConnectionMetadata } = require('./ApplicationRoleConnectionMetadata'); +const Team = require('./Team'); +const Application = require('./interfaces/Application'); +const ApplicationCommandManager = require('../managers/ApplicationCommandManager'); +const ApplicationFlagsBitField = require('../util/ApplicationFlagsBitField'); +const PermissionsBitField = require('../util/PermissionsBitField'); + +/** + * @typedef {Object} ClientApplicationInstallParams + * @property {OAuth2Scopes[]} scopes The scopes to add the application to the server with + * @property {Readonly<PermissionsBitField>} permissions The permissions this bot will request upon joining + */ + +/** + * Represents a client application. + * @extends {Application} + */ +class ClientApplication extends Application { + constructor(client, data) { + super(client, data); + + /** + * The application command manager for this application + * @type {ApplicationCommandManager} + */ + this.commands = new ApplicationCommandManager(this.client); + } + + _patch(data) { + super._patch(data); + + /** + * The tags this application has (max of 5) + * @type {string[]} + */ + this.tags = data.tags ?? []; + + if ('install_params' in data) { + /** + * Settings for this application's default in-app authorization + * @type {?ClientApplicationInstallParams} + */ + this.installParams = { + scopes: data.install_params.scopes, + permissions: new PermissionsBitField(data.install_params.permissions).freeze(), + }; + } else { + this.installParams ??= null; + } + + if ('custom_install_url' in data) { + /** + * This application's custom installation URL + * @type {?string} + */ + this.customInstallURL = data.custom_install_url; + } else { + this.customInstallURL = null; + } + + if ('flags' in data) { + /** + * The flags this application has + * @type {ApplicationFlagsBitField} + */ + this.flags = new ApplicationFlagsBitField(data.flags).freeze(); + } + + if ('approximate_guild_count' in data) { + /** + * An approximate amount of guilds this application is in. + * @type {?number} + */ + this.approximateGuildCount = data.approximate_guild_count; + } else { + this.approximateGuildCount ??= null; + } + + if ('guild_id' in data) { + /** + * The id of the guild associated with this application. + * @type {?Snowflake} + */ + this.guildId = data.guild_id; + } else { + this.guildId ??= null; + } + + if ('cover_image' in data) { + /** + * The hash of the application's cover image + * @type {?string} + */ + this.cover = data.cover_image; + } else { + this.cover ??= null; + } + + if ('rpc_origins' in data) { + /** + * The application's RPC origins, if enabled + * @type {string[]} + */ + this.rpcOrigins = data.rpc_origins; + } else { + this.rpcOrigins ??= []; + } + + if ('bot_require_code_grant' in data) { + /** + * If this application's bot requires a code grant when using the OAuth2 flow + * @type {?boolean} + */ + this.botRequireCodeGrant = data.bot_require_code_grant; + } else { + this.botRequireCodeGrant ??= null; + } + + if ('bot_public' in data) { + /** + * If this application's bot is public + * @type {?boolean} + */ + this.botPublic = data.bot_public; + } else { + this.botPublic ??= null; + } + + if ('role_connections_verification_url' in data) { + /** + * This application's role connection verification entry point URL + * @type {?string} + */ + this.roleConnectionsVerificationURL = data.role_connections_verification_url; + } else { + this.roleConnectionsVerificationURL ??= null; + } + + /** + * The owner of this OAuth application + * @type {?(User|Team)} + */ + this.owner = data.team + ? new Team(this.client, data.team) + : data.owner + ? this.client.users._add(data.owner) + : this.owner ?? null; + } + + /** + * The guild associated with this application. + * @type {?Guild} + * @readonly + */ + get guild() { + return this.client.guilds.cache.get(this.guildId) ?? null; + } + + /** + * Whether this application is partial + * @type {boolean} + * @readonly + */ + get partial() { + return !this.name; + } + + /** + * Obtains this application from Discord. + * @returns {Promise<ClientApplication>} + */ + async fetch() { + const data = await this.client.rest.get(Routes.currentApplication()); + this._patch(data); + return this; + } + + /** + * Gets this application's role connection metadata records + * @returns {Promise<ApplicationRoleConnectionMetadata[]>} + */ + async fetchRoleConnectionMetadataRecords() { + const metadata = await this.client.rest.get(Routes.applicationRoleConnectionMetadata(this.client.user.id)); + return metadata.map(data => new ApplicationRoleConnectionMetadata(data)); + } + + /** + * Data for creating or editing an application role connection metadata. + * @typedef {Object} ApplicationRoleConnectionMetadataEditOptions + * @property {string} name The name of the metadata field + * @property {?Object<Locale, string>} [nameLocalizations] The name localizations for the metadata field + * @property {string} description The description of the metadata field + * @property {?Object<Locale, string>} [descriptionLocalizations] The description localizations for the metadata field + * @property {string} key The dictionary key of the metadata field + * @property {ApplicationRoleConnectionMetadataType} type The type of the metadata field + */ + + /** + * Updates this application's role connection metadata records + * @param {ApplicationRoleConnectionMetadataEditOptions[]} records The new role connection metadata records + * @returns {Promise<ApplicationRoleConnectionMetadata[]>} + */ + async editRoleConnectionMetadataRecords(records) { + const newRecords = await this.client.rest.put(Routes.applicationRoleConnectionMetadata(this.client.user.id), { + body: records.map(record => ({ + type: record.type, + key: record.key, + name: record.name, + name_localizations: record.nameLocalizations, + description: record.description, + description_localizations: record.descriptionLocalizations, + })), + }); + + return newRecords.map(data => new ApplicationRoleConnectionMetadata(data)); + } +} + +module.exports = ClientApplication; diff --git a/node_modules/discord.js/src/structures/ClientPresence.js b/node_modules/discord.js/src/structures/ClientPresence.js new file mode 100644 index 0000000..6dd72ee --- /dev/null +++ b/node_modules/discord.js/src/structures/ClientPresence.js @@ -0,0 +1,90 @@ +'use strict'; + +const { GatewayOpcodes, ActivityType } = require('discord-api-types/v10'); +const { Presence } = require('./Presence'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * Represents the client's presence. + * @extends {Presence} + */ +class ClientPresence extends Presence { + constructor(client, data = {}) { + super(client, Object.assign(data, { status: data.status ?? 'online', user: { id: null } })); + } + + /** + * Sets the client's presence + * @param {PresenceData} presence The data to set the presence to + * @returns {ClientPresence} + */ + set(presence) { + const packet = this._parse(presence); + this._patch(packet); + if (presence.shardId === undefined) { + this.client.ws.broadcast({ op: GatewayOpcodes.PresenceUpdate, d: packet }); + } else if (Array.isArray(presence.shardId)) { + for (const shardId of presence.shardId) { + this.client.ws.shards.get(shardId).send({ op: GatewayOpcodes.PresenceUpdate, d: packet }); + } + } else { + this.client.ws.shards.get(presence.shardId).send({ op: GatewayOpcodes.PresenceUpdate, d: packet }); + } + return this; + } + + /** + * Parses presence data into a packet ready to be sent to Discord + * @param {PresenceData} presence The data to parse + * @returns {APIPresence} + * @private + */ + _parse({ status, since, afk, activities }) { + const data = { + activities: [], + afk: typeof afk === 'boolean' ? afk : false, + since: typeof since === 'number' && !Number.isNaN(since) ? since : null, + status: status ?? this.status, + }; + if (activities?.length) { + for (const [i, activity] of activities.entries()) { + if (typeof activity.name !== 'string') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, `activities[${i}].name`, 'string'); + } + + activity.type ??= ActivityType.Playing; + + if (activity.type === ActivityType.Custom && !activity.state) { + activity.state = activity.name; + activity.name = 'Custom Status'; + } + + data.activities.push({ + type: activity.type, + name: activity.name, + state: activity.state, + url: activity.url, + }); + } + } else if (!activities && (status || afk || since) && this.activities.length) { + data.activities.push( + ...this.activities.map(a => ({ + name: a.name, + state: a.state ?? undefined, + type: a.type, + url: a.url ?? undefined, + })), + ); + } + + return data; + } +} + +module.exports = ClientPresence; + +/* eslint-disable max-len */ +/** + * @external APIPresence + * @see {@link https://discord.com/developers/docs/rich-presence/how-to#updating-presence-update-presence-payload-fields} + */ diff --git a/node_modules/discord.js/src/structures/ClientUser.js b/node_modules/discord.js/src/structures/ClientUser.js new file mode 100644 index 0000000..b93904c --- /dev/null +++ b/node_modules/discord.js/src/structures/ClientUser.js @@ -0,0 +1,187 @@ +'use strict'; + +const { Routes } = require('discord-api-types/v10'); +const User = require('./User'); +const DataResolver = require('../util/DataResolver'); + +/** + * Represents the logged in client's Discord user. + * @extends {User} + */ +class ClientUser extends User { + _patch(data) { + super._patch(data); + + if ('verified' in data) { + /** + * Whether or not this account has been verified + * @type {boolean} + */ + this.verified = data.verified; + } + + if ('mfa_enabled' in data) { + /** + * If the bot's {@link ClientApplication#owner Owner} has MFA enabled on their account + * @type {?boolean} + */ + this.mfaEnabled = typeof data.mfa_enabled === 'boolean' ? data.mfa_enabled : null; + } else { + this.mfaEnabled ??= null; + } + + if ('token' in data) this.client.token = data.token; + } + + /** + * Represents the client user's presence + * @type {ClientPresence} + * @readonly + */ + get presence() { + return this.client.presence; + } + + /** + * Data used to edit the logged in client + * @typedef {Object} ClientUserEditOptions + * @property {string} [username] The new username + * @property {?(BufferResolvable|Base64Resolvable)} [avatar] The new avatar + */ + + /** + * Edits the logged in client. + * @param {ClientUserEditOptions} options The options to provide + * @returns {Promise<ClientUser>} + */ + async edit({ username, avatar }) { + const data = await this.client.rest.patch(Routes.user(), { + body: { username, avatar: avatar && (await DataResolver.resolveImage(avatar)) }, + }); + + this.client.token = data.token; + this.client.rest.setToken(data.token); + const { updated } = this.client.actions.UserUpdate.handle(data); + return updated ?? this; + } + + /** + * Sets the username of the logged in client. + * <info>Changing usernames in Discord is heavily rate limited, with only 2 requests + * every hour. Use this sparingly!</info> + * @param {string} username The new username + * @returns {Promise<ClientUser>} + * @example + * // Set username + * client.user.setUsername('discordjs') + * .then(user => console.log(`My new username is ${user.username}`)) + * .catch(console.error); + */ + setUsername(username) { + return this.edit({ username }); + } + + /** + * Sets the avatar of the logged in client. + * @param {?(BufferResolvable|Base64Resolvable)} avatar The new avatar + * @returns {Promise<ClientUser>} + * @example + * // Set avatar + * client.user.setAvatar('./avatar.png') + * .then(user => console.log(`New avatar set!`)) + * .catch(console.error); + */ + setAvatar(avatar) { + return this.edit({ avatar }); + } + + /** + * Options for setting activities + * @typedef {Object} ActivitiesOptions + * @property {string} name Name of the activity + * @property {string} [state] State of the activity + * @property {ActivityType} [type] Type of the activity + * @property {string} [url] Twitch / YouTube stream URL + */ + + /** + * Data resembling a raw Discord presence. + * @typedef {Object} PresenceData + * @property {PresenceStatusData} [status] Status of the user + * @property {boolean} [afk] Whether the user is AFK + * @property {ActivitiesOptions[]} [activities] Activity the user is playing + * @property {number|number[]} [shardId] Shard id(s) to have the activity set on + */ + + /** + * Sets the full presence of the client user. + * @param {PresenceData} data Data for the presence + * @returns {ClientPresence} + * @example + * // Set the client user's presence + * client.user.setPresence({ activities: [{ name: 'with discord.js' }], status: 'idle' }); + */ + setPresence(data) { + return this.client.presence.set(data); + } + + /** + * A user's status. Must be one of: + * * `online` + * * `idle` + * * `invisible` + * * `dnd` (do not disturb) + * @typedef {string} PresenceStatusData + */ + + /** + * Sets the status of the client user. + * @param {PresenceStatusData} status Status to change to + * @param {number|number[]} [shardId] Shard id(s) to have the activity set on + * @returns {ClientPresence} + * @example + * // Set the client user's status + * client.user.setStatus('idle'); + */ + setStatus(status, shardId) { + return this.setPresence({ status, shardId }); + } + + /** + * Options for setting an activity. + * @typedef {Object} ActivityOptions + * @property {string} name Name of the activity + * @property {string} [state] State of the activity + * @property {string} [url] Twitch / YouTube stream URL + * @property {ActivityType} [type] Type of the activity + * @property {number|number[]} [shardId] Shard Id(s) to have the activity set on + */ + + /** + * Sets the activity the client user is playing. + * @param {string|ActivityOptions} name Activity being played, or options for setting the activity + * @param {ActivityOptions} [options] Options for setting the activity + * @returns {ClientPresence} + * @example + * // Set the client user's activity + * client.user.setActivity('discord.js', { type: ActivityType.Watching }); + */ + setActivity(name, options = {}) { + if (!name) return this.setPresence({ activities: [], shardId: options.shardId }); + + const activity = Object.assign({}, options, typeof name === 'object' ? name : { name }); + return this.setPresence({ activities: [activity], shardId: activity.shardId }); + } + + /** + * Sets/removes the AFK flag for the client user. + * @param {boolean} [afk=true] Whether or not the user is AFK + * @param {number|number[]} [shardId] Shard Id(s) to have the AFK flag set on + * @returns {ClientPresence} + */ + setAFK(afk = true, shardId) { + return this.setPresence({ afk, shardId }); + } +} + +module.exports = ClientUser; diff --git a/node_modules/discord.js/src/structures/CommandInteraction.js b/node_modules/discord.js/src/structures/CommandInteraction.js new file mode 100644 index 0000000..ec6ef40 --- /dev/null +++ b/node_modules/discord.js/src/structures/CommandInteraction.js @@ -0,0 +1,224 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Attachment = require('./Attachment'); +const BaseInteraction = require('./BaseInteraction'); +const InteractionWebhook = require('./InteractionWebhook'); +const InteractionResponses = require('./interfaces/InteractionResponses'); + +/** + * Represents a command interaction. + * @extends {BaseInteraction} + * @implements {InteractionResponses} + * @abstract + */ +class CommandInteraction extends BaseInteraction { + constructor(client, data) { + super(client, data); + + /** + * The id of the channel this interaction was sent in + * @type {Snowflake} + * @name CommandInteraction#channelId + */ + + /** + * The invoked application command's id + * @type {Snowflake} + */ + this.commandId = data.data.id; + + /** + * The invoked application command's name + * @type {string} + */ + this.commandName = data.data.name; + + /** + * The invoked application command's type + * @type {ApplicationCommandType} + */ + this.commandType = data.data.type; + + /** + * The id of the guild the invoked application command is registered to + * @type {?Snowflake} + */ + this.commandGuildId = data.data.guild_id ?? null; + + /** + * Whether the reply to this interaction has been deferred + * @type {boolean} + */ + this.deferred = false; + + /** + * Whether this interaction has already been replied to + * @type {boolean} + */ + this.replied = false; + + /** + * Whether the reply to this interaction is ephemeral + * @type {?boolean} + */ + this.ephemeral = null; + + /** + * An associated interaction webhook, can be used to further interact with this interaction + * @type {InteractionWebhook} + */ + this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token); + } + + /** + * The invoked application command, if it was fetched before + * @type {?ApplicationCommand} + */ + get command() { + const id = this.commandId; + return this.guild?.commands.cache.get(id) ?? this.client.application.commands.cache.get(id) ?? null; + } + + /** + * Represents the resolved data of a received command interaction. + * @typedef {Object} CommandInteractionResolvedData + * @property {Collection<Snowflake, User>} [users] The resolved users + * @property {Collection<Snowflake, GuildMember|APIGuildMember>} [members] The resolved guild members + * @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles + * @property {Collection<Snowflake, BaseChannel|APIChannel>} [channels] The resolved channels + * @property {Collection<Snowflake, Message|APIMessage>} [messages] The resolved messages + * @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments + */ + + /** + * Transforms the resolved received from the API. + * @param {APIInteractionDataResolved} resolved The received resolved objects + * @returns {CommandInteractionResolvedData} + * @private + */ + transformResolved({ members, users, channels, roles, messages, attachments }) { + const result = {}; + + if (members) { + result.members = new Collection(); + for (const [id, member] of Object.entries(members)) { + const user = users[id]; + result.members.set(id, this.guild?.members._add({ user, ...member }) ?? member); + } + } + + if (users) { + result.users = new Collection(); + for (const user of Object.values(users)) { + result.users.set(user.id, this.client.users._add(user)); + } + } + + if (roles) { + result.roles = new Collection(); + for (const role of Object.values(roles)) { + result.roles.set(role.id, this.guild?.roles._add(role) ?? role); + } + } + + if (channels) { + result.channels = new Collection(); + for (const channel of Object.values(channels)) { + result.channels.set(channel.id, this.client.channels._add(channel, this.guild) ?? channel); + } + } + + if (messages) { + result.messages = new Collection(); + for (const message of Object.values(messages)) { + result.messages.set(message.id, this.channel?.messages?._add(message) ?? message); + } + } + + if (attachments) { + result.attachments = new Collection(); + for (const attachment of Object.values(attachments)) { + const patched = new Attachment(attachment); + result.attachments.set(attachment.id, patched); + } + } + + return result; + } + + /** + * Represents an option of a received command interaction. + * @typedef {Object} CommandInteractionOption + * @property {string} name The name of the option + * @property {ApplicationCommandOptionType} type The type of the option + * @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a + * {@link ApplicationCommandOptionType.String}, {@link ApplicationCommandOptionType.Integer} or + * {@link ApplicationCommandOptionType.Number} option + * @property {string|number|boolean} [value] The value of the option + * @property {CommandInteractionOption[]} [options] Additional options if this option is a + * subcommand (group) + * @property {User} [user] The resolved user + * @property {GuildMember|APIGuildMember} [member] The resolved member + * @property {GuildChannel|ThreadChannel|APIChannel} [channel] The resolved channel + * @property {Role|APIRole} [role] The resolved role + * @property {Attachment} [attachment] The resolved attachment + */ + + /** + * Transforms an option received from the API. + * @param {APIApplicationCommandOption} option The received option + * @param {APIInteractionDataResolved} resolved The resolved interaction data + * @returns {CommandInteractionOption} + * @private + */ + transformOption(option, resolved) { + const result = { + name: option.name, + type: option.type, + }; + + if ('value' in option) result.value = option.value; + if ('options' in option) result.options = option.options.map(opt => this.transformOption(opt, resolved)); + + if (resolved) { + const user = resolved.users?.[option.value]; + if (user) result.user = this.client.users._add(user); + + const member = resolved.members?.[option.value]; + if (member) result.member = this.guild?.members._add({ user, ...member }) ?? member; + + const channel = resolved.channels?.[option.value]; + if (channel) result.channel = this.client.channels._add(channel, this.guild) ?? channel; + + const role = resolved.roles?.[option.value]; + if (role) result.role = this.guild?.roles._add(role) ?? role; + + const attachment = resolved.attachments?.[option.value]; + if (attachment) result.attachment = new Attachment(attachment); + } + + return result; + } + + // These are here only for documentation purposes - they are implemented by InteractionResponses + /* eslint-disable no-empty-function */ + deferReply() {} + reply() {} + fetchReply() {} + editReply() {} + deleteReply() {} + followUp() {} + showModal() {} + awaitModalSubmit() {} +} + +InteractionResponses.applyToClass(CommandInteraction, ['deferUpdate', 'update']); + +module.exports = CommandInteraction; + +/* eslint-disable max-len */ +/** + * @external APIInteractionDataResolved + * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-resolved-data-structure} + */ diff --git a/node_modules/discord.js/src/structures/CommandInteractionOptionResolver.js b/node_modules/discord.js/src/structures/CommandInteractionOptionResolver.js new file mode 100644 index 0000000..621dbf4 --- /dev/null +++ b/node_modules/discord.js/src/structures/CommandInteractionOptionResolver.js @@ -0,0 +1,308 @@ +'use strict'; + +const { ApplicationCommandOptionType } = require('discord-api-types/v10'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * A resolver for command interaction options. + */ +class CommandInteractionOptionResolver { + constructor(client, options, resolved) { + /** + * The client that instantiated this. + * @name CommandInteractionOptionResolver#client + * @type {Client} + * @readonly + */ + Object.defineProperty(this, 'client', { value: client }); + + /** + * The name of the subcommand group. + * @type {?string} + * @private + */ + this._group = null; + + /** + * The name of the subcommand. + * @type {?string} + * @private + */ + this._subcommand = null; + + /** + * The bottom-level options for the interaction. + * If there is a subcommand (or subcommand and group), this is the options for the subcommand. + * @type {CommandInteractionOption[]} + * @private + */ + this._hoistedOptions = options; + + // Hoist subcommand group if present + if (this._hoistedOptions[0]?.type === ApplicationCommandOptionType.SubcommandGroup) { + this._group = this._hoistedOptions[0].name; + this._hoistedOptions = this._hoistedOptions[0].options ?? []; + } + // Hoist subcommand if present + if (this._hoistedOptions[0]?.type === ApplicationCommandOptionType.Subcommand) { + this._subcommand = this._hoistedOptions[0].name; + this._hoistedOptions = this._hoistedOptions[0].options ?? []; + } + + /** + * The interaction options array. + * @name CommandInteractionOptionResolver#data + * @type {ReadonlyArray<CommandInteractionOption>} + * @readonly + */ + Object.defineProperty(this, 'data', { value: Object.freeze([...options]) }); + + /** + * The interaction resolved data + * @name CommandInteractionOptionResolver#resolved + * @type {?Readonly<CommandInteractionResolvedData>} + */ + Object.defineProperty(this, 'resolved', { value: resolved ? Object.freeze(resolved) : null }); + } + + /** + * Gets an option by its name. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?CommandInteractionOption} The option, if found. + */ + get(name, required = false) { + const option = this._hoistedOptions.find(opt => opt.name === name); + if (!option) { + if (required) { + throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionNotFound, name); + } + return null; + } + return option; + } + + /** + * Gets an option by name and property and checks its type. + * @param {string} name The name of the option. + * @param {ApplicationCommandOptionType[]} allowedTypes The allowed types of the option. + * @param {string[]} properties The properties to check for for `required`. + * @param {boolean} required Whether to throw an error if the option is not found. + * @returns {?CommandInteractionOption} The option, if found. + * @private + */ + _getTypedOption(name, allowedTypes, properties, required) { + const option = this.get(name, required); + if (!option) { + return null; + } else if (!allowedTypes.includes(option.type)) { + throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionType, name, option.type, allowedTypes.join(', ')); + } else if (required && properties.every(prop => option[prop] === null || option[prop] === undefined)) { + throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionEmpty, name, option.type); + } + return option; + } + + /** + * Gets the selected subcommand. + * @param {boolean} [required=true] Whether to throw an error if there is no subcommand. + * @returns {?string} The name of the selected subcommand, or null if not set and not required. + */ + getSubcommand(required = true) { + if (required && !this._subcommand) { + throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionNoSubcommand); + } + return this._subcommand; + } + + /** + * Gets the selected subcommand group. + * @param {boolean} [required=false] Whether to throw an error if there is no subcommand group. + * @returns {?string} The name of the selected subcommand group, or null if not set and not required. + */ + getSubcommandGroup(required = false) { + if (required && !this._group) { + throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionNoSubcommandGroup); + } + return this._group; + } + + /** + * Gets a boolean option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?boolean} The value of the option, or null if not set and not required. + */ + getBoolean(name, required = false) { + const option = this._getTypedOption(name, [ApplicationCommandOptionType.Boolean], ['value'], required); + return option?.value ?? null; + } + + /** + * Gets a channel option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @param {ChannelType[]} [channelTypes=[]] The allowed types of channels. If empty, all channel types are allowed. + * @returns {?(GuildChannel|ThreadChannel|APIChannel)} + * The value of the option, or null if not set and not required. + */ + getChannel(name, required = false, channelTypes = []) { + const option = this._getTypedOption(name, [ApplicationCommandOptionType.Channel], ['channel'], required); + const channel = option?.channel ?? null; + + if (channel && channelTypes.length > 0 && !channelTypes.includes(channel.type)) { + throw new DiscordjsTypeError( + ErrorCodes.CommandInteractionOptionInvalidChannelType, + name, + channel.type, + channelTypes.join(', '), + ); + } + + return channel; + } + + /** + * Gets a string option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?string} The value of the option, or null if not set and not required. + */ + getString(name, required = false) { + const option = this._getTypedOption(name, [ApplicationCommandOptionType.String], ['value'], required); + return option?.value ?? null; + } + + /** + * Gets an integer option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?number} The value of the option, or null if not set and not required. + */ + getInteger(name, required = false) { + const option = this._getTypedOption(name, [ApplicationCommandOptionType.Integer], ['value'], required); + return option?.value ?? null; + } + + /** + * Gets a number option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?number} The value of the option, or null if not set and not required. + */ + getNumber(name, required = false) { + const option = this._getTypedOption(name, [ApplicationCommandOptionType.Number], ['value'], required); + return option?.value ?? null; + } + + /** + * Gets a user option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?User} The value of the option, or null if not set and not required. + */ + getUser(name, required = false) { + const option = this._getTypedOption( + name, + [ApplicationCommandOptionType.User, ApplicationCommandOptionType.Mentionable], + ['user'], + required, + ); + return option?.user ?? null; + } + + /** + * Gets a member option. + * @param {string} name The name of the option. + * @returns {?(GuildMember|APIGuildMember)} + * The value of the option, or null if the user is not present in the guild or the option is not set. + */ + getMember(name) { + const option = this._getTypedOption( + name, + [ApplicationCommandOptionType.User, ApplicationCommandOptionType.Mentionable], + ['member'], + false, + ); + return option?.member ?? null; + } + + /** + * Gets a role option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?(Role|APIRole)} The value of the option, or null if not set and not required. + */ + getRole(name, required = false) { + const option = this._getTypedOption( + name, + [ApplicationCommandOptionType.Role, ApplicationCommandOptionType.Mentionable], + ['role'], + required, + ); + return option?.role ?? null; + } + + /** + * Gets an attachment option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?Attachment} The value of the option, or null if not set and not required. + */ + getAttachment(name, required = false) { + const option = this._getTypedOption(name, [ApplicationCommandOptionType.Attachment], ['attachment'], required); + return option?.attachment ?? null; + } + + /** + * Gets a mentionable option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?(User|GuildMember|APIGuildMember|Role|APIRole)} + * The value of the option, or null if not set and not required. + */ + getMentionable(name, required = false) { + const option = this._getTypedOption( + name, + [ApplicationCommandOptionType.Mentionable], + ['user', 'member', 'role'], + required, + ); + return option?.member ?? option?.user ?? option?.role ?? null; + } + + /** + * Gets a message option. + * @param {string} name The name of the option. + * @param {boolean} [required=false] Whether to throw an error if the option is not found. + * @returns {?Message} + * The value of the option, or null if not set and not required. + */ + getMessage(name, required = false) { + const option = this._getTypedOption(name, ['_MESSAGE'], ['message'], required); + return option?.message ?? null; + } + + /** + * The full autocomplete option object. + * @typedef {Object} AutocompleteFocusedOption + * @property {string} name The name of the option + * @property {ApplicationCommandOptionType} type The type of the application command option + * @property {string} value The value of the option + * @property {boolean} focused Whether this option is currently in focus for autocomplete + */ + + /** + * Gets the focused option. + * @param {boolean} [getFull=false] Whether to get the full option object + * @returns {string|AutocompleteFocusedOption} + * The value of the option, or the whole option if getFull is true + */ + getFocused(getFull = false) { + const focusedOption = this._hoistedOptions.find(option => option.focused); + if (!focusedOption) throw new DiscordjsTypeError(ErrorCodes.AutocompleteInteractionOptionNoFocusedOption); + return getFull ? focusedOption : focusedOption.value; + } +} + +module.exports = CommandInteractionOptionResolver; diff --git a/node_modules/discord.js/src/structures/Component.js b/node_modules/discord.js/src/structures/Component.js new file mode 100644 index 0000000..10ba27d --- /dev/null +++ b/node_modules/discord.js/src/structures/Component.js @@ -0,0 +1,47 @@ +'use strict'; + +const isEqual = require('fast-deep-equal'); + +/** + * Represents a component + */ +class Component { + constructor(data) { + /** + * The API data associated with this component + * @type {APIMessageComponent} + */ + this.data = data; + } + + /** + * The type of the component + * @type {ComponentType} + * @readonly + */ + get type() { + return this.data.type; + } + + /** + * Whether or not the given components are equal + * @param {Component|APIMessageComponent} other The component to compare against + * @returns {boolean} + */ + equals(other) { + if (other instanceof Component) { + return isEqual(other.data, this.data); + } + return isEqual(other, this.data); + } + + /** + * Returns the API-compatible JSON for this component + * @returns {APIMessageComponent} + */ + toJSON() { + return { ...this.data }; + } +} + +module.exports = Component; diff --git a/node_modules/discord.js/src/structures/ContextMenuCommandInteraction.js b/node_modules/discord.js/src/structures/ContextMenuCommandInteraction.js new file mode 100644 index 0000000..fc49ca5 --- /dev/null +++ b/node_modules/discord.js/src/structures/ContextMenuCommandInteraction.js @@ -0,0 +1,64 @@ +'use strict'; + +const { lazy } = require('@discordjs/util'); +const { ApplicationCommandOptionType } = require('discord-api-types/v10'); +const CommandInteraction = require('./CommandInteraction'); +const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver'); + +const getMessage = lazy(() => require('./Message').Message); + +/** + * Represents a context menu interaction. + * @extends {CommandInteraction} + */ +class ContextMenuCommandInteraction extends CommandInteraction { + constructor(client, data) { + super(client, data); + /** + * The target of the interaction, parsed into options + * @type {CommandInteractionOptionResolver} + */ + this.options = new CommandInteractionOptionResolver( + this.client, + this.resolveContextMenuOptions(data.data), + this.transformResolved(data.data.resolved), + ); + + /** + * The id of the target of this interaction + * @type {Snowflake} + */ + this.targetId = data.data.target_id; + } + + /** + * Resolves and transforms options received from the API for a context menu interaction. + * @param {APIApplicationCommandInteractionData} data The interaction data + * @returns {CommandInteractionOption[]} + * @private + */ + resolveContextMenuOptions({ target_id, resolved }) { + const result = []; + + if (resolved.users?.[target_id]) { + result.push( + this.transformOption({ name: 'user', type: ApplicationCommandOptionType.User, value: target_id }, resolved), + ); + } + + if (resolved.messages?.[target_id]) { + result.push({ + name: 'message', + type: '_MESSAGE', + value: target_id, + message: + this.channel?.messages._add(resolved.messages[target_id]) ?? + new (getMessage())(this.client, resolved.messages[target_id]), + }); + } + + return result; + } +} + +module.exports = ContextMenuCommandInteraction; diff --git a/node_modules/discord.js/src/structures/DMChannel.js b/node_modules/discord.js/src/structures/DMChannel.js new file mode 100644 index 0000000..2c917c4 --- /dev/null +++ b/node_modules/discord.js/src/structures/DMChannel.js @@ -0,0 +1,129 @@ +'use strict'; + +const { userMention } = require('@discordjs/builders'); +const { ChannelType } = require('discord-api-types/v10'); +const { BaseChannel } = require('./BaseChannel'); +const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const DMMessageManager = require('../managers/DMMessageManager'); +const Partials = require('../util/Partials'); + +/** + * Represents a direct message channel between two users. + * @extends {BaseChannel} + * @implements {TextBasedChannel} + */ +class DMChannel extends BaseChannel { + constructor(client, data) { + super(client, data); + + // Override the channel type so partials have a known type + this.type = ChannelType.DM; + + /** + * A manager of the messages belonging to this channel + * @type {DMMessageManager} + */ + this.messages = new DMMessageManager(this); + } + + _patch(data) { + super._patch(data); + + if (data.recipients) { + const recipient = data.recipients[0]; + + /** + * The recipient's id + * @type {Snowflake} + */ + this.recipientId = recipient.id; + + if ('username' in recipient || this.client.options.partials.includes(Partials.User)) { + this.client.users._add(recipient); + } + } + + if ('last_message_id' in data) { + /** + * The channel's last message id, if one was sent + * @type {?Snowflake} + */ + this.lastMessageId = data.last_message_id; + } + + if ('last_pin_timestamp' in data) { + /** + * The timestamp when the last pinned message was pinned, if there was one + * @type {?number} + */ + this.lastPinTimestamp = Date.parse(data.last_pin_timestamp); + } else { + this.lastPinTimestamp ??= null; + } + } + + /** + * Whether this DMChannel is a partial + * @type {boolean} + * @readonly + */ + get partial() { + return this.lastMessageId === undefined; + } + + /** + * The recipient on the other end of the DM + * @type {?User} + * @readonly + */ + get recipient() { + return this.client.users.resolve(this.recipientId); + } + + /** + * Fetch this DMChannel. + * @param {boolean} [force=true] Whether to skip the cache check and request the API + * @returns {Promise<DMChannel>} + */ + fetch(force = true) { + return this.client.users.createDM(this.recipientId, { force }); + } + + /** + * When concatenated with a string, this automatically returns the recipient's mention instead of the + * DMChannel object. + * @returns {string} + * @example + * // Logs: Hello from <@123456789012345678>! + * console.log(`Hello from ${channel}!`); + */ + toString() { + return userMention(this.recipientId); + } + + // These are here only for documentation purposes - they are implemented by TextBasedChannel + /* eslint-disable no-empty-function */ + get lastMessage() {} + get lastPinAt() {} + send() {} + sendTyping() {} + createMessageCollector() {} + awaitMessages() {} + createMessageComponentCollector() {} + awaitMessageComponent() {} + // Doesn't work on DM channels; bulkDelete() {} + // Doesn't work on DM channels; fetchWebhooks() {} + // Doesn't work on DM channels; createWebhook() {} + // Doesn't work on DM channels; setRateLimitPerUser() {} + // Doesn't work on DM channels; setNSFW() {} +} + +TextBasedChannel.applyToClass(DMChannel, true, [ + 'bulkDelete', + 'fetchWebhooks', + 'createWebhook', + 'setRateLimitPerUser', + 'setNSFW', +]); + +module.exports = DMChannel; diff --git a/node_modules/discord.js/src/structures/DirectoryChannel.js b/node_modules/discord.js/src/structures/DirectoryChannel.js new file mode 100644 index 0000000..870eff9 --- /dev/null +++ b/node_modules/discord.js/src/structures/DirectoryChannel.js @@ -0,0 +1,36 @@ +'use strict'; + +const { BaseChannel } = require('./BaseChannel'); + +/** + * Represents a channel that displays a directory of guilds. + * @extends {BaseChannel} + */ +class DirectoryChannel extends BaseChannel { + constructor(guild, data, client) { + super(client, data); + + /** + * The guild the channel is in + * @type {InviteGuild} + */ + this.guild = guild; + + /** + * The id of the guild the channel is in + * @type {Snowflake} + */ + this.guildId = guild.id; + } + + _patch(data) { + super._patch(data); + /** + * The channel's name + * @type {string} + */ + this.name = data.name; + } +} + +module.exports = DirectoryChannel; diff --git a/node_modules/discord.js/src/structures/Embed.js b/node_modules/discord.js/src/structures/Embed.js new file mode 100644 index 0000000..dd68120 --- /dev/null +++ b/node_modules/discord.js/src/structures/Embed.js @@ -0,0 +1,220 @@ +'use strict'; + +const { embedLength } = require('@discordjs/builders'); +const isEqual = require('fast-deep-equal'); + +/** + * Represents an embed. + */ +class Embed { + constructor(data) { + /** + * The API embed data. + * @type {APIEmbed} + * @readonly + */ + this.data = { ...data }; + } + + /** + * An array of fields of this embed. + * @type {Array<APIEmbedField>} + * @readonly + */ + get fields() { + return this.data.fields ?? []; + } + + /** + * The title of this embed. + * @type {?string} + * @readonly + */ + get title() { + return this.data.title ?? null; + } + + /** + * The description of this embed. + * @type {?string} + * @readonly + */ + get description() { + return this.data.description ?? null; + } + + /** + * The URL of this embed. + * @type {?string} + * @readonly + */ + get url() { + return this.data.url ?? null; + } + + /** + * The color of this embed. + * @type {?number} + * @readonly + */ + get color() { + return this.data.color ?? null; + } + + /** + * The timestamp of this embed. This is in an ISO 8601 format. + * @type {?string} + * @readonly + */ + get timestamp() { + return this.data.timestamp ?? null; + } + + /** + * @typedef {Object} EmbedAssetData + * @property {?string} url The URL of the image + * @property {?string} proxyURL The proxy URL of the image + * @property {?number} height The height of the image + * @property {?number} width The width of the image + */ + + /** + * The thumbnail of this embed. + * @type {?EmbedAssetData} + * @readonly + */ + get thumbnail() { + if (!this.data.thumbnail) return null; + return { + url: this.data.thumbnail.url, + proxyURL: this.data.thumbnail.proxy_url, + height: this.data.thumbnail.height, + width: this.data.thumbnail.width, + }; + } + + /** + * The image of this embed. + * @type {?EmbedAssetData} + * @readonly + */ + get image() { + if (!this.data.image) return null; + return { + url: this.data.image.url, + proxyURL: this.data.image.proxy_url, + height: this.data.image.height, + width: this.data.image.width, + }; + } + + /** + * The video of this embed. + * @type {?EmbedAssetData} + * @readonly + */ + get video() { + if (!this.data.video) return null; + return { + url: this.data.video.url, + proxyURL: this.data.video.proxy_url, + height: this.data.video.height, + width: this.data.video.width, + }; + } + + /** + * @typedef {Object} EmbedAuthorData + * @property {string} name The name of the author + * @property {?string} url The URL of the author + * @property {?string} iconURL The icon URL of the author + * @property {?string} proxyIconURL The proxy icon URL of the author + */ + + /** + * The author of this embed. + * @type {?EmbedAuthorData} + * @readonly + */ + get author() { + if (!this.data.author) return null; + return { + name: this.data.author.name, + url: this.data.author.url, + iconURL: this.data.author.icon_url, + proxyIconURL: this.data.author.proxy_icon_url, + }; + } + + /** + * The provider of this embed. + * @type {?APIEmbedProvider} + * @readonly + */ + get provider() { + return this.data.provider ?? null; + } + + /** + * @typedef {Object} EmbedFooterData + * @property {string} text The text of the footer + * @property {?string} iconURL The URL of the icon + * @property {?string} proxyIconURL The proxy URL of the icon + */ + + /** + * The footer of this embed. + * @type {?EmbedFooterData} + * @readonly + */ + get footer() { + if (!this.data.footer) return null; + return { + text: this.data.footer.text, + iconURL: this.data.footer.icon_url, + proxyIconURL: this.data.footer.proxy_icon_url, + }; + } + + /** + * The accumulated length for the embed title, description, fields, footer text, and author name. + * @type {number} + * @readonly + */ + get length() { + return embedLength(this.data); + } + + /** + * The hex color of this embed. + * @type {?string} + * @readonly + */ + get hexColor() { + return typeof this.data.color === 'number' + ? `#${this.data.color.toString(16).padStart(6, '0')}` + : this.data.color ?? null; + } + + /** + * Returns the API-compatible JSON for this embed. + * @returns {APIEmbed} + */ + toJSON() { + return { ...this.data }; + } + + /** + * Whether the given embeds are equal. + * @param {Embed|APIEmbed} other The embed to compare against + * @returns {boolean} + */ + equals(other) { + if (other instanceof Embed) { + return isEqual(other.data, this.data); + } + return isEqual(other, this.data); + } +} + +module.exports = Embed; diff --git a/node_modules/discord.js/src/structures/EmbedBuilder.js b/node_modules/discord.js/src/structures/EmbedBuilder.js new file mode 100644 index 0000000..10e445c --- /dev/null +++ b/node_modules/discord.js/src/structures/EmbedBuilder.js @@ -0,0 +1,50 @@ +'use strict'; + +const { EmbedBuilder: BuildersEmbed, embedLength } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { toSnakeCase } = require('../util/Transformers'); +const { resolveColor } = require('../util/Util'); + +/** + * Represents an embed builder. + * @extends {BuildersEmbed} + */ +class EmbedBuilder extends BuildersEmbed { + constructor(data) { + super(toSnakeCase(data)); + } + + /** + * Sets the color of this embed + * @param {?ColorResolvable} color The color of the embed + * @returns {EmbedBuilder} + */ + setColor(color) { + return super.setColor(color && resolveColor(color)); + } + + /** + * Creates a new embed builder from JSON data + * @param {EmbedBuilder|Embed|APIEmbed} other The other data + * @returns {EmbedBuilder} + */ + static from(other) { + return new this(isJSONEncodable(other) ? other.toJSON() : other); + } + + /** + * The accumulated length for the embed title, description, fields, footer text, and author name. + * @type {number} + * @readonly + */ + get length() { + return embedLength(this.data); + } +} + +module.exports = EmbedBuilder; + +/** + * @external BuildersEmbed + * @see {@link https://discord.js.org/docs/packages/builders/stable/EmbedBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/Emoji.js b/node_modules/discord.js/src/structures/Emoji.js new file mode 100644 index 0000000..409d292 --- /dev/null +++ b/node_modules/discord.js/src/structures/Emoji.js @@ -0,0 +1,108 @@ +'use strict'; + +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const Base = require('./Base'); + +/** + * Represents raw emoji data from the API + * @typedef {APIEmoji} RawEmoji + * @property {?Snowflake} id The emoji's id + * @property {?string} name The emoji's name + * @property {?boolean} animated Whether the emoji is animated + */ + +/** + * Represents an emoji, see {@link GuildEmoji} and {@link ReactionEmoji}. + * @extends {Base} + */ +class Emoji extends Base { + constructor(client, emoji) { + super(client); + /** + * Whether or not the emoji is animated + * @type {?boolean} + */ + this.animated = emoji.animated ?? null; + + /** + * The emoji's name + * @type {?string} + */ + this.name = emoji.name ?? null; + + /** + * The emoji's id + * @type {?Snowflake} + */ + this.id = emoji.id; + } + + /** + * The identifier of this emoji, used for message reactions + * @type {string} + * @readonly + */ + get identifier() { + if (this.id) return `${this.animated ? 'a:' : ''}${this.name}:${this.id}`; + return encodeURIComponent(this.name); + } + + /** + * The URL to the emoji file if it's a custom emoji + * @type {?string} + * @readonly + */ + get url() { + return this.id && this.client.rest.cdn.emoji(this.id, this.animated ? 'gif' : 'png'); + } + + /** + * The timestamp the emoji was created at, or null if unicode + * @type {?number} + * @readonly + */ + get createdTimestamp() { + return this.id && DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the emoji was created at, or null if unicode + * @type {?Date} + * @readonly + */ + get createdAt() { + return this.id && new Date(this.createdTimestamp); + } + + /** + * When concatenated with a string, this automatically returns the text required to form a graphical emoji on Discord + * instead of the Emoji object. + * @returns {string} + * @example + * // Send a custom emoji from a guild: + * const emoji = guild.emojis.cache.first(); + * msg.channel.send(`Hello! ${emoji}`); + * @example + * // Send the emoji used in a reaction to the channel the reaction is part of + * reaction.message.channel.send(`The emoji used was: ${reaction.emoji}`); + */ + toString() { + return this.id ? `<${this.animated ? 'a' : ''}:${this.name}:${this.id}>` : this.name; + } + + toJSON() { + return super.toJSON({ + guild: 'guildId', + createdTimestamp: true, + url: true, + identifier: true, + }); + } +} + +exports.Emoji = Emoji; + +/** + * @external APIEmoji + * @see {@link https://discord.com/developers/docs/resources/emoji#emoji-object} + */ diff --git a/node_modules/discord.js/src/structures/ForumChannel.js b/node_modules/discord.js/src/structures/ForumChannel.js new file mode 100644 index 0000000..87e6478 --- /dev/null +++ b/node_modules/discord.js/src/structures/ForumChannel.js @@ -0,0 +1,264 @@ +'use strict'; + +const GuildChannel = require('./GuildChannel'); +const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const GuildForumThreadManager = require('../managers/GuildForumThreadManager'); +const { transformAPIGuildForumTag, transformAPIGuildDefaultReaction } = require('../util/Channels'); + +/** + * @typedef {Object} GuildForumTagEmoji + * @property {?Snowflake} id The id of a guild's custom emoji + * @property {?string} name The unicode character of the emoji + */ + +/** + * @typedef {Object} GuildForumTag + * @property {Snowflake} id The id of the tag + * @property {string} name The name of the tag + * @property {boolean} moderated Whether this tag can only be added to or removed from threads + * by a member with the `ManageThreads` permission + * @property {?GuildForumTagEmoji} emoji The emoji of this tag + */ + +/** + * @typedef {Object} GuildForumTagData + * @property {Snowflake} [id] The id of the tag + * @property {string} name The name of the tag + * @property {boolean} [moderated] Whether this tag can only be added to or removed from threads + * by a member with the `ManageThreads` permission + * @property {?GuildForumTagEmoji} [emoji] The emoji of this tag + */ + +/** + * @typedef {Object} DefaultReactionEmoji + * @property {?Snowflake} id The id of a guild's custom emoji + * @property {?string} name The unicode character of the emoji + */ + +/** + * Represents a channel that only contains threads + * @extends {GuildChannel} + * @implements {TextBasedChannel} + */ +class ForumChannel extends GuildChannel { + constructor(guild, data, client) { + super(guild, data, client, false); + + /** + * A manager of the threads belonging to this channel + * @type {GuildForumThreadManager} + */ + this.threads = new GuildForumThreadManager(this); + + this._patch(data); + } + + _patch(data) { + super._patch(data); + if ('available_tags' in data) { + /** + * The set of tags that can be used in this channel. + * @type {GuildForumTag[]} + */ + this.availableTags = data.available_tags.map(tag => transformAPIGuildForumTag(tag)); + } else { + this.availableTags ??= []; + } + + if ('default_reaction_emoji' in data) { + /** + * The emoji to show in the add reaction button on a thread in a guild forum channel + * @type {?DefaultReactionEmoji} + */ + this.defaultReactionEmoji = data.default_reaction_emoji + ? transformAPIGuildDefaultReaction(data.default_reaction_emoji) + : null; + } else { + this.defaultReactionEmoji ??= null; + } + + if ('default_thread_rate_limit_per_user' in data) { + /** + * The initial rate limit per user (slowmode) to set on newly created threads in a channel. + * @type {?number} + */ + this.defaultThreadRateLimitPerUser = data.default_thread_rate_limit_per_user; + } else { + this.defaultThreadRateLimitPerUser ??= null; + } + + if ('rate_limit_per_user' in data) { + /** + * The rate limit per user (slowmode) for this channel. + * @type {?number} + */ + this.rateLimitPerUser = data.rate_limit_per_user; + } else { + this.rateLimitPerUser ??= null; + } + + if ('default_auto_archive_duration' in data) { + /** + * The default auto archive duration for newly created threads in this channel. + * @type {?ThreadAutoArchiveDuration} + */ + this.defaultAutoArchiveDuration = data.default_auto_archive_duration; + } else { + this.defaultAutoArchiveDuration ??= null; + } + + if ('nsfw' in data) { + /** + * If this channel is considered NSFW. + * @type {boolean} + */ + this.nsfw = data.nsfw; + } else { + this.nsfw ??= false; + } + + if ('topic' in data) { + /** + * The topic of this channel. + * @type {?string} + */ + this.topic = data.topic; + } + + if ('default_sort_order' in data) { + /** + * The default sort order mode used to order posts + * @type {?SortOrderType} + */ + this.defaultSortOrder = data.default_sort_order; + } else { + this.defaultSortOrder ??= null; + } + + /** + * The default layout type used to display posts + * @type {ForumLayoutType} + */ + this.defaultForumLayout = data.default_forum_layout; + } + + /** + * Sets the available tags for this forum channel + * @param {GuildForumTagData[]} availableTags The tags to set as available in this channel + * @param {string} [reason] Reason for changing the available tags + * @returns {Promise<ForumChannel>} + */ + setAvailableTags(availableTags, reason) { + return this.edit({ availableTags, reason }); + } + + /** + * Sets the default reaction emoji for this channel + * @param {?DefaultReactionEmoji} defaultReactionEmoji The emoji to set as the default reaction emoji + * @param {string} [reason] Reason for changing the default reaction emoji + * @returns {Promise<ForumChannel>} + */ + setDefaultReactionEmoji(defaultReactionEmoji, reason) { + return this.edit({ defaultReactionEmoji, reason }); + } + + /** + * Sets the default rate limit per user (slowmode) for new threads in this channel + * @param {number} defaultThreadRateLimitPerUser The rate limit to set on newly created threads in this channel + * @param {string} [reason] Reason for changing the default rate limit + * @returns {Promise<ForumChannel>} + */ + setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser, reason) { + return this.edit({ defaultThreadRateLimitPerUser, reason }); + } + + /** + * Creates an invite to this guild channel. + * @param {InviteCreateOptions} [options={}] The options for creating the invite + * @returns {Promise<Invite>} + * @example + * // Create an invite to a channel + * channel.createInvite() + * .then(invite => console.log(`Created an invite with a code of ${invite.code}`)) + * .catch(console.error); + */ + createInvite(options) { + return this.guild.invites.create(this.id, options); + } + + /** + * Fetches a collection of invites to this guild channel. + * Resolves with a collection mapping invites by their codes. + * @param {boolean} [cache=true] Whether to cache the fetched invites + * @returns {Promise<Collection<string, Invite>>} + */ + fetchInvites(cache) { + return this.guild.invites.fetch({ channelId: this.id, cache }); + } + + /** + * Sets the default auto archive duration for all newly created threads in this channel. + * @param {ThreadAutoArchiveDuration} defaultAutoArchiveDuration The new default auto archive duration + * @param {string} [reason] Reason for changing the channel's default auto archive duration + * @returns {Promise<ForumChannel>} + */ + setDefaultAutoArchiveDuration(defaultAutoArchiveDuration, reason) { + return this.edit({ defaultAutoArchiveDuration, reason }); + } + + /** + * Sets a new topic for the guild channel. + * @param {?string} topic The new topic for the guild channel + * @param {string} [reason] Reason for changing the guild channel's topic + * @returns {Promise<ForumChannel>} + * @example + * // Set a new channel topic + * channel.setTopic('needs more rate limiting') + * .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`)) + * .catch(console.error); + */ + setTopic(topic, reason) { + return this.edit({ topic, reason }); + } + + /** + * Sets the default sort order mode used to order posts + * @param {?SortOrderType} defaultSortOrder The default sort order mode to set on this channel + * @param {string} [reason] Reason for changing the default sort order + * @returns {Promise<ForumChannel>} + */ + setDefaultSortOrder(defaultSortOrder, reason) { + return this.edit({ defaultSortOrder, reason }); + } + + /** + * Sets the default forum layout type used to display posts + * @param {ForumLayoutType} defaultForumLayout The default forum layout type to set on this channel + * @param {string} [reason] Reason for changing the default forum layout + * @returns {Promise<ForumChannel>} + */ + setDefaultForumLayout(defaultForumLayout, reason) { + return this.edit({ defaultForumLayout, reason }); + } + + // These are here only for documentation purposes - they are implemented by TextBasedChannel + /* eslint-disable no-empty-function */ + createWebhook() {} + fetchWebhooks() {} + setNSFW() {} + setRateLimitPerUser() {} +} + +TextBasedChannel.applyToClass(ForumChannel, true, [ + 'send', + 'lastMessage', + 'lastPinAt', + 'bulkDelete', + 'sendTyping', + 'createMessageCollector', + 'awaitMessages', + 'createMessageComponentCollector', + 'awaitMessageComponent', +]); + +module.exports = ForumChannel; diff --git a/node_modules/discord.js/src/structures/Guild.js b/node_modules/discord.js/src/structures/Guild.js new file mode 100644 index 0000000..f07e9b4 --- /dev/null +++ b/node_modules/discord.js/src/structures/Guild.js @@ -0,0 +1,1367 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { makeURLSearchParams } = require('@discordjs/rest'); +const { ChannelType, GuildPremiumTier, Routes, GuildFeature } = require('discord-api-types/v10'); +const AnonymousGuild = require('./AnonymousGuild'); +const GuildAuditLogs = require('./GuildAuditLogs'); +const { GuildOnboarding } = require('./GuildOnboarding'); +const GuildPreview = require('./GuildPreview'); +const GuildTemplate = require('./GuildTemplate'); +const Integration = require('./Integration'); +const Webhook = require('./Webhook'); +const WelcomeScreen = require('./WelcomeScreen'); +const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors'); +const AutoModerationRuleManager = require('../managers/AutoModerationRuleManager'); +const GuildApplicationCommandManager = require('../managers/GuildApplicationCommandManager'); +const GuildBanManager = require('../managers/GuildBanManager'); +const GuildChannelManager = require('../managers/GuildChannelManager'); +const GuildEmojiManager = require('../managers/GuildEmojiManager'); +const GuildInviteManager = require('../managers/GuildInviteManager'); +const GuildMemberManager = require('../managers/GuildMemberManager'); +const GuildScheduledEventManager = require('../managers/GuildScheduledEventManager'); +const GuildStickerManager = require('../managers/GuildStickerManager'); +const PresenceManager = require('../managers/PresenceManager'); +const RoleManager = require('../managers/RoleManager'); +const StageInstanceManager = require('../managers/StageInstanceManager'); +const VoiceStateManager = require('../managers/VoiceStateManager'); +const DataResolver = require('../util/DataResolver'); +const Status = require('../util/Status'); +const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField'); +const { discordSort, getSortableGroupTypes } = require('../util/Util'); + +/** + * Represents a guild (or a server) on Discord. + * <info>It's recommended to see if a guild is available before performing operations or reading data from it. You can + * check this with {@link Guild#available}.</info> + * @extends {AnonymousGuild} + */ +class Guild extends AnonymousGuild { + constructor(client, data) { + super(client, data, false); + + /** + * A manager of the application commands belonging to this guild + * @type {GuildApplicationCommandManager} + */ + this.commands = new GuildApplicationCommandManager(this); + + /** + * A manager of the members belonging to this guild + * @type {GuildMemberManager} + */ + this.members = new GuildMemberManager(this); + + /** + * A manager of the channels belonging to this guild + * @type {GuildChannelManager} + */ + this.channels = new GuildChannelManager(this); + + /** + * A manager of the bans belonging to this guild + * @type {GuildBanManager} + */ + this.bans = new GuildBanManager(this); + + /** + * A manager of the roles belonging to this guild + * @type {RoleManager} + */ + this.roles = new RoleManager(this); + + /** + * A manager of the presences belonging to this guild + * @type {PresenceManager} + */ + this.presences = new PresenceManager(this.client); + + /** + * A manager of the voice states of this guild + * @type {VoiceStateManager} + */ + this.voiceStates = new VoiceStateManager(this); + + /** + * A manager of the stage instances of this guild + * @type {StageInstanceManager} + */ + this.stageInstances = new StageInstanceManager(this); + + /** + * A manager of the invites of this guild + * @type {GuildInviteManager} + */ + this.invites = new GuildInviteManager(this); + + /** + * A manager of the scheduled events of this guild + * @type {GuildScheduledEventManager} + */ + this.scheduledEvents = new GuildScheduledEventManager(this); + + /** + * A manager of the auto moderation rules of this guild. + * @type {AutoModerationRuleManager} + */ + this.autoModerationRules = new AutoModerationRuleManager(this); + + if (!data) return; + if (data.unavailable) { + /** + * Whether the guild is available to access. If it is not available, it indicates a server outage + * @type {boolean} + */ + this.available = false; + } else { + this._patch(data); + if (!data.channels) this.available = false; + } + + /** + * The id of the shard this Guild belongs to. + * @type {number} + */ + this.shardId = data.shardId; + } + + /** + * The Shard this Guild belongs to. + * @type {WebSocketShard} + * @readonly + */ + get shard() { + return this.client.ws.shards.get(this.shardId); + } + + _patch(data) { + super._patch(data); + this.id = data.id; + if ('name' in data) this.name = data.name; + if ('icon' in data) this.icon = data.icon; + if ('unavailable' in data) { + this.available = !data.unavailable; + } else { + this.available ??= true; + } + + if ('discovery_splash' in data) { + /** + * The hash of the guild discovery splash image + * @type {?string} + */ + this.discoverySplash = data.discovery_splash; + } + + if ('member_count' in data) { + /** + * The full amount of members in this guild + * @type {number} + */ + this.memberCount = data.member_count; + } + + if ('large' in data) { + /** + * Whether the guild is "large" (has more than {@link WebsocketOptions large_threshold} members, 50 by default) + * @type {boolean} + */ + this.large = Boolean(data.large); + } + + if ('premium_progress_bar_enabled' in data) { + /** + * Whether this guild has its premium (boost) progress bar enabled + * @type {boolean} + */ + this.premiumProgressBarEnabled = data.premium_progress_bar_enabled; + } + + if ('application_id' in data) { + /** + * The id of the application that created this guild (if applicable) + * @type {?Snowflake} + */ + this.applicationId = data.application_id; + } + + if ('afk_timeout' in data) { + /** + * The time in seconds before a user is counted as "away from keyboard" + * @type {?number} + */ + this.afkTimeout = data.afk_timeout; + } + + if ('afk_channel_id' in data) { + /** + * The id of the voice channel where AFK members are moved + * @type {?Snowflake} + */ + this.afkChannelId = data.afk_channel_id; + } + + if ('system_channel_id' in data) { + /** + * The system channel's id + * @type {?Snowflake} + */ + this.systemChannelId = data.system_channel_id; + } + + if ('premium_tier' in data) { + /** + * The premium tier of this guild + * @type {GuildPremiumTier} + */ + this.premiumTier = data.premium_tier; + } + + if ('widget_enabled' in data) { + /** + * Whether widget images are enabled on this guild + * @type {?boolean} + */ + this.widgetEnabled = data.widget_enabled; + } else { + this.widgetEnabled ??= null; + } + + if ('widget_channel_id' in data) { + /** + * The widget channel's id, if enabled + * @type {?string} + */ + this.widgetChannelId = data.widget_channel_id; + } else { + this.widgetChannelId ??= null; + } + + if ('explicit_content_filter' in data) { + /** + * The explicit content filter level of the guild + * @type {GuildExplicitContentFilter} + */ + this.explicitContentFilter = data.explicit_content_filter; + } + + if ('mfa_level' in data) { + /** + * The required MFA level for this guild + * @type {GuildMFALevel} + */ + this.mfaLevel = data.mfa_level; + } + + if ('joined_at' in data) { + /** + * The timestamp the client user joined the guild at + * @type {number} + */ + this.joinedTimestamp = Date.parse(data.joined_at); + } + + if ('default_message_notifications' in data) { + /** + * The default message notification level of the guild + * @type {GuildDefaultMessageNotifications} + */ + this.defaultMessageNotifications = data.default_message_notifications; + } + + if ('system_channel_flags' in data) { + /** + * The value set for the guild's system channel flags + * @type {Readonly<SystemChannelFlagsBitField>} + */ + this.systemChannelFlags = new SystemChannelFlagsBitField(data.system_channel_flags).freeze(); + } + + if ('max_members' in data) { + /** + * The maximum amount of members the guild can have + * @type {?number} + */ + this.maximumMembers = data.max_members; + } else { + this.maximumMembers ??= null; + } + + if ('max_presences' in data) { + /** + * The maximum amount of presences the guild can have (this is `null` for all but the largest of guilds) + * <info>You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter</info> + * @type {?number} + */ + this.maximumPresences = data.max_presences; + } else { + this.maximumPresences ??= null; + } + + if ('max_video_channel_users' in data) { + /** + * The maximum amount of users allowed in a video channel. + * @type {?number} + */ + this.maxVideoChannelUsers = data.max_video_channel_users; + } else { + this.maxVideoChannelUsers ??= null; + } + + if ('max_stage_video_channel_users' in data) { + /** + * The maximum amount of users allowed in a stage video channel. + * @type {?number} + */ + this.maxStageVideoChannelUsers = data.max_stage_video_channel_users; + } else { + this.maxStageVideoChannelUsers ??= null; + } + + if ('approximate_member_count' in data) { + /** + * The approximate amount of members the guild has + * <info>You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter</info> + * @type {?number} + */ + this.approximateMemberCount = data.approximate_member_count; + } else { + this.approximateMemberCount ??= null; + } + + if ('approximate_presence_count' in data) { + /** + * The approximate amount of presences the guild has + * <info>You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter</info> + * @type {?number} + */ + this.approximatePresenceCount = data.approximate_presence_count; + } else { + this.approximatePresenceCount ??= null; + } + + /** + * The use count of the vanity URL code of the guild, if any + * <info>You will need to fetch this parameter using {@link Guild#fetchVanityData} if you want to receive it</info> + * @type {?number} + */ + this.vanityURLUses ??= null; + + if ('rules_channel_id' in data) { + /** + * The rules channel's id for the guild + * @type {?Snowflake} + */ + this.rulesChannelId = data.rules_channel_id; + } + + if ('public_updates_channel_id' in data) { + /** + * The community updates channel's id for the guild + * @type {?Snowflake} + */ + this.publicUpdatesChannelId = data.public_updates_channel_id; + } + + if ('preferred_locale' in data) { + /** + * The preferred locale of the guild, defaults to `en-US` + * @type {Locale} + */ + this.preferredLocale = data.preferred_locale; + } + + if ('safety_alerts_channel_id' in data) { + /** + * The safety alerts channel's id for the guild + * @type {?Snowflake} + */ + this.safetyAlertsChannelId = data.safety_alerts_channel_id; + } else { + this.safetyAlertsChannelId ??= null; + } + + if (data.channels) { + this.channels.cache.clear(); + for (const rawChannel of data.channels) { + this.client.channels._add(rawChannel, this); + } + } + + if (data.threads) { + for (const rawThread of data.threads) { + this.client.channels._add(rawThread, this); + } + } + + if (data.roles) { + this.roles.cache.clear(); + for (const role of data.roles) this.roles._add(role); + } + + if (data.members) { + this.members.cache.clear(); + for (const guildUser of data.members) this.members._add(guildUser); + } + + if ('owner_id' in data) { + /** + * The user id of this guild's owner + * @type {Snowflake} + */ + this.ownerId = data.owner_id; + } + + if (data.presences) { + for (const presence of data.presences) { + this.presences._add(Object.assign(presence, { guild: this })); + } + } + + if (data.stage_instances) { + this.stageInstances.cache.clear(); + for (const stageInstance of data.stage_instances) { + this.stageInstances._add(stageInstance); + } + } + + if (data.guild_scheduled_events) { + this.scheduledEvents.cache.clear(); + for (const scheduledEvent of data.guild_scheduled_events) { + this.scheduledEvents._add(scheduledEvent); + } + } + + if (data.voice_states) { + this.voiceStates.cache.clear(); + for (const voiceState of data.voice_states) { + this.voiceStates._add(voiceState); + } + } + + if (!this.emojis) { + /** + * A manager of the emojis belonging to this guild + * @type {GuildEmojiManager} + */ + this.emojis = new GuildEmojiManager(this); + if (data.emojis) for (const emoji of data.emojis) this.emojis._add(emoji); + } else if (data.emojis) { + this.client.actions.GuildEmojisUpdate.handle({ + guild_id: this.id, + emojis: data.emojis, + }); + } + + if (!this.stickers) { + /** + * A manager of the stickers belonging to this guild + * @type {GuildStickerManager} + */ + this.stickers = new GuildStickerManager(this); + if (data.stickers) for (const sticker of data.stickers) this.stickers._add(sticker); + } else if (data.stickers) { + this.client.actions.GuildStickersUpdate.handle({ + guild_id: this.id, + stickers: data.stickers, + }); + } + } + + /** + * The time the client user joined the guild + * @type {Date} + * @readonly + */ + get joinedAt() { + return new Date(this.joinedTimestamp); + } + + /** + * The URL to this guild's discovery splash image. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + discoverySplashURL(options = {}) { + return this.discoverySplash && this.client.rest.cdn.discoverySplash(this.id, this.discoverySplash, options); + } + + /** + * Fetches the owner of the guild. + * If the member object isn't needed, use {@link Guild#ownerId} instead. + * @param {BaseFetchOptions} [options] The options for fetching the member + * @returns {Promise<GuildMember>} + */ + async fetchOwner(options) { + if (!this.ownerId) { + throw new DiscordjsError(ErrorCodes.FetchOwnerId); + } + const member = await this.members.fetch({ ...options, user: this.ownerId }); + return member; + } + + /** + * AFK voice channel for this guild + * @type {?VoiceChannel} + * @readonly + */ + get afkChannel() { + return this.client.channels.resolve(this.afkChannelId); + } + + /** + * System channel for this guild + * @type {?TextChannel} + * @readonly + */ + get systemChannel() { + return this.client.channels.resolve(this.systemChannelId); + } + + /** + * Widget channel for this guild + * @type {?(TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel)} + * @readonly + */ + get widgetChannel() { + return this.client.channels.resolve(this.widgetChannelId); + } + + /** + * Rules channel for this guild + * @type {?TextChannel} + * @readonly + */ + get rulesChannel() { + return this.client.channels.resolve(this.rulesChannelId); + } + + /** + * Public updates channel for this guild + * @type {?TextChannel} + * @readonly + */ + get publicUpdatesChannel() { + return this.client.channels.resolve(this.publicUpdatesChannelId); + } + + /** + * Safety alerts channel for this guild + * @type {?TextChannel} + * @readonly + */ + get safetyAlertsChannel() { + return this.client.channels.resolve(this.safetyAlertsChannelId); + } + + /** + * The maximum bitrate available for this guild + * @type {number} + * @readonly + */ + get maximumBitrate() { + if (this.features.includes(GuildFeature.VIPRegions)) { + return 384_000; + } + + switch (this.premiumTier) { + case GuildPremiumTier.Tier1: + return 128_000; + case GuildPremiumTier.Tier2: + return 256_000; + case GuildPremiumTier.Tier3: + return 384_000; + default: + return 96_000; + } + } + + /** + * Fetches a collection of integrations to this guild. + * Resolves with a collection mapping integrations by their ids. + * @returns {Promise<Collection<Snowflake|string, Integration>>} + * @example + * // Fetch integrations + * guild.fetchIntegrations() + * .then(integrations => console.log(`Fetched ${integrations.size} integrations`)) + * .catch(console.error); + */ + async fetchIntegrations() { + const data = await this.client.rest.get(Routes.guildIntegrations(this.id)); + return data.reduce( + (collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)), + new Collection(), + ); + } + + /** + * Fetches a collection of templates from this guild. + * Resolves with a collection mapping templates by their codes. + * @returns {Promise<Collection<string, GuildTemplate>>} + */ + async fetchTemplates() { + const templates = await this.client.rest.get(Routes.guildTemplates(this.id)); + return templates.reduce((col, data) => col.set(data.code, new GuildTemplate(this.client, data)), new Collection()); + } + + /** + * Fetches the welcome screen for this guild. + * @returns {Promise<WelcomeScreen>} + */ + async fetchWelcomeScreen() { + const data = await this.client.rest.get(Routes.guildWelcomeScreen(this.id)); + return new WelcomeScreen(this, data); + } + + /** + * Creates a template for the guild. + * @param {string} name The name for the template + * @param {string} [description] The description for the template + * @returns {Promise<GuildTemplate>} + */ + async createTemplate(name, description) { + const data = await this.client.rest.post(Routes.guildTemplates(this.id), { body: { name, description } }); + return new GuildTemplate(this.client, data); + } + + /** + * Obtains a guild preview for this guild from Discord. + * @returns {Promise<GuildPreview>} + */ + async fetchPreview() { + const data = await this.client.rest.get(Routes.guildPreview(this.id)); + return new GuildPreview(this.client, data); + } + + /** + * An object containing information about a guild's vanity invite. + * @typedef {Object} Vanity + * @property {?string} code Vanity invite code + * @property {number} uses How many times this invite has been used + */ + + /** + * Fetches the vanity URL invite object to this guild. + * Resolves with an object containing the vanity URL invite code and the use count + * @returns {Promise<Vanity>} + * @example + * // Fetch invite data + * guild.fetchVanityData() + * .then(res => { + * console.log(`Vanity URL: https://discord.gg/${res.code} with ${res.uses} uses`); + * }) + * .catch(console.error); + */ + async fetchVanityData() { + const data = await this.client.rest.get(Routes.guildVanityUrl(this.id)); + this.vanityURLCode = data.code; + this.vanityURLUses = data.uses; + + return data; + } + + /** + * Fetches all webhooks for the guild. + * @returns {Promise<Collection<Snowflake, Webhook>>} + * @example + * // Fetch webhooks + * guild.fetchWebhooks() + * .then(webhooks => console.log(`Fetched ${webhooks.size} webhooks`)) + * .catch(console.error); + */ + async fetchWebhooks() { + const apiHooks = await this.client.rest.get(Routes.guildWebhooks(this.id)); + const hooks = new Collection(); + for (const hook of apiHooks) hooks.set(hook.id, new Webhook(this.client, hook)); + return hooks; + } + + /** + * Fetches the guild widget data, requires the widget to be enabled. + * @returns {Promise<Widget>} + * @example + * // Fetches the guild widget data + * guild.fetchWidget() + * .then(widget => console.log(`The widget shows ${widget.channels.size} channels`)) + * .catch(console.error); + */ + fetchWidget() { + return this.client.fetchGuildWidget(this.id); + } + + /** + * Data for the Guild Widget Settings object + * @typedef {Object} GuildWidgetSettings + * @property {boolean} enabled Whether the widget is enabled + * @property {?(TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel)} channel The widget invite channel + */ + + /** + * The Guild Widget Settings object + * @typedef {Object} GuildWidgetSettingsData + * @property {boolean} enabled Whether the widget is enabled + * @property {?(TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel|Snowflake)} channel + * The widget invite channel + */ + + /** + * Fetches the guild widget settings. + * @returns {Promise<GuildWidgetSettings>} + * @example + * // Fetches the guild widget settings + * guild.fetchWidgetSettings() + * .then(widget => console.log(`The widget is ${widget.enabled ? 'enabled' : 'disabled'}`)) + * .catch(console.error); + */ + async fetchWidgetSettings() { + const data = await this.client.rest.get(Routes.guildWidgetSettings(this.id)); + this.widgetEnabled = data.enabled; + this.widgetChannelId = data.channel_id; + return { + enabled: data.enabled, + channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null, + }; + } + + /** + * Options used to fetch audit logs. + * @typedef {Object} GuildAuditLogsFetchOptions + * @property {Snowflake|GuildAuditLogsEntry} [before] Consider only entries before this entry + * @property {Snowflake|GuildAuditLogsEntry} [after] Consider only entries after this entry + * @property {number} [limit] The number of entries to return + * @property {UserResolvable} [user] Only return entries for actions made by this user + * @property {?AuditLogEvent} [type] Only return entries for this action type + */ + + /** + * Fetches audit logs for this guild. + * @param {GuildAuditLogsFetchOptions} [options={}] Options for fetching audit logs + * @returns {Promise<GuildAuditLogs>} + * @example + * // Output audit log entries + * guild.fetchAuditLogs() + * .then(audit => console.log(audit.entries.first())) + * .catch(console.error); + */ + async fetchAuditLogs({ before, after, limit, user, type } = {}) { + const query = makeURLSearchParams({ + before: before?.id ?? before, + after: after?.id ?? after, + limit, + action_type: type, + }); + + if (user) { + const userId = this.client.users.resolveId(user); + if (!userId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable'); + query.set('user_id', userId); + } + + const data = await this.client.rest.get(Routes.guildAuditLog(this.id), { query }); + return new GuildAuditLogs(this, data); + } + + /** + * Fetches the guild onboarding data for this guild. + * @returns {Promise<GuildOnboarding>} + */ + async fetchOnboarding() { + const data = await this.client.rest.get(Routes.guildOnboarding(this.id)); + return new GuildOnboarding(this.client, data); + } + + /** + * The data for editing a guild. + * @typedef {Object} GuildEditOptions + * @property {string} [name] The name of the guild + * @property {?GuildVerificationLevel} [verificationLevel] The verification level of the guild + * @property {?GuildDefaultMessageNotifications} [defaultMessageNotifications] The default message + * notification level of the guild + * @property {?GuildExplicitContentFilter} [explicitContentFilter] The level of the explicit content filter + * @property {?VoiceChannelResolvable} [afkChannel] The AFK channel of the guild + * @property {number} [afkTimeout] The AFK timeout of the guild + * @property {?(BufferResolvable|Base64Resolvable)} [icon] The icon of the guild + * @property {GuildMemberResolvable} [owner] The owner of the guild + * @property {?(BufferResolvable|Base64Resolvable)} [splash] The invite splash image of the guild + * @property {?(BufferResolvable|Base64Resolvable)} [discoverySplash] The discovery splash image of the guild + * @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner of the guild + * @property {?TextChannelResolvable} [systemChannel] The system channel of the guild + * @property {SystemChannelFlagsResolvable} [systemChannelFlags] The system channel flags of the guild + * @property {?TextChannelResolvable} [rulesChannel] The rules channel of the guild + * @property {?TextChannelResolvable} [publicUpdatesChannel] The community updates channel of the guild + * @property {?TextChannelResolvable} [safetyAlertsChannel] The safety alerts channel of the guild + * @property {?string} [preferredLocale] The preferred locale of the guild + * @property {GuildFeature[]} [features] The features of the guild + * @property {?string} [description] The discovery description of the guild + * @property {boolean} [premiumProgressBarEnabled] Whether the guild's premium progress bar is enabled + * @property {string} [reason] Reason for editing this guild + */ + + /** + * Data that can be resolved to a Text Channel object. This can be: + * * A TextChannel + * * A Snowflake + * @typedef {TextChannel|Snowflake} TextChannelResolvable + */ + + /** + * Data that can be resolved to a Voice Channel object. This can be: + * * A VoiceChannel + * * A Snowflake + * @typedef {VoiceChannel|Snowflake} VoiceChannelResolvable + */ + + /** + * Updates the guild with new information - e.g. a new name. + * @param {GuildEditOptions} options The options to provide + * @returns {Promise<Guild>} + * @example + * // Set the guild name + * guild.edit({ + * name: 'Discord Guild', + * }) + * .then(updated => console.log(`New guild name ${updated}`)) + * .catch(console.error); + */ + async edit({ + verificationLevel, + defaultMessageNotifications, + explicitContentFilter, + afkChannel, + afkTimeout, + icon, + owner, + splash, + discoverySplash, + banner, + systemChannel, + systemChannelFlags, + rulesChannel, + publicUpdatesChannel, + preferredLocale, + premiumProgressBarEnabled, + safetyAlertsChannel, + ...options + }) { + const data = await this.client.rest.patch(Routes.guild(this.id), { + body: { + ...options, + verification_level: verificationLevel, + default_message_notifications: defaultMessageNotifications, + explicit_content_filter: explicitContentFilter, + afk_channel_id: afkChannel && this.client.channels.resolveId(afkChannel), + afk_timeout: afkTimeout, + icon: icon && (await DataResolver.resolveImage(icon)), + owner_id: owner && this.client.users.resolveId(owner), + splash: splash && (await DataResolver.resolveImage(splash)), + discovery_splash: discoverySplash && (await DataResolver.resolveImage(discoverySplash)), + banner: banner && (await DataResolver.resolveImage(banner)), + system_channel_id: systemChannel && this.client.channels.resolveId(systemChannel), + system_channel_flags: + systemChannelFlags === undefined ? undefined : SystemChannelFlagsBitField.resolve(systemChannelFlags), + rules_channel_id: rulesChannel && this.client.channels.resolveId(rulesChannel), + public_updates_channel_id: publicUpdatesChannel && this.client.channels.resolveId(publicUpdatesChannel), + preferred_locale: preferredLocale, + premium_progress_bar_enabled: premiumProgressBarEnabled, + safety_alerts_channel_id: safetyAlertsChannel && this.client.channels.resolveId(safetyAlertsChannel), + }, + reason: options.reason, + }); + + return this.client.actions.GuildUpdate.handle(data).updated; + } + + /** + * Welcome channel data + * @typedef {Object} WelcomeChannelData + * @property {string} description The description to show for this welcome channel + * @property {TextChannel|NewsChannel|ForumChannel|Snowflake} channel The channel to link for this welcome channel + * @property {EmojiIdentifierResolvable} [emoji] The emoji to display for this welcome channel + */ + + /** + * Welcome screen edit data + * @typedef {Object} WelcomeScreenEditOptions + * @property {boolean} [enabled] Whether the welcome screen is enabled + * @property {string} [description] The description for the welcome screen + * @property {WelcomeChannelData[]} [welcomeChannels] The welcome channel data for the welcome screen + */ + + /** + * Data that can be resolved to a GuildTextChannel object. This can be: + * * A TextChannel + * * A NewsChannel + * * A Snowflake + * @typedef {TextChannel|NewsChannel|Snowflake} GuildTextChannelResolvable + */ + + /** + * Data that can be resolved to a GuildVoiceChannel object. This can be: + * * A VoiceChannel + * * A StageChannel + * * A Snowflake + * @typedef {VoiceChannel|StageChannel|Snowflake} GuildVoiceChannelResolvable + */ + + /** + * Updates the guild's welcome screen + * @param {WelcomeScreenEditOptions} options The options to provide + * @returns {Promise<WelcomeScreen>} + * @example + * guild.editWelcomeScreen({ + * description: 'Hello World', + * enabled: true, + * welcomeChannels: [ + * { + * description: 'foobar', + * channel: '222197033908436994', + * } + * ], + * }) + */ + async editWelcomeScreen(options) { + const { enabled, description, welcomeChannels } = options; + const welcome_channels = welcomeChannels?.map(welcomeChannelData => { + const emoji = this.emojis.resolve(welcomeChannelData.emoji); + return { + emoji_id: emoji?.id, + emoji_name: emoji?.name ?? welcomeChannelData.emoji, + channel_id: this.channels.resolveId(welcomeChannelData.channel), + description: welcomeChannelData.description, + }; + }); + + const patchData = await this.client.rest.patch(Routes.guildWelcomeScreen(this.id), { + body: { + welcome_channels, + description, + enabled, + }, + }); + return new WelcomeScreen(this, patchData); + } + + /** + * Edits the level of the explicit content filter. + * @param {?GuildExplicitContentFilter} explicitContentFilter The new level of the explicit content filter + * @param {string} [reason] Reason for changing the level of the guild's explicit content filter + * @returns {Promise<Guild>} + */ + setExplicitContentFilter(explicitContentFilter, reason) { + return this.edit({ explicitContentFilter, reason }); + } + + /** + * Edits the setting of the default message notifications of the guild. + * @param {?GuildDefaultMessageNotifications} defaultMessageNotifications + * The new default message notification level of the guild + * @param {string} [reason] Reason for changing the setting of the default message notifications + * @returns {Promise<Guild>} + */ + setDefaultMessageNotifications(defaultMessageNotifications, reason) { + return this.edit({ defaultMessageNotifications, reason }); + } + + /** + * Edits the flags of the default message notifications of the guild. + * @param {SystemChannelFlagsResolvable} systemChannelFlags The new flags for the default message notifications + * @param {string} [reason] Reason for changing the flags of the default message notifications + * @returns {Promise<Guild>} + */ + setSystemChannelFlags(systemChannelFlags, reason) { + return this.edit({ systemChannelFlags, reason }); + } + + /** + * Edits the name of the guild. + * @param {string} name The new name of the guild + * @param {string} [reason] Reason for changing the guild's name + * @returns {Promise<Guild>} + * @example + * // Edit the guild name + * guild.setName('Discord Guild') + * .then(updated => console.log(`Updated guild name to ${updated.name}`)) + * .catch(console.error); + */ + setName(name, reason) { + return this.edit({ name, reason }); + } + + /** + * Edits the verification level of the guild. + * @param {?GuildVerificationLevel} verificationLevel The new verification level of the guild + * @param {string} [reason] Reason for changing the guild's verification level + * @returns {Promise<Guild>} + * @example + * // Edit the guild verification level + * guild.setVerificationLevel(1) + * .then(updated => console.log(`Updated guild verification level to ${guild.verificationLevel}`)) + * .catch(console.error); + */ + setVerificationLevel(verificationLevel, reason) { + return this.edit({ verificationLevel, reason }); + } + + /** + * Edits the AFK channel of the guild. + * @param {?VoiceChannelResolvable} afkChannel The new AFK channel + * @param {string} [reason] Reason for changing the guild's AFK channel + * @returns {Promise<Guild>} + * @example + * // Edit the guild AFK channel + * guild.setAFKChannel(channel) + * .then(updated => console.log(`Updated guild AFK channel to ${guild.afkChannel.name}`)) + * .catch(console.error); + */ + setAFKChannel(afkChannel, reason) { + return this.edit({ afkChannel, reason }); + } + + /** + * Edits the system channel of the guild. + * @param {?TextChannelResolvable} systemChannel The new system channel + * @param {string} [reason] Reason for changing the guild's system channel + * @returns {Promise<Guild>} + * @example + * // Edit the guild system channel + * guild.setSystemChannel(channel) + * .then(updated => console.log(`Updated guild system channel to ${guild.systemChannel.name}`)) + * .catch(console.error); + */ + setSystemChannel(systemChannel, reason) { + return this.edit({ systemChannel, reason }); + } + + /** + * Edits the AFK timeout of the guild. + * @param {number} afkTimeout The time in seconds that a user must be idle to be considered AFK + * @param {string} [reason] Reason for changing the guild's AFK timeout + * @returns {Promise<Guild>} + * @example + * // Edit the guild AFK channel + * guild.setAFKTimeout(60) + * .then(updated => console.log(`Updated guild AFK timeout to ${guild.afkTimeout}`)) + * .catch(console.error); + */ + setAFKTimeout(afkTimeout, reason) { + return this.edit({ afkTimeout, reason }); + } + + /** + * Sets a new guild icon. + * @param {?(Base64Resolvable|BufferResolvable)} icon The new icon of the guild + * @param {string} [reason] Reason for changing the guild's icon + * @returns {Promise<Guild>} + * @example + * // Edit the guild icon + * guild.setIcon('./icon.png') + * .then(updated => console.log('Updated the guild icon')) + * .catch(console.error); + */ + setIcon(icon, reason) { + return this.edit({ icon, reason }); + } + + /** + * Sets a new owner of the guild. + * @param {GuildMemberResolvable} owner The new owner of the guild + * @param {string} [reason] Reason for setting the new owner + * @returns {Promise<Guild>} + * @example + * // Edit the guild owner + * guild.setOwner(guild.members.cache.first()) + * .then(guild => guild.fetchOwner()) + * .then(owner => console.log(`Updated the guild owner to ${owner.displayName}`)) + * .catch(console.error); + */ + setOwner(owner, reason) { + return this.edit({ owner, reason }); + } + + /** + * Sets a new guild invite splash image. + * @param {?(Base64Resolvable|BufferResolvable)} splash The new invite splash image of the guild + * @param {string} [reason] Reason for changing the guild's invite splash image + * @returns {Promise<Guild>} + * @example + * // Edit the guild splash + * guild.setSplash('./splash.png') + * .then(updated => console.log('Updated the guild splash')) + * .catch(console.error); + */ + setSplash(splash, reason) { + return this.edit({ splash, reason }); + } + + /** + * Sets a new guild discovery splash image. + * @param {?(Base64Resolvable|BufferResolvable)} discoverySplash The new discovery splash image of the guild + * @param {string} [reason] Reason for changing the guild's discovery splash image + * @returns {Promise<Guild>} + * @example + * // Edit the guild discovery splash + * guild.setDiscoverySplash('./discoverysplash.png') + * .then(updated => console.log('Updated the guild discovery splash')) + * .catch(console.error); + */ + setDiscoverySplash(discoverySplash, reason) { + return this.edit({ discoverySplash, reason }); + } + + /** + * Sets a new guild banner. + * @param {?(Base64Resolvable|BufferResolvable)} banner The new banner of the guild + * @param {string} [reason] Reason for changing the guild's banner + * @returns {Promise<Guild>} + * @example + * guild.setBanner('./banner.png') + * .then(updated => console.log('Updated the guild banner')) + * .catch(console.error); + */ + setBanner(banner, reason) { + return this.edit({ banner, reason }); + } + + /** + * Edits the rules channel of the guild. + * @param {?TextChannelResolvable} rulesChannel The new rules channel + * @param {string} [reason] Reason for changing the guild's rules channel + * @returns {Promise<Guild>} + * @example + * // Edit the guild rules channel + * guild.setRulesChannel(channel) + * .then(updated => console.log(`Updated guild rules channel to ${guild.rulesChannel.name}`)) + * .catch(console.error); + */ + setRulesChannel(rulesChannel, reason) { + return this.edit({ rulesChannel, reason }); + } + + /** + * Edits the community updates channel of the guild. + * @param {?TextChannelResolvable} publicUpdatesChannel The new community updates channel + * @param {string} [reason] Reason for changing the guild's community updates channel + * @returns {Promise<Guild>} + * @example + * // Edit the guild community updates channel + * guild.setPublicUpdatesChannel(channel) + * .then(updated => console.log(`Updated guild community updates channel to ${guild.publicUpdatesChannel.name}`)) + * .catch(console.error); + */ + setPublicUpdatesChannel(publicUpdatesChannel, reason) { + return this.edit({ publicUpdatesChannel, reason }); + } + + /** + * Edits the preferred locale of the guild. + * @param {?Locale} preferredLocale The new preferred locale of the guild + * @param {string} [reason] Reason for changing the guild's preferred locale + * @returns {Promise<Guild>} + * @example + * // Edit the guild preferred locale + * guild.setPreferredLocale('en-US') + * .then(updated => console.log(`Updated guild preferred locale to ${guild.preferredLocale}`)) + * .catch(console.error); + */ + setPreferredLocale(preferredLocale, reason) { + return this.edit({ preferredLocale, reason }); + } + + /** + * Edits the enabled state of the guild's premium progress bar + * @param {boolean} [enabled=true] The new enabled state of the guild's premium progress bar + * @param {string} [reason] Reason for changing the state of the guild's premium progress bar + * @returns {Promise<Guild>} + */ + setPremiumProgressBarEnabled(enabled = true, reason) { + return this.edit({ premiumProgressBarEnabled: enabled, reason }); + } + + /** + * Edits the safety alerts channel of the guild. + * @param {?TextChannelResolvable} safetyAlertsChannel The new safety alerts channel + * @param {string} [reason] Reason for changing the guild's safety alerts channel + * @returns {Promise<Guild>} + * @example + * // Edit the guild safety alerts channel + * guild.setSafetyAlertsChannel(channel) + * .then(updated => console.log(`Updated guild safety alerts channel to ${updated.safetyAlertsChannel.name}`)) + * .catch(console.error); + */ + setSafetyAlertsChannel(safetyAlertsChannel, reason) { + return this.edit({ safetyAlertsChannel, reason }); + } + + /** + * Edits the guild's widget settings. + * @param {GuildWidgetSettingsData} settings The widget settings for the guild + * @param {string} [reason] Reason for changing the guild's widget settings + * @returns {Promise<Guild>} + */ + async setWidgetSettings(settings, reason) { + await this.client.rest.patch(Routes.guildWidgetSettings(this.id), { + body: { + enabled: settings.enabled, + channel_id: this.channels.resolveId(settings.channel), + }, + reason, + }); + return this; + } + + /** + * Sets the guild's MFA level + * <info>An elevated MFA level requires guild moderators to have 2FA enabled.</info> + * @param {GuildMFALevel} level The MFA level + * @param {string} [reason] Reason for changing the guild's MFA level + * @returns {Promise<Guild>} + * @example + * // Set the MFA level of the guild to Elevated + * guild.setMFALevel(GuildMFALevel.Elevated) + * .then(guild => console.log("Set guild's MFA level to Elevated")) + * .catch(console.error); + */ + async setMFALevel(level, reason) { + await this.client.rest.post(Routes.guildMFA(this.id), { + body: { + level, + }, + reason, + }); + return this; + } + + /** + * Leaves the guild. + * @returns {Promise<Guild>} + * @example + * // Leave a guild + * guild.leave() + * .then(guild => console.log(`Left the guild: ${guild.name}`)) + * .catch(console.error); + */ + async leave() { + if (this.ownerId === this.client.user.id) throw new DiscordjsError(ErrorCodes.GuildOwned); + await this.client.rest.delete(Routes.userGuild(this.id)); + return this; + } + + /** + * Deletes the guild. + * @returns {Promise<Guild>} + * @example + * // Delete a guild + * guild.delete() + * .then(g => console.log(`Deleted the guild ${g}`)) + * .catch(console.error); + */ + async delete() { + await this.client.rest.delete(Routes.guild(this.id)); + return this; + } + + /** + * Sets whether this guild's invites are disabled. + * @param {boolean} [disabled=true] Whether the invites are disabled + * @returns {Promise<Guild>} + */ + async disableInvites(disabled = true) { + const features = this.features.filter(feature => feature !== GuildFeature.InvitesDisabled); + if (disabled) features.push(GuildFeature.InvitesDisabled); + return this.edit({ features }); + } + + /** + * Whether this guild equals another guild. It compares all properties, so for most operations + * it is advisable to just compare `guild.id === guild2.id` as it is much faster and is often + * what most users need. + * @param {Guild} guild The guild to compare with + * @returns {boolean} + */ + equals(guild) { + return ( + guild && + guild instanceof this.constructor && + this.id === guild.id && + this.available === guild.available && + this.splash === guild.splash && + this.discoverySplash === guild.discoverySplash && + this.name === guild.name && + this.memberCount === guild.memberCount && + this.large === guild.large && + this.icon === guild.icon && + this.ownerId === guild.ownerId && + this.verificationLevel === guild.verificationLevel && + (this.features === guild.features || + (this.features.length === guild.features.length && + this.features.every((feat, i) => feat === guild.features[i]))) + ); + } + + toJSON() { + const json = super.toJSON({ + available: false, + createdTimestamp: true, + nameAcronym: true, + presences: false, + voiceStates: false, + }); + json.iconURL = this.iconURL(); + json.splashURL = this.splashURL(); + json.discoverySplashURL = this.discoverySplashURL(); + json.bannerURL = this.bannerURL(); + return json; + } + + /** + * The voice state adapter for this guild that can be used with @discordjs/voice to play audio in voice + * and stage channels. + * @type {Function} + * @readonly + */ + get voiceAdapterCreator() { + return methods => { + this.client.voice.adapters.set(this.id, methods); + return { + sendPayload: data => { + if (this.shard.status !== Status.Ready) return false; + this.shard.send(data); + return true; + }, + destroy: () => { + this.client.voice.adapters.delete(this.id); + }, + }; + }; + } + + /** + * Creates a collection of this guild's roles, sorted by their position and ids. + * @returns {Collection<Snowflake, Role>} + * @private + */ + _sortedRoles() { + return discordSort(this.roles.cache); + } + + /** + * Creates a collection of this guild's or a specific category's channels, sorted by their position and ids. + * @param {GuildChannel} [channel] Category to get the channels of + * @returns {Collection<Snowflake, GuildChannel>} + * @private + */ + _sortedChannels(channel) { + const channelIsCategory = channel.type === ChannelType.GuildCategory; + const types = getSortableGroupTypes(channel.type); + return discordSort( + this.channels.cache.filter(c => types.includes(c.type) && (channelIsCategory || c.parentId === channel.parentId)), + ); + } +} + +exports.Guild = Guild; + +/** + * @external APIGuild + * @see {@link https://discord.com/developers/docs/resources/guild#guild-object} + */ diff --git a/node_modules/discord.js/src/structures/GuildAuditLogs.js b/node_modules/discord.js/src/structures/GuildAuditLogs.js new file mode 100644 index 0000000..2ce13a8 --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildAuditLogs.js @@ -0,0 +1,91 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const ApplicationCommand = require('./ApplicationCommand'); +const GuildAuditLogsEntry = require('./GuildAuditLogsEntry'); +const Integration = require('./Integration'); +const Webhook = require('./Webhook'); +const { flatten } = require('../util/Util'); + +/** + * Audit logs entries are held in this class. + */ +class GuildAuditLogs { + constructor(guild, data) { + if (data.users) for (const user of data.users) guild.client.users._add(user); + if (data.threads) for (const thread of data.threads) guild.client.channels._add(thread, guild); + /** + * Cached webhooks + * @type {Collection<Snowflake, Webhook>} + * @private + */ + this.webhooks = new Collection(); + if (data.webhooks) { + for (const hook of data.webhooks) { + this.webhooks.set(hook.id, new Webhook(guild.client, hook)); + } + } + + /** + * Cached integrations + * @type {Collection<Snowflake|string, Integration>} + * @private + */ + this.integrations = new Collection(); + if (data.integrations) { + for (const integration of data.integrations) { + this.integrations.set(integration.id, new Integration(guild.client, integration, guild)); + } + } + + /** + * Cached {@link GuildScheduledEvent}s. + * @type {Collection<Snowflake, GuildScheduledEvent>} + * @private + */ + this.guildScheduledEvents = data.guild_scheduled_events.reduce( + (guildScheduledEvents, guildScheduledEvent) => + guildScheduledEvents.set(guildScheduledEvent.id, guild.scheduledEvents._add(guildScheduledEvent)), + new Collection(), + ); + + /** + * Cached application commands, includes application commands from other applications + * @type {Collection<Snowflake, ApplicationCommand>} + * @private + */ + this.applicationCommands = new Collection(); + if (data.application_commands) { + for (const command of data.application_commands) { + this.applicationCommands.set(command.id, new ApplicationCommand(guild.client, command, guild)); + } + } + + /** + * Cached auto moderation rules. + * @type {Collection<Snowflake, AutoModerationRule>} + * @private + */ + this.autoModerationRules = data.auto_moderation_rules.reduce( + (autoModerationRules, autoModerationRule) => + autoModerationRules.set(autoModerationRule.id, guild.autoModerationRules._add(autoModerationRule)), + new Collection(), + ); + + /** + * The entries for this guild's audit logs + * @type {Collection<Snowflake, GuildAuditLogsEntry>} + */ + this.entries = new Collection(); + for (const item of data.audit_log_entries) { + const entry = new GuildAuditLogsEntry(guild, item, this); + this.entries.set(entry.id, entry); + } + } + + toJSON() { + return flatten(this); + } +} + +module.exports = GuildAuditLogs; diff --git a/node_modules/discord.js/src/structures/GuildAuditLogsEntry.js b/node_modules/discord.js/src/structures/GuildAuditLogsEntry.js new file mode 100644 index 0000000..febbd12 --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildAuditLogsEntry.js @@ -0,0 +1,528 @@ +'use strict'; + +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { AuditLogOptionsType, AuditLogEvent } = require('discord-api-types/v10'); +const AutoModerationRule = require('./AutoModerationRule'); +const { GuildScheduledEvent } = require('./GuildScheduledEvent'); +const Integration = require('./Integration'); +const Invite = require('./Invite'); +const { StageInstance } = require('./StageInstance'); +const { Sticker } = require('./Sticker'); +const Webhook = require('./Webhook'); +const Partials = require('../util/Partials'); +const { flatten } = require('../util/Util'); + +const Targets = { + All: 'All', + Guild: 'Guild', + GuildScheduledEvent: 'GuildScheduledEvent', + Channel: 'Channel', + User: 'User', + Role: 'Role', + Invite: 'Invite', + Webhook: 'Webhook', + Emoji: 'Emoji', + Message: 'Message', + Integration: 'Integration', + StageInstance: 'StageInstance', + Sticker: 'Sticker', + Thread: 'Thread', + ApplicationCommand: 'ApplicationCommand', + AutoModeration: 'AutoModeration', + Unknown: 'Unknown', +}; + +/** + * The target of a guild audit log entry. It can be one of: + * * A guild + * * A channel + * * A user + * * A role + * * An invite + * * A webhook + * * An emoji + * * A message + * * An integration + * * A stage instance + * * A sticker + * * A guild scheduled event + * * A thread + * * An application command + * * An auto moderation rule + * * An object with an id key if target was deleted or fake entity + * * An object where the keys represent either the new value or the old value + * @typedef {?(Object|Guild|BaseChannel|User|Role|Invite|Webhook|GuildEmoji|Message|Integration|StageInstance|Sticker| + * GuildScheduledEvent|ApplicationCommand|AutoModerationRule)} AuditLogEntryTarget + */ + +/** + * The action type of an entry, e.g. `Create`. Here are the available types: + * * Create + * * Delete + * * Update + * * All + * @typedef {string} AuditLogActionType + */ + +/** + * The target type of an entry. Here are the available types: + * * Guild + * * Channel + * * User + * * Role + * * Invite + * * Webhook + * * Emoji + * * Message + * * Integration + * * StageInstance + * * Sticker + * * Thread + * * GuildScheduledEvent + * * ApplicationCommandPermission + * @typedef {string} AuditLogTargetType + */ + +/** + * Audit logs entry. + */ +class GuildAuditLogsEntry { + /** + * Key mirror of all available audit log targets. + * @type {Object<string, string>} + * @memberof GuildAuditLogsEntry + */ + static Targets = Targets; + + constructor(guild, data, logs) { + /** + * The target type of this entry + * @type {AuditLogTargetType} + */ + this.targetType = GuildAuditLogsEntry.targetType(data.action_type); + const targetType = this.targetType; + + /** + * The action type of this entry + * @type {AuditLogActionType} + */ + this.actionType = GuildAuditLogsEntry.actionType(data.action_type); + + /** + * The type of action that occurred. + * @type {AuditLogEvent} + */ + this.action = data.action_type; + + /** + * The reason of this entry + * @type {?string} + */ + this.reason = data.reason ?? null; + + /** + * The id of the user that executed this entry + * @type {?Snowflake} + */ + this.executorId = data.user_id; + + /** + * The user that executed this entry + * @type {?User} + */ + this.executor = data.user_id + ? guild.client.options.partials.includes(Partials.User) + ? guild.client.users._add({ id: data.user_id }) + : guild.client.users.cache.get(data.user_id) ?? null + : null; + + /** + * An entry in the audit log representing a specific change. + * @typedef {Object} AuditLogChange + * @property {string} key The property that was changed, e.g. `nick` for nickname changes + * <warn>For application command permissions updates the key is the id of the user, channel, + * role, or a permission constant that was updated instead of an actual property name</warn> + * @property {*} [old] The old value of the change, e.g. for nicknames, the old nickname + * @property {*} [new] The new value of the change, e.g. for nicknames, the new nickname + */ + + /** + * Specific property changes + * @type {AuditLogChange[]} + */ + this.changes = data.changes?.map(c => ({ key: c.key, old: c.old_value, new: c.new_value })) ?? []; + + /** + * The entry's id + * @type {Snowflake} + */ + this.id = data.id; + + /** + * Any extra data from the entry + * @type {?(Object|Role|GuildMember)} + */ + this.extra = null; + switch (data.action_type) { + case AuditLogEvent.MemberPrune: + this.extra = { + removed: Number(data.options.members_removed), + days: Number(data.options.delete_member_days), + }; + break; + + case AuditLogEvent.MemberMove: + case AuditLogEvent.MessageDelete: + case AuditLogEvent.MessageBulkDelete: + this.extra = { + channel: guild.channels.cache.get(data.options.channel_id) ?? { id: data.options.channel_id }, + count: Number(data.options.count), + }; + break; + + case AuditLogEvent.MessagePin: + case AuditLogEvent.MessageUnpin: + this.extra = { + channel: guild.client.channels.cache.get(data.options.channel_id) ?? { id: data.options.channel_id }, + messageId: data.options.message_id, + }; + break; + + case AuditLogEvent.MemberDisconnect: + this.extra = { + count: Number(data.options.count), + }; + break; + + case AuditLogEvent.ChannelOverwriteCreate: + case AuditLogEvent.ChannelOverwriteUpdate: + case AuditLogEvent.ChannelOverwriteDelete: + switch (data.options.type) { + case AuditLogOptionsType.Role: + this.extra = guild.roles.cache.get(data.options.id) ?? { + id: data.options.id, + name: data.options.role_name, + type: AuditLogOptionsType.Role, + }; + break; + + case AuditLogOptionsType.Member: + this.extra = guild.members.cache.get(data.options.id) ?? { + id: data.options.id, + type: AuditLogOptionsType.Member, + }; + break; + + default: + break; + } + break; + + case AuditLogEvent.StageInstanceCreate: + case AuditLogEvent.StageInstanceDelete: + case AuditLogEvent.StageInstanceUpdate: + this.extra = { + channel: guild.client.channels.cache.get(data.options?.channel_id) ?? { id: data.options?.channel_id }, + }; + break; + + case AuditLogEvent.ApplicationCommandPermissionUpdate: + this.extra = { + applicationId: data.options.application_id, + }; + break; + + case AuditLogEvent.AutoModerationBlockMessage: + case AuditLogEvent.AutoModerationFlagToChannel: + case AuditLogEvent.AutoModerationUserCommunicationDisabled: + this.extra = { + autoModerationRuleName: data.options.auto_moderation_rule_name, + autoModerationRuleTriggerType: data.options.auto_moderation_rule_trigger_type, + channel: guild.client.channels.cache.get(data.options?.channel_id) ?? { id: data.options?.channel_id }, + }; + break; + + default: + break; + } + + /** + * The id of the target of this entry + * @type {?Snowflake} + */ + this.targetId = data.target_id; + + /** + * The target of this entry + * @type {?AuditLogEntryTarget} + */ + this.target = null; + if (targetType === Targets.Unknown) { + this.target = this.changes.reduce((o, c) => { + o[c.key] = c.new ?? c.old; + return o; + }, {}); + this.target.id = data.target_id; + // MemberDisconnect and similar types do not provide a target_id. + } else if (targetType === Targets.User && data.target_id) { + this.target = guild.client.options.partials.includes(Partials.User) + ? guild.client.users._add({ id: data.target_id }) + : guild.client.users.cache.get(data.target_id) ?? null; + } else if (targetType === Targets.Guild) { + this.target = guild.client.guilds.cache.get(data.target_id); + } else if (targetType === Targets.Webhook) { + this.target = + logs?.webhooks.get(data.target_id) ?? + new Webhook( + guild.client, + this.changes.reduce( + (o, c) => { + o[c.key] = c.new ?? c.old; + return o; + }, + { + id: data.target_id, + guild_id: guild.id, + }, + ), + ); + } else if (targetType === Targets.Invite) { + let change = this.changes.find(c => c.key === 'code'); + change = change.new ?? change.old; + + this.target = + guild.invites.cache.get(change) ?? + new Invite( + guild.client, + this.changes.reduce( + (o, c) => { + o[c.key] = c.new ?? c.old; + return o; + }, + { guild }, + ), + ); + } else if (targetType === Targets.Message) { + // Discord sends a channel id for the MessageBulkDelete action type. + this.target = + data.action_type === AuditLogEvent.MessageBulkDelete + ? guild.channels.cache.get(data.target_id) ?? { id: data.target_id } + : guild.client.users.cache.get(data.target_id) ?? null; + } else if (targetType === Targets.Integration) { + this.target = + logs?.integrations.get(data.target_id) ?? + new Integration( + guild.client, + this.changes.reduce( + (o, c) => { + o[c.key] = c.new ?? c.old; + return o; + }, + { id: data.target_id }, + ), + guild, + ); + } else if (targetType === Targets.Channel || targetType === Targets.Thread) { + this.target = + guild.channels.cache.get(data.target_id) ?? + this.changes.reduce( + (o, c) => { + o[c.key] = c.new ?? c.old; + return o; + }, + { id: data.target_id }, + ); + } else if (targetType === Targets.StageInstance) { + this.target = + guild.stageInstances.cache.get(data.target_id) ?? + new StageInstance( + guild.client, + this.changes.reduce( + (o, c) => { + o[c.key] = c.new ?? c.old; + return o; + }, + { + id: data.target_id, + channel_id: data.options?.channel_id, + guild_id: guild.id, + }, + ), + ); + } else if (targetType === Targets.Sticker) { + this.target = + guild.stickers.cache.get(data.target_id) ?? + new Sticker( + guild.client, + this.changes.reduce( + (o, c) => { + o[c.key] = c.new ?? c.old; + return o; + }, + { id: data.target_id }, + ), + ); + } else if (targetType === Targets.GuildScheduledEvent) { + this.target = + guild.scheduledEvents.cache.get(data.target_id) ?? + new GuildScheduledEvent( + guild.client, + this.changes.reduce( + (o, c) => { + o[c.key] = c.new ?? c.old; + return o; + }, + { id: data.target_id, guild_id: guild.id }, + ), + ); + } else if (targetType === Targets.ApplicationCommand) { + this.target = logs?.applicationCommands.get(data.target_id) ?? { id: data.target_id }; + } else if (targetType === Targets.AutoModeration) { + this.target = + guild.autoModerationRules.cache.get(data.target_id) ?? + new AutoModerationRule( + guild.client, + this.changes.reduce( + (o, c) => { + o[c.key] = c.new ?? c.old; + return o; + }, + { id: data.target_id, guild_id: guild.id }, + ), + guild, + ); + } else if (data.target_id) { + this.target = guild[`${targetType.toLowerCase()}s`]?.cache.get(data.target_id) ?? { id: data.target_id }; + } + } + + /** + * Finds the target type of a guild audit log entry. + * @param {AuditLogEvent} target The action target + * @returns {AuditLogTargetType} + */ + static targetType(target) { + if (target < 10) return Targets.Guild; + if (target < 20) return Targets.Channel; + if (target < 30) return Targets.User; + if (target < 40) return Targets.Role; + if (target < 50) return Targets.Invite; + if (target < 60) return Targets.Webhook; + if (target < 70) return Targets.Emoji; + if (target < 80) return Targets.Message; + if (target < 83) return Targets.Integration; + if (target < 86) return Targets.StageInstance; + if (target < 100) return Targets.Sticker; + if (target < 110) return Targets.GuildScheduledEvent; + if (target < 120) return Targets.Thread; + if (target < 130) return Targets.ApplicationCommand; + if (target >= 140 && target < 150) return Targets.AutoModeration; + return Targets.Unknown; + } + + /** + * Finds the action type from the guild audit log entry action. + * @param {AuditLogEvent} action The action target + * @returns {AuditLogActionType} + */ + static actionType(action) { + if ( + [ + AuditLogEvent.ChannelCreate, + AuditLogEvent.ChannelOverwriteCreate, + AuditLogEvent.MemberBanRemove, + AuditLogEvent.BotAdd, + AuditLogEvent.RoleCreate, + AuditLogEvent.InviteCreate, + AuditLogEvent.WebhookCreate, + AuditLogEvent.EmojiCreate, + AuditLogEvent.MessagePin, + AuditLogEvent.IntegrationCreate, + AuditLogEvent.StageInstanceCreate, + AuditLogEvent.StickerCreate, + AuditLogEvent.GuildScheduledEventCreate, + AuditLogEvent.ThreadCreate, + AuditLogEvent.AutoModerationRuleCreate, + AuditLogEvent.AutoModerationBlockMessage, + ].includes(action) + ) { + return 'Create'; + } + + if ( + [ + AuditLogEvent.ChannelDelete, + AuditLogEvent.ChannelOverwriteDelete, + AuditLogEvent.MemberKick, + AuditLogEvent.MemberPrune, + AuditLogEvent.MemberBanAdd, + AuditLogEvent.MemberDisconnect, + AuditLogEvent.RoleDelete, + AuditLogEvent.InviteDelete, + AuditLogEvent.WebhookDelete, + AuditLogEvent.EmojiDelete, + AuditLogEvent.MessageDelete, + AuditLogEvent.MessageBulkDelete, + AuditLogEvent.MessageUnpin, + AuditLogEvent.IntegrationDelete, + AuditLogEvent.StageInstanceDelete, + AuditLogEvent.StickerDelete, + AuditLogEvent.GuildScheduledEventDelete, + AuditLogEvent.ThreadDelete, + AuditLogEvent.AutoModerationRuleDelete, + ].includes(action) + ) { + return 'Delete'; + } + + if ( + [ + AuditLogEvent.GuildUpdate, + AuditLogEvent.ChannelUpdate, + AuditLogEvent.ChannelOverwriteUpdate, + AuditLogEvent.MemberUpdate, + AuditLogEvent.MemberRoleUpdate, + AuditLogEvent.MemberMove, + AuditLogEvent.RoleUpdate, + AuditLogEvent.InviteUpdate, + AuditLogEvent.WebhookUpdate, + AuditLogEvent.EmojiUpdate, + AuditLogEvent.IntegrationUpdate, + AuditLogEvent.StageInstanceUpdate, + AuditLogEvent.StickerUpdate, + AuditLogEvent.GuildScheduledEventUpdate, + AuditLogEvent.ThreadUpdate, + AuditLogEvent.ApplicationCommandPermissionUpdate, + AuditLogEvent.AutoModerationRuleUpdate, + ].includes(action) + ) { + return 'Update'; + } + + return 'All'; + } + + /** + * The timestamp this entry was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time this entry was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + toJSON() { + return flatten(this, { createdTimestamp: true }); + } +} + +module.exports = GuildAuditLogsEntry; diff --git a/node_modules/discord.js/src/structures/GuildBan.js b/node_modules/discord.js/src/structures/GuildBan.js new file mode 100644 index 0000000..9c5a10e --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildBan.js @@ -0,0 +1,59 @@ +'use strict'; + +const Base = require('./Base'); + +/** + * Represents a ban in a guild on Discord. + * @extends {Base} + */ +class GuildBan extends Base { + constructor(client, data, guild) { + super(client); + + /** + * The guild in which the ban is + * @type {Guild} + */ + this.guild = guild; + + this._patch(data); + } + + _patch(data) { + if ('user' in data) { + /** + * The user this ban applies to + * @type {User} + */ + this.user = this.client.users._add(data.user, true); + } + + if ('reason' in data) { + /** + * The reason for the ban + * @type {?string} + */ + this.reason = data.reason; + } + } + + /** + * Whether this GuildBan is partial. If the reason is not provided the value is null + * @type {boolean} + * @readonly + */ + get partial() { + return !('reason' in this); + } + + /** + * Fetches this GuildBan. + * @param {boolean} [force=true] Whether to skip the cache check and request the API + * @returns {Promise<GuildBan>} + */ + fetch(force = true) { + return this.guild.bans.fetch({ user: this.user, cache: true, force }); + } +} + +module.exports = GuildBan; diff --git a/node_modules/discord.js/src/structures/GuildChannel.js b/node_modules/discord.js/src/structures/GuildChannel.js new file mode 100644 index 0000000..c066c71 --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildChannel.js @@ -0,0 +1,472 @@ +'use strict'; + +const { Snowflake } = require('@sapphire/snowflake'); +const { PermissionFlagsBits, ChannelType } = require('discord-api-types/v10'); +const { BaseChannel } = require('./BaseChannel'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const PermissionOverwriteManager = require('../managers/PermissionOverwriteManager'); +const { VoiceBasedChannelTypes } = require('../util/Constants'); +const PermissionsBitField = require('../util/PermissionsBitField'); +const { getSortableGroupTypes } = require('../util/Util'); + +/** + * Represents a guild channel from any of the following: + * - {@link TextChannel} + * - {@link VoiceChannel} + * - {@link CategoryChannel} + * - {@link NewsChannel} + * - {@link StageChannel} + * - {@link ForumChannel} + * @extends {BaseChannel} + * @abstract + */ +class GuildChannel extends BaseChannel { + constructor(guild, data, client, immediatePatch = true) { + super(client, data, false); + + /** + * The guild the channel is in + * @type {Guild} + */ + this.guild = guild; + + /** + * The id of the guild the channel is in + * @type {Snowflake} + */ + this.guildId = guild?.id ?? data.guild_id; + /** + * A manager of permission overwrites that belong to this channel + * @type {PermissionOverwriteManager} + */ + this.permissionOverwrites = new PermissionOverwriteManager(this); + + if (data && immediatePatch) this._patch(data); + } + + _patch(data) { + super._patch(data); + + if ('name' in data) { + /** + * The name of the guild channel + * @type {string} + */ + this.name = data.name; + } + + if ('position' in data) { + /** + * The raw position of the channel from Discord + * @type {number} + */ + this.rawPosition = data.position; + } + + if ('guild_id' in data) { + this.guildId = data.guild_id; + } + + if ('parent_id' in data) { + /** + * The id of the category parent of this channel + * @type {?Snowflake} + */ + this.parentId = data.parent_id; + } else { + this.parentId ??= null; + } + + if ('permission_overwrites' in data) { + this.permissionOverwrites.cache.clear(); + for (const overwrite of data.permission_overwrites) { + this.permissionOverwrites._add(overwrite); + } + } + } + + _clone() { + const clone = super._clone(); + clone.permissionOverwrites = new PermissionOverwriteManager(clone, this.permissionOverwrites.cache.values()); + return clone; + } + + /** + * The category parent of this channel + * @type {?CategoryChannel} + * @readonly + */ + get parent() { + return this.guild.channels.resolve(this.parentId); + } + + /** + * If the permissionOverwrites match the parent channel, null if no parent + * @type {?boolean} + * @readonly + */ + get permissionsLocked() { + if (!this.parent) return null; + + // Get all overwrites + const overwriteIds = new Set([ + ...this.permissionOverwrites.cache.keys(), + ...this.parent.permissionOverwrites.cache.keys(), + ]); + + // Compare all overwrites + return [...overwriteIds].every(key => { + const channelVal = this.permissionOverwrites.cache.get(key); + const parentVal = this.parent.permissionOverwrites.cache.get(key); + + // Handle empty overwrite + if ( + (!channelVal && + parentVal.deny.bitfield === PermissionsBitField.DefaultBit && + parentVal.allow.bitfield === PermissionsBitField.DefaultBit) || + (!parentVal && + channelVal.deny.bitfield === PermissionsBitField.DefaultBit && + channelVal.allow.bitfield === PermissionsBitField.DefaultBit) + ) { + return true; + } + + // Compare overwrites + return ( + channelVal !== undefined && + parentVal !== undefined && + channelVal.deny.bitfield === parentVal.deny.bitfield && + channelVal.allow.bitfield === parentVal.allow.bitfield + ); + }); + } + + /** + * The position of the channel + * @type {number} + * @readonly + */ + get position() { + const selfIsCategory = this.type === ChannelType.GuildCategory; + const types = getSortableGroupTypes(this.type); + + let count = 0; + for (const channel of this.guild.channels.cache.values()) { + if (!types.includes(channel.type)) continue; + if (!selfIsCategory && channel.parentId !== this.parentId) continue; + if (this.rawPosition === channel.rawPosition) { + if (Snowflake.compare(channel.id, this.id) === -1) count++; + } else if (this.rawPosition > channel.rawPosition) { + count++; + } + } + + return count; + } + + /** + * Gets the overall set of permissions for a member or role in this channel, taking into account channel overwrites. + * @param {GuildMemberResolvable|RoleResolvable} memberOrRole The member or role to obtain the overall permissions for + * @param {boolean} [checkAdmin=true] Whether having the {@link PermissionFlagsBits.Administrator} permission + * will return all permissions + * @returns {?Readonly<PermissionsBitField>} + */ + permissionsFor(memberOrRole, checkAdmin = true) { + const member = this.guild.members.resolve(memberOrRole); + if (member) return this.memberPermissions(member, checkAdmin); + const role = this.guild.roles.resolve(memberOrRole); + return role && this.rolePermissions(role, checkAdmin); + } + + overwritesFor(member, verified = false, roles = null) { + if (!verified) member = this.guild.members.resolve(member); + if (!member) return []; + + roles ??= member.roles.cache; + const roleOverwrites = []; + let memberOverwrites; + let everyoneOverwrites; + + for (const overwrite of this.permissionOverwrites.cache.values()) { + if (overwrite.id === this.guild.id) { + everyoneOverwrites = overwrite; + } else if (roles.has(overwrite.id)) { + roleOverwrites.push(overwrite); + } else if (overwrite.id === member.id) { + memberOverwrites = overwrite; + } + } + + return { + everyone: everyoneOverwrites, + roles: roleOverwrites, + member: memberOverwrites, + }; + } + + /** + * Gets the overall set of permissions for a member in this channel, taking into account channel overwrites. + * @param {GuildMember} member The member to obtain the overall permissions for + * @param {boolean} checkAdmin Whether having the {@link PermissionFlagsBits.Administrator} permission + * will return all permissions + * @returns {Readonly<PermissionsBitField>} + * @private + */ + memberPermissions(member, checkAdmin) { + if (checkAdmin && member.id === this.guild.ownerId) { + return new PermissionsBitField(PermissionsBitField.All).freeze(); + } + + const roles = member.roles.cache; + const permissions = new PermissionsBitField(roles.map(role => role.permissions)); + + if (checkAdmin && permissions.has(PermissionFlagsBits.Administrator)) { + return new PermissionsBitField(PermissionsBitField.All).freeze(); + } + + const overwrites = this.overwritesFor(member, true, roles); + + return permissions + .remove(overwrites.everyone?.deny ?? PermissionsBitField.DefaultBit) + .add(overwrites.everyone?.allow ?? PermissionsBitField.DefaultBit) + .remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.deny) : PermissionsBitField.DefaultBit) + .add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allow) : PermissionsBitField.DefaultBit) + .remove(overwrites.member?.deny ?? PermissionsBitField.DefaultBit) + .add(overwrites.member?.allow ?? PermissionsBitField.DefaultBit) + .freeze(); + } + + /** + * Gets the overall set of permissions for a role in this channel, taking into account channel overwrites. + * @param {Role} role The role to obtain the overall permissions for + * @param {boolean} checkAdmin Whether having the {@link PermissionFlagsBits.Administrator} permission + * will return all permissions + * @returns {Readonly<PermissionsBitField>} + * @private + */ + rolePermissions(role, checkAdmin) { + if (checkAdmin && role.permissions.has(PermissionFlagsBits.Administrator)) { + return new PermissionsBitField(PermissionsBitField.All).freeze(); + } + + const everyoneOverwrites = this.permissionOverwrites.cache.get(this.guild.id); + const roleOverwrites = this.permissionOverwrites.cache.get(role.id); + + return role.permissions + .remove(everyoneOverwrites?.deny ?? PermissionsBitField.DefaultBit) + .add(everyoneOverwrites?.allow ?? PermissionsBitField.DefaultBit) + .remove(roleOverwrites?.deny ?? PermissionsBitField.DefaultBit) + .add(roleOverwrites?.allow ?? PermissionsBitField.DefaultBit) + .freeze(); + } + + /** + * Locks in the permission overwrites from the parent channel. + * @returns {Promise<GuildChannel>} + */ + lockPermissions() { + if (!this.parent) return Promise.reject(new DiscordjsError(ErrorCodes.GuildChannelOrphan)); + const permissionOverwrites = this.parent.permissionOverwrites.cache.map(overwrite => overwrite.toJSON()); + return this.edit({ permissionOverwrites }); + } + + /** + * A collection of cached members of this channel, mapped by their ids. + * Members that can view this channel, if the channel is text-based. + * Members in the channel, if the channel is voice-based. + * @type {Collection<Snowflake, GuildMember>} + * @readonly + */ + get members() { + return this.guild.members.cache.filter(m => this.permissionsFor(m).has(PermissionFlagsBits.ViewChannel, false)); + } + + /** + * Edits the channel. + * @param {GuildChannelEditOptions} options The options to provide + * @returns {Promise<GuildChannel>} + * @example + * // Edit a channel + * channel.edit({ name: 'new-channel' }) + * .then(console.log) + * .catch(console.error); + */ + edit(options) { + return this.guild.channels.edit(this, options); + } + + /** + * Sets a new name for the guild channel. + * @param {string} name The new name for the guild channel + * @param {string} [reason] Reason for changing the guild channel's name + * @returns {Promise<GuildChannel>} + * @example + * // Set a new channel name + * channel.setName('not_general') + * .then(newChannel => console.log(`Channel's new name is ${newChannel.name}`)) + * .catch(console.error); + */ + setName(name, reason) { + return this.edit({ name, reason }); + } + + /** + * Options used to set the parent of a channel. + * @typedef {Object} SetParentOptions + * @property {boolean} [lockPermissions=true] Whether to lock the permissions to what the parent's permissions are + * @property {string} [reason] The reason for modifying the parent of the channel + */ + + /** + * Sets the parent of this channel. + * @param {?CategoryChannelResolvable} channel The category channel to set as the parent + * @param {SetParentOptions} [options={}] The options for setting the parent + * @returns {Promise<GuildChannel>} + * @example + * // Add a parent to a channel + * message.channel.setParent('355908108431917066', { lockPermissions: false }) + * .then(channel => console.log(`New parent of ${message.channel.name}: ${channel.name}`)) + * .catch(console.error); + */ + setParent(channel, { lockPermissions = true, reason } = {}) { + return this.edit({ + parent: channel ?? null, + lockPermissions, + reason, + }); + } + + /** + * Options used to set the position of a channel. + * @typedef {Object} SetChannelPositionOptions + * @property {boolean} [relative=false] Whether or not to change the position relative to its current value + * @property {string} [reason] The reason for changing the position + */ + + /** + * Sets a new position for the guild channel. + * @param {number} position The new position for the guild channel + * @param {SetChannelPositionOptions} [options] Options for setting position + * @returns {Promise<GuildChannel>} + * @example + * // Set a new channel position + * channel.setPosition(2) + * .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`)) + * .catch(console.error); + */ + setPosition(position, options = {}) { + return this.guild.channels.setPosition(this, position, options); + } + + /** + * Options used to clone a guild channel. + * @typedef {GuildChannelCreateOptions} GuildChannelCloneOptions + * @property {string} [name=this.name] Name of the new channel + */ + + /** + * Clones this channel. + * @param {GuildChannelCloneOptions} [options] The options for cloning this channel + * @returns {Promise<GuildChannel>} + */ + clone(options = {}) { + return this.guild.channels.create({ + name: options.name ?? this.name, + permissionOverwrites: this.permissionOverwrites.cache, + topic: this.topic, + type: this.type, + nsfw: this.nsfw, + parent: this.parent, + bitrate: this.bitrate, + userLimit: this.userLimit, + rateLimitPerUser: this.rateLimitPerUser, + position: this.rawPosition, + reason: null, + ...options, + }); + } + + /** + * Checks if this channel has the same type, topic, position, name, overwrites, and id as another channel. + * In most cases, a simple `channel.id === channel2.id` will do, and is much faster too. + * @param {GuildChannel} channel Channel to compare with + * @returns {boolean} + */ + equals(channel) { + let equal = + channel && + this.id === channel.id && + this.type === channel.type && + this.topic === channel.topic && + this.position === channel.position && + this.name === channel.name; + + if (equal) { + if (this.permissionOverwrites && channel.permissionOverwrites) { + equal = this.permissionOverwrites.cache.equals(channel.permissionOverwrites.cache); + } else { + equal = !this.permissionOverwrites && !channel.permissionOverwrites; + } + } + + return equal; + } + + /** + * Whether the channel is deletable by the client user + * @type {boolean} + * @readonly + */ + get deletable() { + return this.manageable && this.guild.rulesChannelId !== this.id && this.guild.publicUpdatesChannelId !== this.id; + } + + /** + * Whether the channel is manageable by the client user + * @type {boolean} + * @readonly + */ + get manageable() { + if (this.client.user.id === this.guild.ownerId) return true; + const permissions = this.permissionsFor(this.client.user); + if (!permissions) return false; + + // This flag allows managing even if timed out + if (permissions.has(PermissionFlagsBits.Administrator, false)) return true; + if (this.guild.members.me.communicationDisabledUntilTimestamp > Date.now()) return false; + + const bitfield = VoiceBasedChannelTypes.includes(this.type) + ? PermissionFlagsBits.ManageChannels | PermissionFlagsBits.Connect + : PermissionFlagsBits.ViewChannel | PermissionFlagsBits.ManageChannels; + return permissions.has(bitfield, false); + } + + /** + * Whether the channel is viewable by the client user + * @type {boolean} + * @readonly + */ + get viewable() { + if (this.client.user.id === this.guild.ownerId) return true; + const permissions = this.permissionsFor(this.client.user); + if (!permissions) return false; + return permissions.has(PermissionFlagsBits.ViewChannel, false); + } + + /** + * Deletes this channel. + * @param {string} [reason] Reason for deleting this channel + * @returns {Promise<GuildChannel>} + * @example + * // Delete the channel + * channel.delete('making room for new channels') + * .then(console.log) + * .catch(console.error); + */ + async delete(reason) { + await this.guild.channels.delete(this.id, reason); + return this; + } +} + +module.exports = GuildChannel; diff --git a/node_modules/discord.js/src/structures/GuildEmoji.js b/node_modules/discord.js/src/structures/GuildEmoji.js new file mode 100644 index 0000000..0035a36 --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildEmoji.js @@ -0,0 +1,148 @@ +'use strict'; + +const { PermissionFlagsBits } = require('discord-api-types/v10'); +const BaseGuildEmoji = require('./BaseGuildEmoji'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const GuildEmojiRoleManager = require('../managers/GuildEmojiRoleManager'); + +/** + * Represents a custom emoji. + * @extends {BaseGuildEmoji} + */ +class GuildEmoji extends BaseGuildEmoji { + constructor(client, data, guild) { + super(client, data, guild); + + /** + * The user who created this emoji + * @type {?User} + */ + this.author = null; + + /** + * Array of role ids this emoji is active for + * @name GuildEmoji#_roles + * @type {Snowflake[]} + * @private + */ + Object.defineProperty(this, '_roles', { value: [], writable: true }); + + this._patch(data); + } + + /** + * The guild this emoji is part of + * @type {Guild} + * @name GuildEmoji#guild + */ + + _clone() { + const clone = super._clone(); + clone._roles = this._roles.slice(); + return clone; + } + + _patch(data) { + super._patch(data); + + if (data.user) this.author = this.client.users._add(data.user); + if (data.roles) this._roles = data.roles; + } + + /** + * Whether the emoji is deletable by the client user + * @type {boolean} + * @readonly + */ + get deletable() { + if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe); + return !this.managed && this.guild.members.me.permissions.has(PermissionFlagsBits.ManageGuildExpressions); + } + + /** + * A manager for roles this emoji is active for. + * @type {GuildEmojiRoleManager} + * @readonly + */ + get roles() { + return new GuildEmojiRoleManager(this); + } + + /** + * Fetches the author for this emoji + * @returns {Promise<User>} + */ + fetchAuthor() { + return this.guild.emojis.fetchAuthor(this); + } + + /** + * Data for editing an emoji. + * @typedef {Object} GuildEmojiEditOptions + * @property {string} [name] The name of the emoji + * @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] Roles to restrict emoji to + * @property {string} [reason] Reason for editing this emoji + */ + + /** + * Edits the emoji. + * @param {GuildEmojiEditOptions} options The options to provide + * @returns {Promise<GuildEmoji>} + * @example + * // Edit an emoji + * emoji.edit({ name: 'newemoji' }) + * .then(e => console.log(`Edited emoji ${e}`)) + * .catch(console.error); + */ + edit(options) { + return this.guild.emojis.edit(this.id, options); + } + + /** + * Sets the name of the emoji. + * @param {string} name The new name for the emoji + * @param {string} [reason] Reason for changing the emoji's name + * @returns {Promise<GuildEmoji>} + */ + setName(name, reason) { + return this.edit({ name, reason }); + } + + /** + * Deletes the emoji. + * @param {string} [reason] Reason for deleting the emoji + * @returns {Promise<GuildEmoji>} + */ + async delete(reason) { + await this.guild.emojis.delete(this.id, reason); + return this; + } + + /** + * Whether this emoji is the same as another one. + * @param {GuildEmoji|APIEmoji} other The emoji to compare it to + * @returns {boolean} + */ + equals(other) { + if (other instanceof GuildEmoji) { + return ( + other.id === this.id && + other.name === this.name && + other.managed === this.managed && + other.available === this.available && + other.requiresColons === this.requiresColons && + other.roles.cache.size === this.roles.cache.size && + other.roles.cache.every(role => this.roles.cache.has(role.id)) + ); + } else { + return ( + other.id === this.id && + other.name === this.name && + other.roles.length === this.roles.cache.size && + other.roles.every(role => this.roles.cache.has(role)) + ); + } + } +} + +module.exports = GuildEmoji; diff --git a/node_modules/discord.js/src/structures/GuildMember.js b/node_modules/discord.js/src/structures/GuildMember.js new file mode 100644 index 0000000..8806b50 --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildMember.js @@ -0,0 +1,520 @@ +'use strict'; + +const { PermissionFlagsBits } = require('discord-api-types/v10'); +const Base = require('./Base'); +const VoiceState = require('./VoiceState'); +const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager'); +const { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField'); +const PermissionsBitField = require('../util/PermissionsBitField'); + +/** + * Represents a member of a guild on Discord. + * @implements {TextBasedChannel} + * @extends {Base} + */ +class GuildMember extends Base { + constructor(client, data, guild) { + super(client); + + /** + * The guild that this member is part of + * @type {Guild} + */ + this.guild = guild; + + /** + * The timestamp the member joined the guild at + * @type {?number} + */ + this.joinedTimestamp = null; + + /** + * The last timestamp this member started boosting the guild + * @type {?number} + */ + this.premiumSinceTimestamp = null; + + /** + * The nickname of this member, if they have one + * @type {?string} + */ + this.nickname = null; + + /** + * Whether this member has yet to pass the guild's membership gate + * @type {?boolean} + */ + this.pending = null; + + /** + * The timestamp this member's timeout will be removed + * @type {?number} + */ + this.communicationDisabledUntilTimestamp = null; + + /** + * The role ids of the member + * @name GuildMember#_roles + * @type {Snowflake[]} + * @private + */ + Object.defineProperty(this, '_roles', { value: [], writable: true }); + + if (data) this._patch(data); + } + + _patch(data) { + if ('user' in data) { + /** + * The user that this guild member instance represents + * @type {?User} + */ + this.user = this.client.users._add(data.user, true); + } + + if ('nick' in data) this.nickname = data.nick; + if ('avatar' in data) { + /** + * The guild member's avatar hash + * @type {?string} + */ + this.avatar = data.avatar; + } else if (typeof this.avatar !== 'string') { + this.avatar = null; + } + if ('joined_at' in data) this.joinedTimestamp = Date.parse(data.joined_at); + if ('premium_since' in data) { + this.premiumSinceTimestamp = data.premium_since ? Date.parse(data.premium_since) : null; + } + if ('roles' in data) this._roles = data.roles; + + if ('pending' in data) { + this.pending = data.pending; + } else if (!this.partial) { + // See https://github.com/discordjs/discord.js/issues/6546 for more info. + this.pending ??= false; + } + + if ('communication_disabled_until' in data) { + this.communicationDisabledUntilTimestamp = + data.communication_disabled_until && Date.parse(data.communication_disabled_until); + } + + if ('flags' in data) { + /** + * The flags of this member + * @type {Readonly<GuildMemberFlagsBitField>} + */ + this.flags = new GuildMemberFlagsBitField(data.flags).freeze(); + } else { + this.flags ??= new GuildMemberFlagsBitField().freeze(); + } + } + + _clone() { + const clone = super._clone(); + clone._roles = this._roles.slice(); + return clone; + } + + /** + * Whether this GuildMember is a partial + * @type {boolean} + * @readonly + */ + get partial() { + return this.joinedTimestamp === null; + } + + /** + * A manager for the roles belonging to this member + * @type {GuildMemberRoleManager} + * @readonly + */ + get roles() { + return new GuildMemberRoleManager(this); + } + + /** + * The voice state of this member + * @type {VoiceState} + * @readonly + */ + get voice() { + return this.guild.voiceStates.cache.get(this.id) ?? new VoiceState(this.guild, { user_id: this.id }); + } + + /** + * A link to the member's guild avatar. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + avatarURL(options = {}) { + return this.avatar && this.client.rest.cdn.guildMemberAvatar(this.guild.id, this.id, this.avatar, options); + } + + /** + * A link to the member's guild avatar if they have one. + * Otherwise, a link to their {@link User#displayAvatarURL} will be returned. + * @param {ImageURLOptions} [options={}] Options for the Image URL + * @returns {string} + */ + displayAvatarURL(options) { + return this.avatarURL(options) ?? this.user.displayAvatarURL(options); + } + + /** + * The time this member joined the guild + * @type {?Date} + * @readonly + */ + get joinedAt() { + return this.joinedTimestamp && new Date(this.joinedTimestamp); + } + + /** + * The time this member's timeout will be removed + * @type {?Date} + * @readonly + */ + get communicationDisabledUntil() { + return this.communicationDisabledUntilTimestamp && new Date(this.communicationDisabledUntilTimestamp); + } + + /** + * The last time this member started boosting the guild + * @type {?Date} + * @readonly + */ + get premiumSince() { + return this.premiumSinceTimestamp && new Date(this.premiumSinceTimestamp); + } + + /** + * The presence of this guild member + * @type {?Presence} + * @readonly + */ + get presence() { + return this.guild.presences.resolve(this.id); + } + + /** + * The displayed color of this member in base 10 + * @type {number} + * @readonly + */ + get displayColor() { + return this.roles.color?.color ?? 0; + } + + /** + * The displayed color of this member in hexadecimal + * @type {string} + * @readonly + */ + get displayHexColor() { + return this.roles.color?.hexColor ?? '#000000'; + } + + /** + * The member's id + * @type {Snowflake} + * @readonly + */ + get id() { + return this.user.id; + } + + /** + * The DM between the client's user and this member + * @type {?DMChannel} + * @readonly + */ + get dmChannel() { + return this.client.users.dmChannel(this.id); + } + + /** + * The nickname of this member, or their user display name if they don't have one + * @type {?string} + * @readonly + */ + get displayName() { + return this.nickname ?? this.user.displayName; + } + + /** + * The overall set of permissions for this member, taking only roles and owner status into account + * @type {Readonly<PermissionsBitField>} + * @readonly + */ + get permissions() { + if (this.user.id === this.guild.ownerId) return new PermissionsBitField(PermissionsBitField.All).freeze(); + return new PermissionsBitField(this.roles.cache.map(role => role.permissions)).freeze(); + } + + /** + * Whether the client user is above this user in the hierarchy, according to role position and guild ownership. + * This is a prerequisite for many moderative actions. + * @type {boolean} + * @readonly + */ + get manageable() { + if (this.user.id === this.guild.ownerId) return false; + if (this.user.id === this.client.user.id) return false; + if (this.client.user.id === this.guild.ownerId) return true; + if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe); + return this.guild.members.me.roles.highest.comparePositionTo(this.roles.highest) > 0; + } + + /** + * Whether this member is kickable by the client user + * @type {boolean} + * @readonly + */ + get kickable() { + if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe); + return this.manageable && this.guild.members.me.permissions.has(PermissionFlagsBits.KickMembers); + } + + /** + * Whether this member is bannable by the client user + * @type {boolean} + * @readonly + */ + get bannable() { + if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe); + return this.manageable && this.guild.members.me.permissions.has(PermissionFlagsBits.BanMembers); + } + + /** + * Whether this member is moderatable by the client user + * @type {boolean} + * @readonly + */ + get moderatable() { + return ( + !this.permissions.has(PermissionFlagsBits.Administrator) && + this.manageable && + (this.guild.members.me?.permissions.has(PermissionFlagsBits.ModerateMembers) ?? false) + ); + } + + /** + * Whether this member is currently timed out + * @returns {boolean} + */ + isCommunicationDisabled() { + return this.communicationDisabledUntilTimestamp > Date.now(); + } + + /** + * Returns `channel.permissionsFor(guildMember)`. Returns permissions for a member in a guild channel, + * taking into account roles and permission overwrites. + * @param {GuildChannelResolvable} channel The guild channel to use as context + * @returns {Readonly<PermissionsBitField>} + */ + permissionsIn(channel) { + channel = this.guild.channels.resolve(channel); + if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve); + return channel.permissionsFor(this); + } + + /** + * Edits this member. + * @param {GuildMemberEditOptions} options The options to provide + * @returns {Promise<GuildMember>} + */ + edit(options) { + return this.guild.members.edit(this, options); + } + + /** + * Sets the flags for this member. + * @param {GuildMemberFlagsResolvable} flags The flags to set + * @param {string} [reason] Reason for setting the flags + * @returns {Promise<GuildMember>} + */ + setFlags(flags, reason) { + return this.edit({ flags, reason }); + } + + /** + * Sets the nickname for this member. + * @param {?string} nick The nickname for the guild member, or `null` if you want to reset their nickname + * @param {string} [reason] Reason for setting the nickname + * @returns {Promise<GuildMember>} + * @example + * // Set a nickname for a guild member + * guildMember.setNickname('cool nickname', 'Needed a new nickname') + * .then(member => console.log(`Set nickname of ${member.user.username}`)) + * .catch(console.error); + * @example + * // Remove a nickname for a guild member + * guildMember.setNickname(null, 'No nicknames allowed!') + * .then(member => console.log(`Removed nickname for ${member.user.username}`)) + * .catch(console.error); + */ + setNickname(nick, reason) { + return this.edit({ nick, reason }); + } + + /** + * Creates a DM channel between the client and this member. + * @param {boolean} [force=false] Whether to skip the cache check and request the API + * @returns {Promise<DMChannel>} + */ + createDM(force = false) { + return this.user.createDM(force); + } + + /** + * Deletes any DMs with this member. + * @returns {Promise<DMChannel>} + */ + deleteDM() { + return this.user.deleteDM(); + } + + /** + * Kicks this member from the guild. + * @param {string} [reason] Reason for kicking user + * @returns {Promise<GuildMember>} + */ + kick(reason) { + return this.guild.members.kick(this, reason); + } + + /** + * Bans this guild member. + * @param {BanOptions} [options] Options for the ban + * @returns {Promise<GuildMember>} + * @example + * // Ban a guild member, deleting a week's worth of messages + * guildMember.ban({ deleteMessageSeconds: 60 * 60 * 24 * 7, reason: 'They deserved it' }) + * .then(console.log) + * .catch(console.error); + */ + ban(options) { + return this.guild.bans.create(this, options); + } + + /** + * Times this guild member out. + * @param {DateResolvable|null} communicationDisabledUntil The date or timestamp + * for the member's communication to be disabled until. Provide `null` to remove the timeout. + * @param {string} [reason] The reason for this timeout. + * @returns {Promise<GuildMember>} + * @example + * // Time a guild member out for 5 minutes + * guildMember.disableCommunicationUntil(Date.now() + (5 * 60 * 1000), 'They deserved it') + * .then(console.log) + * .catch(console.error); + * @example + * // Remove the timeout of a guild member + * guildMember.disableCommunicationUntil(null) + * .then(member => console.log(`Removed timeout for ${member.displayName}`)) + * .catch(console.error); + */ + disableCommunicationUntil(communicationDisabledUntil, reason) { + return this.edit({ communicationDisabledUntil, reason }); + } + + /** + * Times this guild member out. + * @param {number|null} timeout The time in milliseconds + * for the member's communication to be disabled until. Provide `null` to remove the timeout. + * @param {string} [reason] The reason for this timeout. + * @returns {Promise<GuildMember>} + * @example + * // Time a guild member out for 5 minutes + * guildMember.timeout(5 * 60 * 1000, 'They deserved it') + * .then(console.log) + * .catch(console.error); + */ + timeout(timeout, reason) { + return this.disableCommunicationUntil(timeout && Date.now() + timeout, reason); + } + + /** + * Fetches this GuildMember. + * @param {boolean} [force=true] Whether to skip the cache check and request the API + * @returns {Promise<GuildMember>} + */ + fetch(force = true) { + return this.guild.members.fetch({ user: this.id, cache: true, force }); + } + + /** + * Whether this guild member equals another guild member. It compares all properties, so for most + * comparison it is advisable to just compare `member.id === member2.id` as it is significantly faster + * and is often what most users need. + * @param {GuildMember} member The member to compare with + * @returns {boolean} + */ + equals(member) { + return ( + member instanceof this.constructor && + this.id === member.id && + this.partial === member.partial && + this.guild.id === member.guild.id && + this.joinedTimestamp === member.joinedTimestamp && + this.nickname === member.nickname && + this.avatar === member.avatar && + this.pending === member.pending && + this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp && + this.flags.bitfield === member.flags.bitfield && + (this._roles === member._roles || + (this._roles.length === member._roles.length && this._roles.every((role, i) => role === member._roles[i]))) + ); + } + + /** + * When concatenated with a string, this automatically returns the user's mention instead of the GuildMember object. + * @returns {string} + * @example + * // Logs: Hello from <@123456789012345678>! + * console.log(`Hello from ${member}!`); + */ + toString() { + return this.user.toString(); + } + + toJSON() { + const json = super.toJSON({ + guild: 'guildId', + user: 'userId', + displayName: true, + roles: true, + }); + json.avatarURL = this.avatarURL(); + json.displayAvatarURL = this.displayAvatarURL(); + return json; + } +} + +/** + * Sends a message to this user. + * @method send + * @memberof GuildMember + * @instance + * @param {string|MessagePayload|MessageCreateOptions} options The options to provide + * @returns {Promise<Message>} + * @example + * // Send a direct message + * guildMember.send('Hello!') + * .then(message => console.log(`Sent message: ${message.content} to ${guildMember.displayName}`)) + * .catch(console.error); + */ + +TextBasedChannel.applyToClass(GuildMember); + +exports.GuildMember = GuildMember; + +/** + * @external APIGuildMember + * @see {@link https://discord.com/developers/docs/resources/guild#guild-member-object} + */ diff --git a/node_modules/discord.js/src/structures/GuildOnboarding.js b/node_modules/discord.js/src/structures/GuildOnboarding.js new file mode 100644 index 0000000..119f905 --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildOnboarding.js @@ -0,0 +1,58 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Base = require('./Base'); +const { GuildOnboardingPrompt } = require('./GuildOnboardingPrompt'); + +/** + * Represents the onboarding data of a guild. + * @extends {Base} + */ +class GuildOnboarding extends Base { + constructor(client, data) { + super(client); + + /** + * The id of the guild this onboarding data is for + * @type {Snowflake} + */ + this.guildId = data.guild_id; + + const guild = this.guild; + + /** + * The prompts shown during onboarding and in customize community + * @type {Collection<Snowflake, GuildOnboardingPrompt>} + */ + this.prompts = data.prompts.reduce( + (prompts, prompt) => prompts.set(prompt.id, new GuildOnboardingPrompt(client, prompt, this.guildId)), + new Collection(), + ); + + /** + * The ids of the channels that new members get opted into automatically + * @type {Collection<Snowflake, GuildChannel>} + */ + this.defaultChannels = data.default_channel_ids.reduce( + (channels, channelId) => channels.set(channelId, guild.channels.cache.get(channelId)), + new Collection(), + ); + + /** + * Whether onboarding is enabled + * @type {boolean} + */ + this.enabled = data.enabled; + } + + /** + * The guild this onboarding is from + * @type {Guild} + * @readonly + */ + get guild() { + return this.client.guilds.cache.get(this.guildId); + } +} + +exports.GuildOnboarding = GuildOnboarding; diff --git a/node_modules/discord.js/src/structures/GuildOnboardingPrompt.js b/node_modules/discord.js/src/structures/GuildOnboardingPrompt.js new file mode 100644 index 0000000..4de3f5d --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildOnboardingPrompt.js @@ -0,0 +1,78 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Base = require('./Base'); +const { GuildOnboardingPromptOption } = require('./GuildOnboardingPromptOption'); + +/** + * Represents the data of a prompt of a guilds onboarding. + * @extends {Base} + */ +class GuildOnboardingPrompt extends Base { + constructor(client, data, guildId) { + super(client); + + /** + * The id of the guild this onboarding prompt is from + * @type {Snowflake} + */ + this.guildId = guildId; + + /** + * The id of the prompt + * @type {Snowflake} + */ + this.id = data.id; + + /** + * The options available within the prompt + * @type {Collection<Snowflake, GuildOnboardingPromptOption>} + */ + this.options = data.options.reduce( + (options, option) => options.set(option.id, new GuildOnboardingPromptOption(client, option, guildId)), + new Collection(), + ); + + /** + * The title of the prompt + * @type {string} + */ + this.title = data.title; + + /** + * Whether users are limited to selecting one option for the prompt + * @type {boolean} + */ + this.singleSelect = data.single_select; + + /** + * Whether the prompt is required before a user completes the onboarding flow + * @type {boolean} + */ + this.required = data.required; + + /** + * Whether the prompt is present in the onboarding flow. + * If `false`, the prompt will only appear in the Channels & Roles tab + * @type {boolean} + */ + this.inOnboarding = data.in_onboarding; + + /** + * The type of the prompt + * @type {GuildOnboardingPromptType} + */ + this.type = data.type; + } + + /** + * The guild this onboarding prompt is from + * @type {Guild} + * @readonly + */ + get guild() { + return this.client.guilds.cache.get(this.guildId); + } +} + +exports.GuildOnboardingPrompt = GuildOnboardingPrompt; diff --git a/node_modules/discord.js/src/structures/GuildOnboardingPromptOption.js b/node_modules/discord.js/src/structures/GuildOnboardingPromptOption.js new file mode 100644 index 0000000..3002144 --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildOnboardingPromptOption.js @@ -0,0 +1,84 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Base = require('./Base'); +const { resolvePartialEmoji } = require('../util/Util'); + +/** + * Represents the data of an option from a prompt of a guilds onboarding. + * @extends {Base} + */ +class GuildOnboardingPromptOption extends Base { + constructor(client, data, guildId) { + super(client); + + /** + * The id of the guild this onboarding prompt option is from + * @type {Snowflake} + */ + this.guildId = guildId; + + const guild = this.guild; + + /** + * The id of the option + * @type {Snowflake} + */ + this.id = data.id; + + /** + * The channels a member is added to when the option is selected + * @type {Collection<Snowflake, GuildChannel>} + */ + this.channels = data.channel_ids.reduce( + (channels, channelId) => channels.set(channelId, guild.channels.cache.get(channelId)), + new Collection(), + ); + + /** + * The roles assigned to a member when the option is selected + * @type {Collection<Snowflake, Role>} + */ + this.roles = data.role_ids.reduce( + (roles, roleId) => roles.set(roleId, guild.roles.cache.get(roleId)), + new Collection(), + ); + + /** + * The data for an emoji of a guilds onboarding prompt option + * @typedef {Object} GuildOnboardingPromptOptionEmoji + * @property {?Snowflake} id The id of the emoji + * @property {string} name The name of the emoji + * @property {boolean} animated Whether the emoji is animated + */ + + /** + * The emoji of the option + * @type {?GuildOnboardingPromptOptionEmoji} + */ + this.emoji = resolvePartialEmoji(data.emoji); + + /** + * The title of the option + * @type {string} + */ + this.title = data.title; + + /** + * The description of the option + * @type {?string} + */ + this.description = data.description; + } + + /** + * The guild this onboarding prompt option is from + * @type {Guild} + * @readonly + */ + get guild() { + return this.client.guilds.cache.get(this.guildId); + } +} + +exports.GuildOnboardingPromptOption = GuildOnboardingPromptOption; diff --git a/node_modules/discord.js/src/structures/GuildPreview.js b/node_modules/discord.js/src/structures/GuildPreview.js new file mode 100644 index 0000000..6ff2026 --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildPreview.js @@ -0,0 +1,193 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { Routes } = require('discord-api-types/v10'); +const Base = require('./Base'); +const GuildPreviewEmoji = require('./GuildPreviewEmoji'); +const { Sticker } = require('./Sticker'); + +/** + * Represents the data about the guild any bot can preview, connected to the specified guild. + * @extends {Base} + */ +class GuildPreview extends Base { + constructor(client, data) { + super(client); + + if (!data) return; + + this._patch(data); + } + + _patch(data) { + /** + * The id of this guild + * @type {string} + */ + this.id = data.id; + + if ('name' in data) { + /** + * The name of this guild + * @type {string} + */ + this.name = data.name; + } + + if ('icon' in data) { + /** + * The icon of this guild + * @type {?string} + */ + this.icon = data.icon; + } + + if ('splash' in data) { + /** + * The splash icon of this guild + * @type {?string} + */ + this.splash = data.splash; + } + + if ('discovery_splash' in data) { + /** + * The discovery splash icon of this guild + * @type {?string} + */ + this.discoverySplash = data.discovery_splash; + } + + if ('features' in data) { + /** + * An array of enabled guild features + * @type {GuildFeature[]} + */ + this.features = data.features; + } + + if ('approximate_member_count' in data) { + /** + * The approximate count of members in this guild + * @type {number} + */ + this.approximateMemberCount = data.approximate_member_count; + } + + if ('approximate_presence_count' in data) { + /** + * The approximate count of online members in this guild + * @type {number} + */ + this.approximatePresenceCount = data.approximate_presence_count; + } + + if ('description' in data) { + /** + * The description for this guild + * @type {?string} + */ + this.description = data.description; + } else { + this.description ??= null; + } + + if (!this.emojis) { + /** + * Collection of emojis belonging to this guild + * @type {Collection<Snowflake, GuildPreviewEmoji>} + */ + this.emojis = new Collection(); + } else { + this.emojis.clear(); + } + for (const emoji of data.emojis) { + this.emojis.set(emoji.id, new GuildPreviewEmoji(this.client, emoji, this)); + } + + /** + * Collection of stickers belonging to this guild + * @type {Collection<Snowflake, Sticker>} + */ + this.stickers = data.stickers.reduce( + (stickers, sticker) => stickers.set(sticker.id, new Sticker(this.client, sticker)), + new Collection(), + ); + } + + /** + * The timestamp this guild was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time this guild was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The URL to this guild's splash. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + splashURL(options = {}) { + return this.splash && this.client.rest.cdn.splash(this.id, this.splash, options); + } + + /** + * The URL to this guild's discovery splash. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + discoverySplashURL(options = {}) { + return this.discoverySplash && this.client.rest.cdn.discoverySplash(this.id, this.discoverySplash, options); + } + + /** + * The URL to this guild's icon. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + iconURL(options = {}) { + return this.icon && this.client.rest.cdn.icon(this.id, this.icon, options); + } + + /** + * Fetches this guild. + * @returns {Promise<GuildPreview>} + */ + async fetch() { + const data = await this.client.rest.get(Routes.guildPreview(this.id)); + this._patch(data); + return this; + } + + /** + * When concatenated with a string, this automatically returns the guild's name instead of the Guild object. + * @returns {string} + * @example + * // Logs: Hello from My Guild! + * console.log(`Hello from ${previewGuild}!`); + */ + toString() { + return this.name; + } + + toJSON() { + const json = super.toJSON(); + json.iconURL = this.iconURL(); + json.splashURL = this.splashURL(); + return json; + } +} + +module.exports = GuildPreview; diff --git a/node_modules/discord.js/src/structures/GuildPreviewEmoji.js b/node_modules/discord.js/src/structures/GuildPreviewEmoji.js new file mode 100644 index 0000000..144b41d --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildPreviewEmoji.js @@ -0,0 +1,27 @@ +'use strict'; + +const BaseGuildEmoji = require('./BaseGuildEmoji'); + +/** + * Represents an instance of an emoji belonging to a public guild obtained through Discord's preview endpoint. + * @extends {BaseGuildEmoji} + */ +class GuildPreviewEmoji extends BaseGuildEmoji { + /** + * The public guild this emoji is part of + * @type {GuildPreview} + * @name GuildPreviewEmoji#guild + */ + + constructor(client, data, guild) { + super(client, data, guild); + + /** + * The roles this emoji is active for + * @type {Snowflake[]} + */ + this.roles = data.roles; + } +} + +module.exports = GuildPreviewEmoji; diff --git a/node_modules/discord.js/src/structures/GuildScheduledEvent.js b/node_modules/discord.js/src/structures/GuildScheduledEvent.js new file mode 100644 index 0000000..e9a37b2 --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildScheduledEvent.js @@ -0,0 +1,439 @@ +'use strict'; + +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { GuildScheduledEventStatus, GuildScheduledEventEntityType, RouteBases } = require('discord-api-types/v10'); +const Base = require('./Base'); +const { DiscordjsError, ErrorCodes } = require('../errors'); + +/** + * Represents a scheduled event in a {@link Guild}. + * @extends {Base} + */ +class GuildScheduledEvent extends Base { + constructor(client, data) { + super(client); + + /** + * The id of the guild scheduled event + * @type {Snowflake} + */ + this.id = data.id; + + /** + * The id of the guild this guild scheduled event belongs to + * @type {Snowflake} + */ + this.guildId = data.guild_id; + + this._patch(data); + } + + _patch(data) { + if ('channel_id' in data) { + /** + * The channel id in which the scheduled event will be hosted, + * or `null` if entity type is {@link GuildScheduledEventEntityType.External} + * @type {?Snowflake} + */ + this.channelId = data.channel_id; + } else { + this.channelId ??= null; + } + + if ('creator_id' in data) { + /** + * The id of the user that created this guild scheduled event + * @type {?Snowflake} + */ + this.creatorId = data.creator_id; + } else { + this.creatorId ??= null; + } + + /** + * The name of the guild scheduled event + * @type {string} + */ + this.name = data.name; + + if ('description' in data) { + /** + * The description of the guild scheduled event + * @type {?string} + */ + this.description = data.description; + } else { + this.description ??= null; + } + + /** + * The timestamp the guild scheduled event will start at + * <info>This can be potentially `null` only when it's an {@link AuditLogEntryTarget}</info> + * @type {?number} + */ + this.scheduledStartTimestamp = data.scheduled_start_time ? Date.parse(data.scheduled_start_time) : null; + + /** + * The timestamp the guild scheduled event will end at, + * or `null` if the event does not have a scheduled time to end + * @type {?number} + */ + this.scheduledEndTimestamp = data.scheduled_end_time ? Date.parse(data.scheduled_end_time) : null; + + /** + * The privacy level of the guild scheduled event + * @type {GuildScheduledEventPrivacyLevel} + */ + this.privacyLevel = data.privacy_level; + + /** + * The status of the guild scheduled event + * @type {GuildScheduledEventStatus} + */ + this.status = data.status; + + /** + * The type of hosting entity associated with the scheduled event + * @type {GuildScheduledEventEntityType} + */ + this.entityType = data.entity_type; + + if ('entity_id' in data) { + /** + * The id of the hosting entity associated with the scheduled event + * @type {?Snowflake} + */ + this.entityId = data.entity_id; + } else { + this.entityId ??= null; + } + + if ('user_count' in data) { + /** + * The number of users who are subscribed to this guild scheduled event + * @type {?number} + */ + this.userCount = data.user_count; + } else { + this.userCount ??= null; + } + + if ('creator' in data) { + /** + * The user that created this guild scheduled event + * @type {?User} + */ + this.creator = this.client.users._add(data.creator); + } else { + this.creator ??= this.client.users.resolve(this.creatorId); + } + + /* eslint-disable max-len */ + /** + * Represents the additional metadata for a {@link GuildScheduledEvent} + * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-metadata} + * @typedef {Object} GuildScheduledEventEntityMetadata + * @property {?string} location The location of the guild scheduled event + */ + /* eslint-enable max-len */ + + if ('entity_metadata' in data) { + if (data.entity_metadata) { + /** + * Additional metadata + * @type {?GuildScheduledEventEntityMetadata} + */ + this.entityMetadata = { + location: data.entity_metadata.location ?? this.entityMetadata?.location ?? null, + }; + } else { + this.entityMetadata = null; + } + } else { + this.entityMetadata ??= null; + } + + if ('image' in data) { + /** + * The cover image hash for this scheduled event + * @type {?string} + */ + this.image = data.image; + } else { + this.image ??= null; + } + } + + /** + * The URL of this scheduled event's cover image + * @param {BaseImageURLOptions} [options={}] Options for image URL + * @returns {?string} + */ + coverImageURL(options = {}) { + return this.image && this.client.rest.cdn.guildScheduledEventCover(this.id, this.image, options); + } + + /** + * The timestamp the guild scheduled event was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the guild scheduled event was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The time the guild scheduled event will start at + * <info>This can be potentially `null` only when it's an {@link AuditLogEntryTarget}</info> + * @type {?Date} + * @readonly + */ + get scheduledStartAt() { + return this.scheduledStartTimestamp && new Date(this.scheduledStartTimestamp); + } + + /** + * The time the guild scheduled event will end at, + * or `null` if the event does not have a scheduled time to end + * @type {?Date} + * @readonly + */ + get scheduledEndAt() { + return this.scheduledEndTimestamp && new Date(this.scheduledEndTimestamp); + } + + /** + * The channel associated with this scheduled event + * @type {?(VoiceChannel|StageChannel)} + * @readonly + */ + get channel() { + return this.client.channels.resolve(this.channelId); + } + + /** + * The guild this scheduled event belongs to + * @type {?Guild} + * @readonly + */ + get guild() { + return this.client.guilds.resolve(this.guildId); + } + + /** + * The URL to the guild scheduled event + * @type {string} + * @readonly + */ + get url() { + return `${RouteBases.scheduledEvent}/${this.guildId}/${this.id}`; + } + + /** + * Options used to create an invite URL to a {@link GuildScheduledEvent} + * @typedef {InviteCreateOptions} GuildScheduledEventInviteURLCreateOptions + * @property {GuildInvitableChannelResolvable} [channel] The channel to create the invite in. + * <warn>This is required when the `entityType` of `GuildScheduledEvent` is + * {@link GuildScheduledEventEntityType.External}, gets ignored otherwise</warn> + */ + + /** + * Creates an invite URL to this guild scheduled event. + * @param {GuildScheduledEventInviteURLCreateOptions} [options] The options to create the invite + * @returns {Promise<string>} + */ + async createInviteURL(options) { + let channelId = this.channelId; + if (this.entityType === GuildScheduledEventEntityType.External) { + if (!options?.channel) throw new DiscordjsError(ErrorCodes.InviteOptionsMissingChannel); + channelId = this.guild.channels.resolveId(options.channel); + if (!channelId) throw new DiscordjsError(ErrorCodes.GuildChannelResolve); + } + const invite = await this.guild.invites.create(channelId, options); + return `${RouteBases.invite}/${invite.code}?event=${this.id}`; + } + + /** + * Edits this guild scheduled event. + * @param {GuildScheduledEventEditOptions} options The options to edit the guild scheduled event + * @returns {Promise<GuildScheduledEvent>} + * @example + * // Edit a guild scheduled event + * guildScheduledEvent.edit({ name: 'Party' }) + * .then(guildScheduledEvent => console.log(guildScheduledEvent)) + * .catch(console.error); + */ + edit(options) { + return this.guild.scheduledEvents.edit(this.id, options); + } + + /** + * Deletes this guild scheduled event. + * @returns {Promise<GuildScheduledEvent>} + * @example + * // Delete a guild scheduled event + * guildScheduledEvent.delete() + * .then(guildScheduledEvent => console.log(guildScheduledEvent)) + * .catch(console.error); + */ + async delete() { + await this.guild.scheduledEvents.delete(this.id); + return this; + } + + /** + * Sets a new name for the guild scheduled event. + * @param {string} name The new name of the guild scheduled event + * @param {string} [reason] The reason for changing the name + * @returns {Promise<GuildScheduledEvent>} + * @example + * // Set name of a guild scheduled event + * guildScheduledEvent.setName('Birthday Party') + * .then(guildScheduledEvent => console.log(`Set the name to: ${guildScheduledEvent.name}`)) + * .catch(console.error); + */ + setName(name, reason) { + return this.edit({ name, reason }); + } + + /** + * Sets a new time to schedule the event at. + * @param {DateResolvable} scheduledStartTime The time to schedule the event at + * @param {string} [reason] The reason for changing the scheduled start time + * @returns {Promise<GuildScheduledEvent>} + * @example + * // Set start time of a guild scheduled event + * guildScheduledEvent.setScheduledStartTime('2022-09-24T00:00:00+05:30') + * .then(guildScheduledEvent => console.log(`Set the start time to: ${guildScheduledEvent.scheduledStartTime}`)) + * .catch(console.error); + */ + setScheduledStartTime(scheduledStartTime, reason) { + return this.edit({ scheduledStartTime, reason }); + } + + // TODO: scheduledEndTime gets reset on passing null but it hasn't been documented + /** + * Sets a new time to end the event at. + * @param {DateResolvable} scheduledEndTime The time to end the event at + * @param {string} [reason] The reason for changing the scheduled end time + * @returns {Promise<GuildScheduledEvent>} + * @example + * // Set end time of a guild scheduled event + * guildScheduledEvent.setScheduledEndTime('2022-09-25T00:00:00+05:30') + * .then(guildScheduledEvent => console.log(`Set the end time to: ${guildScheduledEvent.scheduledEndTime}`)) + * .catch(console.error); + */ + setScheduledEndTime(scheduledEndTime, reason) { + return this.edit({ scheduledEndTime, reason }); + } + + /** + * Sets the new description of the guild scheduled event. + * @param {string} description The description of the guild scheduled event + * @param {string} [reason] The reason for changing the description + * @returns {Promise<GuildScheduledEvent>} + * @example + * // Set description of a guild scheduled event + * guildScheduledEvent.setDescription('A virtual birthday party') + * .then(guildScheduledEvent => console.log(`Set the description to: ${guildScheduledEvent.description}`)) + * .catch(console.error); + */ + setDescription(description, reason) { + return this.edit({ description, reason }); + } + + /** + * Sets the new status of the guild scheduled event. + * <info>If you're working with TypeScript, use this method in conjunction with status type-guards + * like {@link GuildScheduledEvent#isScheduled} to get only valid status as suggestion</info> + * @param {GuildScheduledEventStatus} status The status of the guild scheduled event + * @param {string} [reason] The reason for changing the status + * @returns {Promise<GuildScheduledEvent>} + * @example + * // Set status of a guild scheduled event + * guildScheduledEvent.setStatus(GuildScheduledEventStatus.Active) + * .then(guildScheduledEvent => console.log(`Set the status to: ${guildScheduledEvent.status}`)) + * .catch(console.error); + */ + setStatus(status, reason) { + return this.edit({ status, reason }); + } + + /** + * Sets the new location of the guild scheduled event. + * @param {string} location The location of the guild scheduled event + * @param {string} [reason] The reason for changing the location + * @returns {Promise<GuildScheduledEvent>} + * @example + * // Set location of a guild scheduled event + * guildScheduledEvent.setLocation('Earth') + * .then(guildScheduledEvent => console.log(`Set the location to: ${guildScheduledEvent.entityMetadata.location}`)) + * .catch(console.error); + */ + setLocation(location, reason) { + return this.edit({ entityMetadata: { location }, reason }); + } + + /** + * Fetches subscribers of this guild scheduled event. + * @param {FetchGuildScheduledEventSubscribersOptions} [options] Options for fetching the subscribers + * @returns {Promise<Collection<Snowflake, GuildScheduledEventUser>>} + */ + fetchSubscribers(options) { + return this.guild.scheduledEvents.fetchSubscribers(this.id, options); + } + + /** + * When concatenated with a string, this automatically concatenates the event's URL instead of the object. + * @returns {string} + * @example + * // Logs: Event: https://discord.com/events/412345678901234567/499876543211234567 + * console.log(`Event: ${guildScheduledEvent}`); + */ + toString() { + return this.url; + } + + /** + * Indicates whether this guild scheduled event has an {@link GuildScheduledEventStatus.Active} status. + * @returns {boolean} + */ + isActive() { + return this.status === GuildScheduledEventStatus.Active; + } + + /** + * Indicates whether this guild scheduled event has a {@link GuildScheduledEventStatus.Canceled} status. + * @returns {boolean} + */ + isCanceled() { + return this.status === GuildScheduledEventStatus.Canceled; + } + + /** + * Indicates whether this guild scheduled event has a {@link GuildScheduledEventStatus.Completed} status. + * @returns {boolean} + */ + isCompleted() { + return this.status === GuildScheduledEventStatus.Completed; + } + + /** + * Indicates whether this guild scheduled event has a {@link GuildScheduledEventStatus.Scheduled} status. + * @returns {boolean} + */ + isScheduled() { + return this.status === GuildScheduledEventStatus.Scheduled; + } +} + +exports.GuildScheduledEvent = GuildScheduledEvent; diff --git a/node_modules/discord.js/src/structures/GuildTemplate.js b/node_modules/discord.js/src/structures/GuildTemplate.js new file mode 100644 index 0000000..c1e219b --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildTemplate.js @@ -0,0 +1,241 @@ +'use strict'; + +const { setTimeout, clearTimeout } = require('node:timers'); +const { RouteBases, Routes } = require('discord-api-types/v10'); +const Base = require('./Base'); +const DataResolver = require('../util/DataResolver'); +const Events = require('../util/Events'); + +/** + * Represents the template for a guild. + * @extends {Base} + */ +class GuildTemplate extends Base { + /** + * A regular expression that matches guild template links. + * The `code` group property is present on the `exec()` result of this expression. + * @type {RegExp} + * @memberof GuildTemplate + */ + static GuildTemplatesPattern = /discord(?:app)?\.(?:com\/template|new)\/(?<code>[\w-]{2,255})/i; + + constructor(client, data) { + super(client); + this._patch(data); + } + + _patch(data) { + if ('code' in data) { + /** + * The unique code of this template + * @type {string} + */ + this.code = data.code; + } + + if ('name' in data) { + /** + * The name of this template + * @type {string} + */ + this.name = data.name; + } + + if ('description' in data) { + /** + * The description of this template + * @type {?string} + */ + this.description = data.description; + } + + if ('usage_count' in data) { + /** + * The amount of times this template has been used + * @type {number} + */ + this.usageCount = data.usage_count; + } + + if ('creator_id' in data) { + /** + * The id of the user that created this template + * @type {Snowflake} + */ + this.creatorId = data.creator_id; + } + + if ('creator' in data) { + /** + * The user that created this template + * @type {User} + */ + this.creator = this.client.users._add(data.creator); + } + + if ('created_at' in data) { + /** + * The timestamp of when this template was created at + * @type {number} + */ + this.createdTimestamp = Date.parse(data.created_at); + } + + if ('updated_at' in data) { + /** + * The timestamp of when this template was last synced to the guild + * @type {number} + */ + this.updatedTimestamp = Date.parse(data.updated_at); + } + + if ('source_guild_id' in data) { + /** + * The id of the guild that this template belongs to + * @type {Snowflake} + */ + this.guildId = data.source_guild_id; + } + + if ('serialized_source_guild' in data) { + /** + * The data of the guild that this template would create + * @type {APIGuild} + */ + this.serializedGuild = data.serialized_source_guild; + } + + /** + * Whether this template has unsynced changes + * @type {?boolean} + */ + this.unSynced = 'is_dirty' in data ? Boolean(data.is_dirty) : null; + + return this; + } + + /** + * Creates a guild based on this template. + * <warn>This is only available to bots in fewer than 10 guilds.</warn> + * @param {string} name The name of the guild + * @param {BufferResolvable|Base64Resolvable} [icon] The icon for the guild + * @returns {Promise<Guild>} + */ + async createGuild(name, icon) { + const { client } = this; + const data = await client.rest.post(Routes.template(this.code), { + body: { + name, + icon: await DataResolver.resolveImage(icon), + }, + }); + + if (client.guilds.cache.has(data.id)) return client.guilds.cache.get(data.id); + + return new Promise(resolve => { + const resolveGuild = guild => { + client.off(Events.GuildCreate, handleGuild); + client.decrementMaxListeners(); + resolve(guild); + }; + + const handleGuild = guild => { + if (guild.id === data.id) { + clearTimeout(timeout); + resolveGuild(guild); + } + }; + + client.incrementMaxListeners(); + client.on(Events.GuildCreate, handleGuild); + + const timeout = setTimeout(() => resolveGuild(client.guilds._add(data)), 10_000).unref(); + }); + } + + /** + * Options used to edit a guild template. + * @typedef {Object} GuildTemplateEditOptions + * @property {string} [name] The name of this template + * @property {string} [description] The description of this template + */ + + /** + * Updates the metadata of this template. + * @param {GuildTemplateEditOptions} [options] Options for editing the template + * @returns {Promise<GuildTemplate>} + */ + async edit({ name, description } = {}) { + const data = await this.client.rest.patch(Routes.guildTemplate(this.guildId, this.code), { + body: { name, description }, + }); + return this._patch(data); + } + + /** + * Deletes this template. + * @returns {Promise<GuildTemplate>} + */ + async delete() { + await this.client.rest.delete(Routes.guildTemplate(this.guildId, this.code)); + return this; + } + + /** + * Syncs this template to the current state of the guild. + * @returns {Promise<GuildTemplate>} + */ + async sync() { + const data = await this.client.rest.put(Routes.guildTemplate(this.guildId, this.code)); + return this._patch(data); + } + + /** + * The time when this template was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The time when this template was last synced to the guild + * @type {Date} + * @readonly + */ + get updatedAt() { + return new Date(this.updatedTimestamp); + } + + /** + * The guild that this template belongs to + * @type {?Guild} + * @readonly + */ + get guild() { + return this.client.guilds.resolve(this.guildId); + } + + /** + * The URL of this template + * @type {string} + * @readonly + */ + get url() { + return `${RouteBases.template}/${this.code}`; + } + + /** + * When concatenated with a string, this automatically returns the template's code instead of the template object. + * @returns {string} + * @example + * // Logs: Template: FKvmczH2HyUf + * console.log(`Template: ${guildTemplate}!`); + */ + toString() { + return this.code; + } +} + +module.exports = GuildTemplate; diff --git a/node_modules/discord.js/src/structures/Integration.js b/node_modules/discord.js/src/structures/Integration.js new file mode 100644 index 0000000..fa9777b --- /dev/null +++ b/node_modules/discord.js/src/structures/Integration.js @@ -0,0 +1,220 @@ +'use strict'; + +const { Routes } = require('discord-api-types/v10'); +const Base = require('./Base'); +const IntegrationApplication = require('./IntegrationApplication'); + +/** + * The information account for an integration + * @typedef {Object} IntegrationAccount + * @property {Snowflake|string} id The id of the account + * @property {string} name The name of the account + */ + +/** + * The type of an {@link Integration}. This can be: + * * `twitch` + * * `youtube` + * * `discord` + * * `guild_subscription` + * @typedef {string} IntegrationType + */ + +/** + * Represents a guild integration. + * @extends {Base} + */ +class Integration extends Base { + constructor(client, data, guild) { + super(client); + + /** + * The guild this integration belongs to + * @type {Guild} + */ + this.guild = guild; + + /** + * The integration id + * @type {Snowflake|string} + */ + this.id = data.id; + + /** + * The integration name + * @type {string} + */ + this.name = data.name; + + /** + * The integration type + * @type {IntegrationType} + */ + this.type = data.type; + + /** + * Whether this integration is enabled + * @type {?boolean} + */ + this.enabled = data.enabled ?? null; + + if ('syncing' in data) { + /** + * Whether this integration is syncing + * @type {?boolean} + */ + this.syncing = data.syncing; + } else { + this.syncing ??= null; + } + + /** + * The role that this integration uses for subscribers + * @type {?Role} + */ + this.role = this.guild.roles.resolve(data.role_id); + + if ('enable_emoticons' in data) { + /** + * Whether emoticons should be synced for this integration (twitch only currently) + * @type {?boolean} + */ + this.enableEmoticons = data.enable_emoticons; + } else { + this.enableEmoticons ??= null; + } + + if (data.user) { + /** + * The user for this integration + * @type {?User} + */ + this.user = this.client.users._add(data.user); + } else { + this.user ??= null; + } + + /** + * The account integration information + * @type {IntegrationAccount} + */ + this.account = data.account; + + if ('synced_at' in data) { + /** + * The timestamp at which this integration was last synced at + * @type {?number} + */ + this.syncedTimestamp = Date.parse(data.synced_at); + } else { + this.syncedTimestamp ??= null; + } + + if ('subscriber_count' in data) { + /** + * How many subscribers this integration has + * @type {?number} + */ + this.subscriberCount = data.subscriber_count; + } else { + this.subscriberCount ??= null; + } + + if ('revoked' in data) { + /** + * Whether this integration has been revoked + * @type {?boolean} + */ + this.revoked = data.revoked; + } else { + this.revoked ??= null; + } + + this._patch(data); + } + + /** + * The date at which this integration was last synced at + * @type {?Date} + * @readonly + */ + get syncedAt() { + return this.syncedTimestamp && new Date(this.syncedTimestamp); + } + + /** + * All roles that are managed by this integration + * @type {Collection<Snowflake, Role>} + * @readonly + */ + get roles() { + const roles = this.guild.roles.cache; + return roles.filter(role => role.tags?.integrationId === this.id); + } + + _patch(data) { + if ('expire_behavior' in data) { + /** + * The behavior of expiring subscribers + * @type {?IntegrationExpireBehavior} + */ + this.expireBehavior = data.expire_behavior; + } else { + this.expireBehavior ??= null; + } + + if ('expire_grace_period' in data) { + /** + * The grace period (in days) before expiring subscribers + * @type {?number} + */ + this.expireGracePeriod = data.expire_grace_period; + } else { + this.expireGracePeriod ??= null; + } + + if ('application' in data) { + if (this.application) { + this.application._patch(data.application); + } else { + /** + * The application for this integration + * @type {?IntegrationApplication} + */ + this.application = new IntegrationApplication(this.client, data.application); + } + } else { + this.application ??= null; + } + + if ('scopes' in data) { + /** + * The scopes this application has been authorized for + * @type {OAuth2Scopes[]} + */ + this.scopes = data.scopes; + } else { + this.scopes ??= []; + } + } + + /** + * Deletes this integration. + * @returns {Promise<Integration>} + * @param {string} [reason] Reason for deleting this integration + */ + async delete(reason) { + await this.client.rest.delete(Routes.guildIntegration(this.guild.id, this.id), { reason }); + return this; + } + + toJSON() { + return super.toJSON({ + role: 'roleId', + guild: 'guildId', + user: 'userId', + }); + } +} + +module.exports = Integration; diff --git a/node_modules/discord.js/src/structures/IntegrationApplication.js b/node_modules/discord.js/src/structures/IntegrationApplication.js new file mode 100644 index 0000000..4985008 --- /dev/null +++ b/node_modules/discord.js/src/structures/IntegrationApplication.js @@ -0,0 +1,85 @@ +'use strict'; + +const Application = require('./interfaces/Application'); + +/** + * Represents an Integration's OAuth2 Application. + * @extends {Application} + */ +class IntegrationApplication extends Application { + _patch(data) { + super._patch(data); + + if ('bot' in data) { + /** + * The bot user for this application + * @type {?User} + */ + this.bot = this.client.users._add(data.bot); + } else { + this.bot ??= null; + } + + if ('terms_of_service_url' in data) { + /** + * The URL of the application's terms of service + * @type {?string} + */ + this.termsOfServiceURL = data.terms_of_service_url; + } else { + this.termsOfServiceURL ??= null; + } + + if ('privacy_policy_url' in data) { + /** + * The URL of the application's privacy policy + * @type {?string} + */ + this.privacyPolicyURL = data.privacy_policy_url; + } else { + this.privacyPolicyURL ??= null; + } + + if ('rpc_origins' in data) { + /** + * The Array of RPC origin URLs + * @type {string[]} + */ + this.rpcOrigins = data.rpc_origins; + } else { + this.rpcOrigins ??= []; + } + + if ('hook' in data) { + /** + * Whether the application can be default hooked by the client + * @type {?boolean} + */ + this.hook = data.hook; + } else { + this.hook ??= null; + } + + if ('cover_image' in data) { + /** + * The hash of the application's cover image + * @type {?string} + */ + this.cover = data.cover_image; + } else { + this.cover ??= null; + } + + if ('verify_key' in data) { + /** + * The hex-encoded key for verification in interactions and the GameSDK's GetTicket + * @type {?string} + */ + this.verifyKey = data.verify_key; + } else { + this.verifyKey ??= null; + } + } +} + +module.exports = IntegrationApplication; diff --git a/node_modules/discord.js/src/structures/InteractionCollector.js b/node_modules/discord.js/src/structures/InteractionCollector.js new file mode 100644 index 0000000..bb8e6c7 --- /dev/null +++ b/node_modules/discord.js/src/structures/InteractionCollector.js @@ -0,0 +1,269 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Collector = require('./interfaces/Collector'); +const Events = require('../util/Events'); + +/** + * @typedef {CollectorOptions} InteractionCollectorOptions + * @property {TextBasedChannelsResolvable} [channel] The channel to listen to interactions from + * @property {ComponentType} [componentType] The type of component to listen for + * @property {GuildResolvable} [guild] The guild to listen to interactions from + * @property {InteractionType} [interactionType] The type of interaction to listen for + * @property {number} [max] The maximum total amount of interactions to collect + * @property {number} [maxComponents] The maximum number of components to collect + * @property {number} [maxUsers] The maximum number of users to interact + * @property {Message|APIMessage} [message] The message to listen to interactions from + * @property {InteractionResponse} [interactionResponse] The interaction response to listen + * to message component interactions from + */ + +/** + * Collects interactions. + * Will automatically stop if the message ({@link Client#event:messageDelete messageDelete} or + * {@link Client#event:messageDeleteBulk messageDeleteBulk}), + * channel ({@link Client#event:channelDelete channelDelete}), or + * guild ({@link Client#event:guildDelete guildDelete}) is deleted. + * <info>Interaction collectors that do not specify `time` or `idle` may be prone to always running. + * Ensure your interaction collectors end via either of these options or manual cancellation.</info> + * @extends {Collector} + */ +class InteractionCollector extends Collector { + /** + * @param {Client} client The client on which to collect interactions + * @param {InteractionCollectorOptions} [options={}] The options to apply to this collector + */ + constructor(client, options = {}) { + super(client, options); + + /** + * The message from which to collect interactions, if provided + * @type {?Snowflake} + */ + this.messageId = options.message?.id ?? options.interactionResponse?.interaction.message?.id ?? null; + + /** + * The message interaction id from which to collect interactions, if provided + * @type {?Snowflake} + */ + this.messageInteractionId = options.interactionResponse?.id ?? null; + + /** + * The channel from which to collect interactions, if provided + * @type {?Snowflake} + */ + this.channelId = + options.interactionResponse?.interaction.channelId ?? + options.message?.channelId ?? + options.message?.channel_id ?? + this.client.channels.resolveId(options.channel); + + /** + * The guild from which to collect interactions, if provided + * @type {?Snowflake} + */ + this.guildId = + options.interactionResponse?.interaction.guildId ?? + options.message?.guildId ?? + options.message?.guild_id ?? + this.client.guilds.resolveId(options.channel?.guild) ?? + this.client.guilds.resolveId(options.guild); + + /** + * The type of interaction to collect + * @type {?InteractionType} + */ + this.interactionType = options.interactionType ?? null; + + /** + * The type of component to collect + * @type {?ComponentType} + */ + this.componentType = options.componentType ?? null; + + /** + * The users that have interacted with this collector + * @type {Collection<Snowflake, User>} + */ + this.users = new Collection(); + + /** + * The total number of interactions collected + * @type {number} + */ + this.total = 0; + + this.client.incrementMaxListeners(); + + const bulkDeleteListener = messages => { + if (messages.has(this.messageId)) this.stop('messageDelete'); + }; + + if (this.messageId || this.messageInteractionId) { + this._handleMessageDeletion = this._handleMessageDeletion.bind(this); + this.client.on(Events.MessageDelete, this._handleMessageDeletion); + this.client.on(Events.MessageBulkDelete, bulkDeleteListener); + } + + if (this.channelId) { + this._handleChannelDeletion = this._handleChannelDeletion.bind(this); + this._handleThreadDeletion = this._handleThreadDeletion.bind(this); + this.client.on(Events.ChannelDelete, this._handleChannelDeletion); + this.client.on(Events.ThreadDelete, this._handleThreadDeletion); + } + + if (this.guildId) { + this._handleGuildDeletion = this._handleGuildDeletion.bind(this); + this.client.on(Events.GuildDelete, this._handleGuildDeletion); + } + + this.client.on(Events.InteractionCreate, this.handleCollect); + + this.once('end', () => { + this.client.removeListener(Events.InteractionCreate, this.handleCollect); + this.client.removeListener(Events.MessageDelete, this._handleMessageDeletion); + this.client.removeListener(Events.MessageBulkDelete, bulkDeleteListener); + this.client.removeListener(Events.ChannelDelete, this._handleChannelDeletion); + this.client.removeListener(Events.ThreadDelete, this._handleThreadDeletion); + this.client.removeListener(Events.GuildDelete, this._handleGuildDeletion); + this.client.decrementMaxListeners(); + }); + + this.on('collect', interaction => { + this.total++; + this.users.set(interaction.user.id, interaction.user); + }); + } + + /** + * Handles an incoming interaction for possible collection. + * @param {BaseInteraction} interaction The interaction to possibly collect + * @returns {?Snowflake} + * @private + */ + collect(interaction) { + /** + * Emitted whenever an interaction is collected. + * @event InteractionCollector#collect + * @param {BaseInteraction} interaction The interaction that was collected + */ + + if (this.interactionType && interaction.type !== this.interactionType) return null; + if (this.componentType && interaction.componentType !== this.componentType) return null; + if (this.messageId && interaction.message?.id !== this.messageId) return null; + if ( + this.messageInteractionId && + interaction.message?.interaction?.id && + interaction.message.interaction.id !== this.messageInteractionId + ) { + return null; + } + if (this.channelId && interaction.channelId !== this.channelId) return null; + if (this.guildId && interaction.guildId !== this.guildId) return null; + + return interaction.id; + } + + /** + * Handles an interaction for possible disposal. + * @param {BaseInteraction} interaction The interaction that could be disposed of + * @returns {?Snowflake} + */ + dispose(interaction) { + /** + * Emitted whenever an interaction is disposed of. + * @event InteractionCollector#dispose + * @param {BaseInteraction} interaction The interaction that was disposed of + */ + if (this.type && interaction.type !== this.type) return null; + if (this.componentType && interaction.componentType !== this.componentType) return null; + if (this.messageId && interaction.message?.id !== this.messageId) return null; + if ( + this.messageInteractionId && + interaction.message?.interaction?.id && + interaction.message.interaction.id !== this.messageInteractionId + ) { + return null; + } + if (this.channelId && interaction.channelId !== this.channelId) return null; + if (this.guildId && interaction.guildId !== this.guildId) return null; + + return interaction.id; + } + + /** + * Empties this interaction collector. + */ + empty() { + this.total = 0; + this.collected.clear(); + this.users.clear(); + this.checkEnd(); + } + + /** + * The reason this collector has ended with, or null if it hasn't ended yet + * @type {?string} + * @readonly + */ + get endReason() { + if (this.options.max && this.total >= this.options.max) return 'limit'; + if (this.options.maxComponents && this.collected.size >= this.options.maxComponents) return 'componentLimit'; + if (this.options.maxUsers && this.users.size >= this.options.maxUsers) return 'userLimit'; + return super.endReason; + } + + /** + * Handles checking if the message has been deleted, and if so, stops the collector with the reason 'messageDelete'. + * @private + * @param {Message} message The message that was deleted + * @returns {void} + */ + _handleMessageDeletion(message) { + if (message.id === this.messageId) { + this.stop('messageDelete'); + } + + if (message.interaction?.id === this.messageInteractionId) { + this.stop('messageDelete'); + } + } + + /** + * Handles checking if the channel has been deleted, and if so, stops the collector with the reason 'channelDelete'. + * @private + * @param {GuildChannel} channel The channel that was deleted + * @returns {void} + */ + _handleChannelDeletion(channel) { + if (channel.id === this.channelId || channel.threads?.cache.has(this.channelId)) { + this.stop('channelDelete'); + } + } + + /** + * Handles checking if the thread has been deleted, and if so, stops the collector with the reason 'threadDelete'. + * @private + * @param {ThreadChannel} thread The thread that was deleted + * @returns {void} + */ + _handleThreadDeletion(thread) { + if (thread.id === this.channelId) { + this.stop('threadDelete'); + } + } + + /** + * Handles checking if the guild has been deleted, and if so, stops the collector with the reason 'guildDelete'. + * @private + * @param {Guild} guild The guild that was deleted + * @returns {void} + */ + _handleGuildDeletion(guild) { + if (guild.id === this.guildId) { + this.stop('guildDelete'); + } + } +} + +module.exports = InteractionCollector; diff --git a/node_modules/discord.js/src/structures/InteractionResponse.js b/node_modules/discord.js/src/structures/InteractionResponse.js new file mode 100644 index 0000000..9b372e3 --- /dev/null +++ b/node_modules/discord.js/src/structures/InteractionResponse.js @@ -0,0 +1,102 @@ +'use strict'; + +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { InteractionType } = require('discord-api-types/v10'); +const { DiscordjsError, ErrorCodes } = require('../errors'); + +/** + * Represents an interaction's response + */ +class InteractionResponse { + constructor(interaction, id) { + /** + * The interaction associated with the interaction response + * @type {BaseInteraction} + */ + this.interaction = interaction; + /** + * The id of the original interaction response + * @type {Snowflake} + */ + this.id = id ?? interaction.id; + this.client = interaction.client; + } + + /** + * The timestamp the interaction response was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the interaction response was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * Collects a single component interaction that passes the filter. + * The Promise will reject if the time expires. + * @param {AwaitMessageComponentOptions} [options={}] Options to pass to the internal collector + * @returns {Promise<MessageComponentInteraction>} + */ + awaitMessageComponent(options = {}) { + const _options = { ...options, max: 1 }; + return new Promise((resolve, reject) => { + const collector = this.createMessageComponentCollector(_options); + collector.once('end', (interactions, reason) => { + const interaction = interactions.first(); + if (interaction) resolve(interaction); + else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason)); + }); + }); + } + + /** + * Creates a message component interaction collector + * @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector + * @returns {InteractionCollector} + */ + createMessageComponentCollector(options = {}) { + return new InteractionCollector(this.client, { + ...options, + interactionResponse: this, + interactionType: InteractionType.MessageComponent, + }); + } + + /** + * Fetches the response as a {@link Message} object. + * @returns {Promise<Message>} + */ + fetch() { + return this.interaction.fetchReply(); + } + + /** + * Deletes the response. + * @returns {Promise<void>} + */ + delete() { + return this.interaction.deleteReply(); + } + + /** + * Edits the response. + * @param {string|MessagePayload|WebhookMessageEditOptions} options The new options for the response. + * @returns {Promise<Message>} + */ + edit(options) { + return this.interaction.editReply(options); + } +} + +// eslint-disable-next-line import/order +const InteractionCollector = require('./InteractionCollector'); +module.exports = InteractionResponse; diff --git a/node_modules/discord.js/src/structures/InteractionWebhook.js b/node_modules/discord.js/src/structures/InteractionWebhook.js new file mode 100644 index 0000000..58eb531 --- /dev/null +++ b/node_modules/discord.js/src/structures/InteractionWebhook.js @@ -0,0 +1,59 @@ +'use strict'; + +const Webhook = require('./Webhook'); + +/** + * Represents a webhook for an Interaction + * @implements {Webhook} + */ +class InteractionWebhook { + /** + * @param {Client} client The instantiating client + * @param {Snowflake} id The application's id + * @param {string} token The interaction's token + */ + constructor(client, id, token) { + /** + * The client that instantiated the interaction webhook + * @name InteractionWebhook#client + * @type {Client} + * @readonly + */ + Object.defineProperty(this, 'client', { value: client }); + this.id = id; + Object.defineProperty(this, 'token', { value: token, writable: true, configurable: true }); + } + + // These are here only for documentation purposes - they are implemented by Webhook + /* eslint-disable no-empty-function */ + /** + * Sends a message with this webhook. + * @param {string|MessagePayload|InteractionReplyOptions} options The content for the reply + * @returns {Promise<Message>} + */ + + send() {} + + /** + * Gets a message that was sent by this webhook. + * @param {Snowflake|'@original'} message The id of the message to fetch + * @returns {Promise<Message>} Returns the message sent by this webhook + */ + + fetchMessage() {} + + /** + * Edits a message that was sent by this webhook. + * @param {MessageResolvable|'@original'} message The message to edit + * @param {string|MessagePayload|WebhookMessageEditOptions} options The options to provide + * @returns {Promise<Message>} Returns the message edited by this webhook + */ + + editMessage() {} + deleteMessage() {} + get url() {} +} + +Webhook.applyToClass(InteractionWebhook, ['sendSlackMessage', 'edit', 'delete', 'createdTimestamp', 'createdAt']); + +module.exports = InteractionWebhook; diff --git a/node_modules/discord.js/src/structures/Invite.js b/node_modules/discord.js/src/structures/Invite.js new file mode 100644 index 0000000..19014ff --- /dev/null +++ b/node_modules/discord.js/src/structures/Invite.js @@ -0,0 +1,322 @@ +'use strict'; + +const { RouteBases, Routes, PermissionFlagsBits } = require('discord-api-types/v10'); +const Base = require('./Base'); +const { GuildScheduledEvent } = require('./GuildScheduledEvent'); +const IntegrationApplication = require('./IntegrationApplication'); +const InviteStageInstance = require('./InviteStageInstance'); +const { DiscordjsError, ErrorCodes } = require('../errors'); + +/** + * Represents an invitation to a guild channel. + * @extends {Base} + */ +class Invite extends Base { + /** + * A regular expression that matches Discord invite links. + * The `code` group property is present on the `exec()` result of this expression. + * @type {RegExp} + * @memberof Invite + */ + static InvitesPattern = /discord(?:(?:app)?\.com\/invite|\.gg(?:\/invite)?)\/(?<code>[\w-]{2,255})/i; + + constructor(client, data) { + super(client); + this._patch(data); + } + + _patch(data) { + const InviteGuild = require('./InviteGuild'); + /** + * The guild the invite is for including welcome screen data if present + * @type {?(Guild|InviteGuild)} + */ + this.guild ??= null; + if (data.guild) { + this.guild = this.client.guilds.resolve(data.guild.id) ?? new InviteGuild(this.client, data.guild); + } + + if ('code' in data) { + /** + * The code for this invite + * @type {string} + */ + this.code = data.code; + } + + if ('approximate_presence_count' in data) { + /** + * The approximate number of online members of the guild this invite is for + * <info>This is only available when the invite was fetched through {@link Client#fetchInvite}.</info> + * @type {?number} + */ + this.presenceCount = data.approximate_presence_count; + } else { + this.presenceCount ??= null; + } + + if ('approximate_member_count' in data) { + /** + * The approximate total number of members of the guild this invite is for + * <info>This is only available when the invite was fetched through {@link Client#fetchInvite}.</info> + * @type {?number} + */ + this.memberCount = data.approximate_member_count; + } else { + this.memberCount ??= null; + } + + if ('temporary' in data) { + /** + * Whether or not this invite only grants temporary membership + * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch} + * or created through {@link GuildInviteManager#create}.</info> + * @type {?boolean} + */ + this.temporary = data.temporary ?? null; + } else { + this.temporary ??= null; + } + + if ('max_age' in data) { + /** + * The maximum age of the invite, in seconds, 0 if never expires + * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch} + * or created through {@link GuildInviteManager#create}.</info> + * @type {?number} + */ + this.maxAge = data.max_age; + } else { + this.maxAge ??= null; + } + + if ('uses' in data) { + /** + * How many times this invite has been used + * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch} + * or created through {@link GuildInviteManager#create}.</info> + * @type {?number} + */ + this.uses = data.uses; + } else { + this.uses ??= null; + } + + if ('max_uses' in data) { + /** + * The maximum uses of this invite + * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch} + * or created through {@link GuildInviteManager#create}.</info> + * @type {?number} + */ + this.maxUses = data.max_uses; + } else { + this.maxUses ??= null; + } + + if ('inviter_id' in data) { + /** + * The user's id who created this invite + * @type {?Snowflake} + */ + this.inviterId = data.inviter_id; + } else { + this.inviterId ??= null; + } + + if ('inviter' in data) { + this.client.users._add(data.inviter); + this.inviterId = data.inviter.id; + } + + if ('target_user' in data) { + /** + * The user whose stream to display for this voice channel stream invite + * @type {?User} + */ + this.targetUser = this.client.users._add(data.target_user); + } else { + this.targetUser ??= null; + } + + if ('target_application' in data) { + /** + * The embedded application to open for this voice channel embedded application invite + * @type {?IntegrationApplication} + */ + this.targetApplication = new IntegrationApplication(this.client, data.target_application); + } else { + this.targetApplication ??= null; + } + + if ('target_type' in data) { + /** + * The target type + * @type {?InviteTargetType} + */ + this.targetType = data.target_type; + } else { + this.targetType ??= null; + } + + if ('channel_id' in data) { + /** + * The id of the channel this invite is for + * @type {?Snowflake} + */ + this.channelId = data.channel_id; + } + + if ('channel' in data) { + /** + * The channel this invite is for + * @type {?BaseChannel} + */ + this.channel = + this.client.channels._add(data.channel, this.guild, { cache: false }) ?? + this.client.channels.resolve(this.channelId); + + this.channelId ??= data.channel.id; + } + + if ('created_at' in data) { + /** + * The timestamp this invite was created at + * @type {?number} + */ + this.createdTimestamp = Date.parse(data.created_at); + } else { + this.createdTimestamp ??= null; + } + + if ('expires_at' in data) { + this._expiresTimestamp = data.expires_at && Date.parse(data.expires_at); + } else { + this._expiresTimestamp ??= null; + } + + if ('stage_instance' in data) { + /** + * The stage instance data if there is a public {@link StageInstance} in the stage channel this invite is for + * @type {?InviteStageInstance} + * @deprecated + */ + this.stageInstance = new InviteStageInstance(this.client, data.stage_instance, this.channel.id, this.guild.id); + } else { + this.stageInstance ??= null; + } + + if ('guild_scheduled_event' in data) { + /** + * The guild scheduled event data if there is a {@link GuildScheduledEvent} in the channel this invite is for + * @type {?GuildScheduledEvent} + */ + this.guildScheduledEvent = new GuildScheduledEvent(this.client, data.guild_scheduled_event); + } else { + this.guildScheduledEvent ??= null; + } + } + + /** + * The time the invite was created at + * @type {?Date} + * @readonly + */ + get createdAt() { + return this.createdTimestamp && new Date(this.createdTimestamp); + } + + /** + * Whether the invite is deletable by the client user + * @type {boolean} + * @readonly + */ + get deletable() { + const guild = this.guild; + if (!guild || !this.client.guilds.cache.has(guild.id)) return false; + if (!guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe); + return Boolean( + this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageChannels, false) || + guild.members.me.permissions.has(PermissionFlagsBits.ManageGuild), + ); + } + + /** + * The timestamp the invite will expire at + * @type {?number} + * @readonly + */ + get expiresTimestamp() { + return ( + this._expiresTimestamp ?? + (this.createdTimestamp && this.maxAge ? this.createdTimestamp + this.maxAge * 1_000 : null) + ); + } + + /** + * The time the invite will expire at + * @type {?Date} + * @readonly + */ + get expiresAt() { + return this.expiresTimestamp && new Date(this.expiresTimestamp); + } + + /** + * The user who created this invite + * @type {?User} + * @readonly + */ + get inviter() { + return this.inviterId && this.client.users.resolve(this.inviterId); + } + + /** + * The URL to the invite + * @type {string} + * @readonly + */ + get url() { + return `${RouteBases.invite}/${this.code}`; + } + + /** + * Deletes this invite. + * @param {string} [reason] Reason for deleting this invite + * @returns {Promise<Invite>} + */ + async delete(reason) { + await this.client.rest.delete(Routes.invite(this.code), { reason }); + return this; + } + + /** + * When concatenated with a string, this automatically concatenates the invite's URL instead of the object. + * @returns {string} + * @example + * // Logs: Invite: https://discord.gg/A1b2C3 + * console.log(`Invite: ${invite}`); + */ + toString() { + return this.url; + } + + toJSON() { + return super.toJSON({ + url: true, + expiresTimestamp: true, + presenceCount: false, + memberCount: false, + uses: false, + channel: 'channelId', + inviter: 'inviterId', + guild: 'guildId', + }); + } + + valueOf() { + return this.code; + } +} + +module.exports = Invite; diff --git a/node_modules/discord.js/src/structures/InviteGuild.js b/node_modules/discord.js/src/structures/InviteGuild.js new file mode 100644 index 0000000..8efd980 --- /dev/null +++ b/node_modules/discord.js/src/structures/InviteGuild.js @@ -0,0 +1,22 @@ +'use strict'; + +const AnonymousGuild = require('./AnonymousGuild'); +const WelcomeScreen = require('./WelcomeScreen'); + +/** + * Represents a guild received from an invite, includes welcome screen data if available. + * @extends {AnonymousGuild} + */ +class InviteGuild extends AnonymousGuild { + constructor(client, data) { + super(client, data); + + /** + * The welcome screen for this invite guild + * @type {?WelcomeScreen} + */ + this.welcomeScreen = data.welcome_screen !== undefined ? new WelcomeScreen(this, data.welcome_screen) : null; + } +} + +module.exports = InviteGuild; diff --git a/node_modules/discord.js/src/structures/InviteStageInstance.js b/node_modules/discord.js/src/structures/InviteStageInstance.js new file mode 100644 index 0000000..21ede43 --- /dev/null +++ b/node_modules/discord.js/src/structures/InviteStageInstance.js @@ -0,0 +1,87 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Base = require('./Base'); + +/** + * Represents the data about a public {@link StageInstance} in an {@link Invite}. + * @extends {Base} + * @deprecated + */ +class InviteStageInstance extends Base { + constructor(client, data, channelId, guildId) { + super(client); + + /** + * The id of the stage channel this invite is for + * @type {Snowflake} + */ + this.channelId = channelId; + + /** + * The stage channel's guild id + * @type {Snowflake} + */ + this.guildId = guildId; + + /** + * The members speaking in the stage channel + * @type {Collection<Snowflake, GuildMember>} + */ + this.members = new Collection(); + + this._patch(data); + } + + _patch(data) { + if ('topic' in data) { + /** + * The topic of the stage instance + * @type {string} + */ + this.topic = data.topic; + } + + if ('participant_count' in data) { + /** + * The number of users in the stage channel + * @type {number} + */ + this.participantCount = data.participant_count; + } + + if ('speaker_count' in data) { + /** + * The number of users speaking in the stage channel + * @type {number} + */ + this.speakerCount = data.speaker_count; + } + + this.members.clear(); + for (const rawMember of data.members) { + const member = this.guild.members._add(rawMember); + this.members.set(member.id, member); + } + } + + /** + * The stage channel this invite is for + * @type {?StageChannel} + * @readonly + */ + get channel() { + return this.client.channels.resolve(this.channelId); + } + + /** + * The guild of the stage channel this invite is for + * @type {?Guild} + * @readonly + */ + get guild() { + return this.client.guilds.resolve(this.guildId); + } +} + +module.exports = InviteStageInstance; diff --git a/node_modules/discord.js/src/structures/MentionableSelectMenuBuilder.js b/node_modules/discord.js/src/structures/MentionableSelectMenuBuilder.js new file mode 100644 index 0000000..b22f600 --- /dev/null +++ b/node_modules/discord.js/src/structures/MentionableSelectMenuBuilder.js @@ -0,0 +1,32 @@ +'use strict'; + +const { MentionableSelectMenuBuilder: BuildersMentionableSelectMenu } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { toSnakeCase } = require('../util/Transformers'); + +/** + * Class used to build select menu components to be sent through the API + * @extends {BuildersMentionableSelectMenu} + */ +class MentionableSelectMenuBuilder extends BuildersMentionableSelectMenu { + constructor(data = {}) { + super(toSnakeCase(data)); + } + + /** + * Creates a new select menu builder from JSON data + * @param {MentionableSelectMenuBuilder|MentionableSelectMenuComponent|APIMentionableSelectComponent} other + * The other data + * @returns {MentionableSelectMenuBuilder} + */ + static from(other) { + return new this(isJSONEncodable(other) ? other.toJSON() : other); + } +} + +module.exports = MentionableSelectMenuBuilder; + +/** + * @external BuildersMentionableSelectMenu + * @see {@link https://discord.js.org/docs/packages/builders/stable/MentionableSelectMenuBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/MentionableSelectMenuComponent.js b/node_modules/discord.js/src/structures/MentionableSelectMenuComponent.js new file mode 100644 index 0000000..d0f75c3 --- /dev/null +++ b/node_modules/discord.js/src/structures/MentionableSelectMenuComponent.js @@ -0,0 +1,11 @@ +'use strict'; + +const BaseSelectMenuComponent = require('./BaseSelectMenuComponent'); + +/** + * Represents a mentionable select menu component + * @extends {BaseSelectMenuComponent} + */ +class MentionableSelectMenuComponent extends BaseSelectMenuComponent {} + +module.exports = MentionableSelectMenuComponent; diff --git a/node_modules/discord.js/src/structures/MentionableSelectMenuInteraction.js b/node_modules/discord.js/src/structures/MentionableSelectMenuInteraction.js new file mode 100644 index 0000000..416d5ce --- /dev/null +++ b/node_modules/discord.js/src/structures/MentionableSelectMenuInteraction.js @@ -0,0 +1,71 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const MessageComponentInteraction = require('./MessageComponentInteraction'); +const Events = require('../util/Events'); + +/** + * Represents a {@link ComponentType.MentionableSelect} select menu interaction. + * @extends {MessageComponentInteraction} + */ +class MentionableSelectMenuInteraction extends MessageComponentInteraction { + constructor(client, data) { + super(client, data); + const { resolved, values } = data.data; + const { members, users, roles } = resolved ?? {}; + + /** + * An array of the selected user and role ids + * @type {Snowflake[]} + */ + this.values = values ?? []; + + /** + * Collection of the selected users + * @type {Collection<Snowflake, User>} + */ + this.users = new Collection(); + + /** + * Collection of the selected users + * @type {Collection<Snowflake, GuildMember|APIGuildMember>} + */ + this.members = new Collection(); + + /** + * Collection of the selected roles + * @type {Collection<Snowflake, Role|APIRole>} + */ + this.roles = new Collection(); + + if (members) { + for (const [id, member] of Object.entries(members)) { + const user = users[id]; + if (!user) { + this.client.emit( + Events.Debug, + `[MentionableSelectMenuInteraction] Received a member without a user, skipping ${id}`, + ); + + continue; + } + + this.members.set(id, this.guild?.members._add({ user, ...member }) ?? { user, ...member }); + } + } + + if (users) { + for (const user of Object.values(users)) { + this.users.set(user.id, this.client.users._add(user)); + } + } + + if (roles) { + for (const role of Object.values(roles)) { + this.roles.set(role.id, this.guild?.roles._add(role) ?? role); + } + } + } +} + +module.exports = MentionableSelectMenuInteraction; diff --git a/node_modules/discord.js/src/structures/Message.js b/node_modules/discord.js/src/structures/Message.js new file mode 100644 index 0000000..c82c177 --- /dev/null +++ b/node_modules/discord.js/src/structures/Message.js @@ -0,0 +1,997 @@ +'use strict'; + +const { messageLink } = require('@discordjs/builders'); +const { Collection } = require('@discordjs/collection'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { + InteractionType, + ChannelType, + MessageType, + MessageFlags, + PermissionFlagsBits, +} = require('discord-api-types/v10'); +const Attachment = require('./Attachment'); +const Base = require('./Base'); +const ClientApplication = require('./ClientApplication'); +const Embed = require('./Embed'); +const InteractionCollector = require('./InteractionCollector'); +const Mentions = require('./MessageMentions'); +const MessagePayload = require('./MessagePayload'); +const ReactionCollector = require('./ReactionCollector'); +const { Sticker } = require('./Sticker'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const ReactionManager = require('../managers/ReactionManager'); +const { createComponent } = require('../util/Components'); +const { NonSystemMessageTypes, MaxBulkDeletableMessageAge, DeletableMessageTypes } = require('../util/Constants'); +const MessageFlagsBitField = require('../util/MessageFlagsBitField'); +const PermissionsBitField = require('../util/PermissionsBitField'); +const { cleanContent, resolvePartialEmoji } = require('../util/Util'); + +/** + * Represents a message on Discord. + * @extends {Base} + */ +class Message extends Base { + constructor(client, data) { + super(client); + + /** + * The id of the channel the message was sent in + * @type {Snowflake} + */ + this.channelId = data.channel_id; + + /** + * The id of the guild the message was sent in, if any + * @type {?Snowflake} + */ + this.guildId = data.guild_id ?? this.channel?.guild?.id ?? null; + + this._patch(data); + } + + _patch(data) { + /** + * The message's id + * @type {Snowflake} + */ + this.id = data.id; + + /** + * The timestamp the message was sent at + * @type {number} + */ + this.createdTimestamp = DiscordSnowflake.timestampFrom(this.id); + + if ('type' in data) { + /** + * The type of the message + * @type {?MessageType} + */ + this.type = data.type; + + /** + * Whether or not this message was sent by Discord, not actually a user (e.g. pin notifications) + * @type {?boolean} + */ + this.system = !NonSystemMessageTypes.includes(this.type); + } else { + this.system ??= null; + this.type ??= null; + } + + if ('content' in data) { + /** + * The content of the message. + * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent + * in a guild for messages that do not mention the client.</info> + * @type {?string} + */ + this.content = data.content; + } else { + this.content ??= null; + } + + if ('author' in data) { + /** + * The author of the message + * @type {?User} + */ + this.author = this.client.users._add(data.author, !data.webhook_id); + } else { + this.author ??= null; + } + + if ('pinned' in data) { + /** + * Whether or not this message is pinned + * @type {?boolean} + */ + this.pinned = Boolean(data.pinned); + } else { + this.pinned ??= null; + } + + if ('tts' in data) { + /** + * Whether or not the message was Text-To-Speech + * @type {?boolean} + */ + this.tts = data.tts; + } else { + this.tts ??= null; + } + + if ('nonce' in data) { + /** + * A random number or string used for checking message delivery + * <warn>This is only received after the message was sent successfully, and + * lost if re-fetched</warn> + * @type {?string} + */ + this.nonce = data.nonce; + } else { + this.nonce ??= null; + } + + if ('embeds' in data) { + /** + * An array of embeds in the message - e.g. YouTube Player. + * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent + * in a guild for messages that do not mention the client.</info> + * @type {Embed[]} + */ + this.embeds = data.embeds.map(e => new Embed(e)); + } else { + this.embeds = this.embeds?.slice() ?? []; + } + + if ('components' in data) { + /** + * An array of of action rows in the message. + * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent + * in a guild for messages that do not mention the client.</info> + * @type {ActionRow[]} + */ + this.components = data.components.map(c => createComponent(c)); + } else { + this.components = this.components?.slice() ?? []; + } + + if ('attachments' in data) { + /** + * A collection of attachments in the message - e.g. Pictures - mapped by their ids. + * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent + * in a guild for messages that do not mention the client.</info> + * @type {Collection<Snowflake, Attachment>} + */ + this.attachments = new Collection(); + if (data.attachments) { + for (const attachment of data.attachments) { + this.attachments.set(attachment.id, new Attachment(attachment)); + } + } + } else { + this.attachments = new Collection(this.attachments); + } + + if ('sticker_items' in data || 'stickers' in data) { + /** + * A collection of stickers in the message + * @type {Collection<Snowflake, Sticker>} + */ + this.stickers = new Collection( + (data.sticker_items ?? data.stickers)?.map(s => [s.id, new Sticker(this.client, s)]), + ); + } else { + this.stickers = new Collection(this.stickers); + } + + if ('position' in data) { + /** + * A generally increasing integer (there may be gaps or duplicates) that represents + * the approximate position of the message in a thread. + * @type {?number} + */ + this.position = data.position; + } else { + this.position ??= null; + } + + if ('role_subscription_data' in data) { + /** + * Role subscription data found on {@link MessageType.RoleSubscriptionPurchase} messages. + * @typedef {Object} RoleSubscriptionData + * @property {Snowflake} roleSubscriptionListingId The id of the SKU and listing the user is subscribed to + * @property {string} tierName The name of the tier the user is subscribed to + * @property {number} totalMonthsSubscribed The total number of months the user has been subscribed for + * @property {boolean} isRenewal Whether this notification is a renewal + */ + + /** + * The data of the role subscription purchase or renewal. + * <info>This is present on {@link MessageType.RoleSubscriptionPurchase} messages.</info> + * @type {?RoleSubscriptionData} + */ + this.roleSubscriptionData = { + roleSubscriptionListingId: data.role_subscription_data.role_subscription_listing_id, + tierName: data.role_subscription_data.tier_name, + totalMonthsSubscribed: data.role_subscription_data.total_months_subscribed, + isRenewal: data.role_subscription_data.is_renewal, + }; + } else { + this.roleSubscriptionData ??= null; + } + + // Discord sends null if the message has not been edited + if (data.edited_timestamp) { + /** + * The timestamp the message was last edited at (if applicable) + * @type {?number} + */ + this.editedTimestamp = Date.parse(data.edited_timestamp); + } else { + this.editedTimestamp ??= null; + } + + if ('reactions' in data) { + /** + * A manager of the reactions belonging to this message + * @type {ReactionManager} + */ + this.reactions = new ReactionManager(this); + if (data.reactions?.length > 0) { + for (const reaction of data.reactions) { + this.reactions._add(reaction); + } + } + } else { + this.reactions ??= new ReactionManager(this); + } + + if (!this.mentions) { + /** + * All valid mentions that the message contains + * @type {MessageMentions} + */ + this.mentions = new Mentions( + this, + data.mentions, + data.mention_roles, + data.mention_everyone, + data.mention_channels, + data.referenced_message?.author, + ); + } else { + this.mentions = new Mentions( + this, + data.mentions ?? this.mentions.users, + data.mention_roles ?? this.mentions.roles, + data.mention_everyone ?? this.mentions.everyone, + data.mention_channels ?? this.mentions.crosspostedChannels, + data.referenced_message?.author ?? this.mentions.repliedUser, + ); + } + + if ('webhook_id' in data) { + /** + * The id of the webhook that sent the message, if applicable + * @type {?Snowflake} + */ + this.webhookId = data.webhook_id; + } else { + this.webhookId ??= null; + } + + if ('application' in data) { + /** + * Supplemental application information for group activities + * @type {?ClientApplication} + */ + this.groupActivityApplication = new ClientApplication(this.client, data.application); + } else { + this.groupActivityApplication ??= null; + } + + if ('application_id' in data) { + /** + * The id of the application of the interaction that sent this message, if any + * @type {?Snowflake} + */ + this.applicationId = data.application_id; + } else { + this.applicationId ??= null; + } + + if ('activity' in data) { + /** + * Group activity + * @type {?MessageActivity} + */ + this.activity = { + partyId: data.activity.party_id, + type: data.activity.type, + }; + } else { + this.activity ??= null; + } + + if ('thread' in data) { + this.client.channels._add(data.thread, this.guild); + } + + if (this.member && data.member) { + this.member._patch(data.member); + } else if (data.member && this.guild && this.author) { + this.guild.members._add(Object.assign(data.member, { user: this.author })); + } + + if ('flags' in data) { + /** + * Flags that are applied to the message + * @type {Readonly<MessageFlagsBitField>} + */ + this.flags = new MessageFlagsBitField(data.flags).freeze(); + } else { + this.flags = new MessageFlagsBitField(this.flags).freeze(); + } + + /** + * Reference data sent in a message that contains ids identifying the referenced message. + * This can be present in the following types of message: + * * Crossposted messages (`MessageFlags.Crossposted`) + * * {@link MessageType.ChannelFollowAdd} + * * {@link MessageType.ChannelPinnedMessage} + * * {@link MessageType.Reply} + * * {@link MessageType.ThreadStarterMessage} + * @see {@link https://discord.com/developers/docs/resources/channel#message-types} + * @typedef {Object} MessageReference + * @property {Snowflake} channelId The channel's id the message was referenced + * @property {?Snowflake} guildId The guild's id the message was referenced + * @property {?Snowflake} messageId The message's id that was referenced + */ + + if ('message_reference' in data) { + /** + * Message reference data + * @type {?MessageReference} + */ + this.reference = { + channelId: data.message_reference.channel_id, + guildId: data.message_reference.guild_id, + messageId: data.message_reference.message_id, + }; + } else { + this.reference ??= null; + } + + if (data.referenced_message) { + this.channel?.messages._add({ guild_id: data.message_reference?.guild_id, ...data.referenced_message }); + } + + /** + * Partial data of the interaction that a message is a reply to + * @typedef {Object} MessageInteraction + * @property {Snowflake} id The interaction's id + * @property {InteractionType} type The type of the interaction + * @property {string} commandName The name of the interaction's application command, + * as well as the subcommand and subcommand group, where applicable + * @property {User} user The user that invoked the interaction + */ + + if (data.interaction) { + /** + * Partial data of the interaction that this message is a reply to + * @type {?MessageInteraction} + */ + this.interaction = { + id: data.interaction.id, + type: data.interaction.type, + commandName: data.interaction.name, + user: this.client.users._add(data.interaction.user), + }; + } else { + this.interaction ??= null; + } + } + + /** + * The channel that the message was sent in + * @type {TextBasedChannels} + * @readonly + */ + get channel() { + return this.client.channels.resolve(this.channelId); + } + + /** + * Whether or not this message is a partial + * @type {boolean} + * @readonly + */ + get partial() { + return typeof this.content !== 'string' || !this.author; + } + + /** + * Represents the author of the message as a guild member. + * Only available if the message comes from a guild where the author is still a member + * @type {?GuildMember} + * @readonly + */ + get member() { + return this.guild?.members.resolve(this.author) ?? null; + } + + /** + * The time the message was sent at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The time the message was last edited at (if applicable) + * @type {?Date} + * @readonly + */ + get editedAt() { + return this.editedTimestamp && new Date(this.editedTimestamp); + } + + /** + * The guild the message was sent in (if in a guild channel) + * @type {?Guild} + * @readonly + */ + get guild() { + return this.client.guilds.resolve(this.guildId) ?? this.channel?.guild ?? null; + } + + /** + * Whether this message has a thread associated with it + * @type {boolean} + * @readonly + */ + get hasThread() { + return this.flags.has(MessageFlags.HasThread); + } + + /** + * The thread started by this message + * <info>This property is not suitable for checking whether a message has a thread, + * use {@link Message#hasThread} instead.</info> + * @type {?ThreadChannel} + * @readonly + */ + get thread() { + return this.channel?.threads?.resolve(this.id) ?? null; + } + + /** + * The URL to jump to this message + * @type {string} + * @readonly + */ + get url() { + return this.inGuild() ? messageLink(this.channelId, this.id, this.guildId) : messageLink(this.channelId, this.id); + } + + /** + * The message contents with all mentions replaced by the equivalent text. + * If mentions cannot be resolved to a name, the relevant mention in the message content will not be converted. + * @type {?string} + * @readonly + */ + get cleanContent() { + // eslint-disable-next-line eqeqeq + return this.content != null ? cleanContent(this.content, this.channel) : null; + } + + /** + * Creates a reaction collector. + * @param {ReactionCollectorOptions} [options={}] Options to send to the collector + * @returns {ReactionCollector} + * @example + * // Create a reaction collector + * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId'; + * const collector = message.createReactionCollector({ filter, time: 15_000 }); + * collector.on('collect', r => console.log(`Collected ${r.emoji.name}`)); + * collector.on('end', collected => console.log(`Collected ${collected.size} items`)); + */ + createReactionCollector(options = {}) { + return new ReactionCollector(this, options); + } + + /** + * An object containing the same properties as CollectorOptions, but a few more: + * @typedef {ReactionCollectorOptions} AwaitReactionsOptions + * @property {string[]} [errors] Stop/end reasons that cause the promise to reject + */ + + /** + * Similar to createReactionCollector but in promise form. + * Resolves with a collection of reactions that pass the specified filter. + * @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector + * @returns {Promise<Collection<string | Snowflake, MessageReaction>>} + * @example + * // Create a reaction collector + * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId' + * message.awaitReactions({ filter, time: 15_000 }) + * .then(collected => console.log(`Collected ${collected.size} reactions`)) + * .catch(console.error); + */ + awaitReactions(options = {}) { + return new Promise((resolve, reject) => { + const collector = this.createReactionCollector(options); + collector.once('end', (reactions, reason) => { + if (options.errors?.includes(reason)) reject(reactions); + else resolve(reactions); + }); + }); + } + + /** + * @typedef {CollectorOptions} MessageComponentCollectorOptions + * @property {ComponentType} [componentType] The type of component to listen for + * @property {number} [max] The maximum total amount of interactions to collect + * @property {number} [maxComponents] The maximum number of components to collect + * @property {number} [maxUsers] The maximum number of users to interact + */ + + /** + * Creates a message component interaction collector. + * @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector + * @returns {InteractionCollector} + * @example + * // Create a message component interaction collector + * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId'; + * const collector = message.createMessageComponentCollector({ filter, time: 15_000 }); + * collector.on('collect', i => console.log(`Collected ${i.customId}`)); + * collector.on('end', collected => console.log(`Collected ${collected.size} items`)); + */ + createMessageComponentCollector(options = {}) { + return new InteractionCollector(this.client, { + ...options, + interactionType: InteractionType.MessageComponent, + message: this, + }); + } + + /** + * An object containing the same properties as CollectorOptions, but a few more: + * @typedef {Object} AwaitMessageComponentOptions + * @property {CollectorFilter} [filter] The filter applied to this collector + * @property {number} [time] Time to wait for an interaction before rejecting + * @property {ComponentType} [componentType] The type of component interaction to collect + * @property {number} [idle] Time to wait without another message component interaction before ending the collector + * @property {boolean} [dispose] Whether to remove the message component interaction after collecting + * @property {InteractionResponse} [interactionResponse] The interaction response to collect interactions from + */ + + /** + * Collects a single component interaction that passes the filter. + * The Promise will reject if the time expires. + * @param {AwaitMessageComponentOptions} [options={}] Options to pass to the internal collector + * @returns {Promise<MessageComponentInteraction>} + * @example + * // Collect a message component interaction + * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId'; + * message.awaitMessageComponent({ filter, time: 15_000 }) + * .then(interaction => console.log(`${interaction.customId} was clicked!`)) + * .catch(console.error); + */ + awaitMessageComponent(options = {}) { + const _options = { ...options, max: 1 }; + return new Promise((resolve, reject) => { + const collector = this.createMessageComponentCollector(_options); + collector.once('end', (interactions, reason) => { + const interaction = interactions.first(); + if (interaction) resolve(interaction); + else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason)); + }); + }); + } + + /** + * Whether the message is editable by the client user + * @type {boolean} + * @readonly + */ + get editable() { + const precheck = Boolean(this.author.id === this.client.user.id && (!this.guild || this.channel?.viewable)); + + // Regardless of permissions thread messages cannot be edited if + // the thread is archived or the thread is locked and the bot does not have permission to manage threads. + if (this.channel?.isThread()) { + if (this.channel.archived) return false; + if (this.channel.locked) { + const permissions = this.channel.permissionsFor(this.client.user); + if (!permissions?.has(PermissionFlagsBits.ManageThreads, true)) return false; + } + } + + return precheck; + } + + /** + * Whether the message is deletable by the client user + * @type {boolean} + * @readonly + */ + get deletable() { + if (!DeletableMessageTypes.includes(this.type)) return false; + + if (!this.guild) { + return this.author.id === this.client.user.id; + } + // DMChannel does not have viewable property, so check viewable after proved that message is on a guild. + if (!this.channel?.viewable) { + return false; + } + + const permissions = this.channel?.permissionsFor(this.client.user); + if (!permissions) return false; + // This flag allows deleting even if timed out + if (permissions.has(PermissionFlagsBits.Administrator, false)) return true; + + // The auto moderation action message author is the reference message author + return ( + (this.type !== MessageType.AutoModerationAction && this.author.id === this.client.user.id) || + (permissions.has(PermissionFlagsBits.ManageMessages, false) && !this.guild.members.me.isCommunicationDisabled()) + ); + } + + /** + * Whether the message is bulk deletable by the client user + * @type {boolean} + * @readonly + * @example + * // Filter for bulk deletable messages + * channel.bulkDelete(messages.filter(message => message.bulkDeletable)); + */ + get bulkDeletable() { + return ( + (this.inGuild() && + Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge && + this.deletable && + this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageMessages, false)) ?? + false + ); + } + + /** + * Whether the message is pinnable by the client user + * @type {boolean} + * @readonly + */ + get pinnable() { + const { channel } = this; + return Boolean( + !this.system && + (!this.guild || + (channel?.viewable && + channel?.permissionsFor(this.client.user)?.has(PermissionFlagsBits.ManageMessages, false))), + ); + } + + /** + * Fetches the Message this crosspost/reply/pin-add references, if available to the client + * @returns {Promise<Message>} + */ + async fetchReference() { + if (!this.reference) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing); + const { channelId, messageId } = this.reference; + const channel = this.client.channels.resolve(channelId); + if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve); + const message = await channel.messages.fetch(messageId); + return message; + } + + /** + * Whether the message is crosspostable by the client user + * @type {boolean} + * @readonly + */ + get crosspostable() { + const bitfield = + PermissionFlagsBits.SendMessages | + (this.author.id === this.client.user.id ? PermissionsBitField.DefaultBit : PermissionFlagsBits.ManageMessages); + const { channel } = this; + return Boolean( + channel?.type === ChannelType.GuildAnnouncement && + !this.flags.has(MessageFlags.Crossposted) && + this.type === MessageType.Default && + channel.viewable && + channel.permissionsFor(this.client.user)?.has(bitfield, false), + ); + } + + /** + * Edits the content of the message. + * @param {string|MessagePayload|MessageEditOptions} options The options to provide + * @returns {Promise<Message>} + * @example + * // Update the content of a message + * message.edit('This is my new content!') + * .then(msg => console.log(`Updated the content of a message to ${msg.content}`)) + * .catch(console.error); + */ + edit(options) { + if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached)); + return this.channel.messages.edit(this, options); + } + + /** + * Publishes a message in an announcement channel to all channels following it. + * @returns {Promise<Message>} + * @example + * // Crosspost a message + * if (message.channel.type === ChannelType.GuildAnnouncement) { + * message.crosspost() + * .then(() => console.log('Crossposted message')) + * .catch(console.error); + * } + */ + crosspost() { + if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached)); + return this.channel.messages.crosspost(this.id); + } + + /** + * Pins this message to the channel's pinned messages. + * @param {string} [reason] Reason for pinning + * @returns {Promise<Message>} + * @example + * // Pin a message + * message.pin() + * .then(console.log) + * .catch(console.error) + */ + async pin(reason) { + if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached); + await this.channel.messages.pin(this.id, reason); + return this; + } + + /** + * Unpins this message from the channel's pinned messages. + * @param {string} [reason] Reason for unpinning + * @returns {Promise<Message>} + * @example + * // Unpin a message + * message.unpin() + * .then(console.log) + * .catch(console.error) + */ + async unpin(reason) { + if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached); + await this.channel.messages.unpin(this.id, reason); + return this; + } + + /** + * Adds a reaction to the message. + * @param {EmojiIdentifierResolvable} emoji The emoji to react with + * @returns {Promise<MessageReaction>} + * @example + * // React to a message with a unicode emoji + * message.react('🤔') + * .then(console.log) + * .catch(console.error); + * @example + * // React to a message with a custom emoji + * message.react(message.guild.emojis.cache.get('123456789012345678')) + * .then(console.log) + * .catch(console.error); + */ + async react(emoji) { + if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached); + await this.channel.messages.react(this.id, emoji); + + return this.client.actions.MessageReactionAdd.handle( + { + [this.client.actions.injectedUser]: this.client.user, + [this.client.actions.injectedChannel]: this.channel, + [this.client.actions.injectedMessage]: this, + emoji: resolvePartialEmoji(emoji), + }, + true, + ).reaction; + } + + /** + * Deletes the message. + * @returns {Promise<Message>} + * @example + * // Delete a message + * message.delete() + * .then(msg => console.log(`Deleted message from ${msg.author.username}`)) + * .catch(console.error); + */ + async delete() { + if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached); + await this.channel.messages.delete(this.id); + return this; + } + + /** + * Options provided when sending a message as an inline reply. + * @typedef {BaseMessageCreateOptions} MessageReplyOptions + * @property {boolean} [failIfNotExists=this.client.options.failIfNotExists] Whether to error if the referenced + * message does not exist (creates a standard message in this case when false) + */ + + /** + * Send an inline reply to this message. + * @param {string|MessagePayload|MessageReplyOptions} options The options to provide + * @returns {Promise<Message>} + * @example + * // Reply to a message + * message.reply('This is a reply!') + * .then(() => console.log(`Replied to message "${message.content}"`)) + * .catch(console.error); + */ + reply(options) { + if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached)); + let data; + + if (options instanceof MessagePayload) { + data = options; + } else { + data = MessagePayload.create(this, options, { + reply: { + messageReference: this, + failIfNotExists: options?.failIfNotExists ?? this.client.options.failIfNotExists, + }, + }); + } + return this.channel.send(data); + } + + /** + * Options for starting a thread on a message. + * @typedef {Object} StartThreadOptions + * @property {string} name The name of the new thread + * @property {ThreadAutoArchiveDuration} [autoArchiveDuration=this.channel.defaultAutoArchiveDuration] The amount of + * time after which the thread should automatically archive in case of no recent activity + * @property {string} [reason] Reason for creating the thread + * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the thread in seconds + */ + + /** + * Create a new public thread from this message + * @see GuildTextThreadManager#create + * @param {StartThreadOptions} [options] Options for starting a thread on this message + * @returns {Promise<ThreadChannel>} + */ + startThread(options = {}) { + if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached)); + if (![ChannelType.GuildText, ChannelType.GuildAnnouncement].includes(this.channel.type)) { + return Promise.reject(new DiscordjsError(ErrorCodes.MessageThreadParent)); + } + if (this.hasThread) return Promise.reject(new DiscordjsError(ErrorCodes.MessageExistingThread)); + return this.channel.threads.create({ ...options, startMessage: this }); + } + + /** + * Fetch this message. + * @param {boolean} [force=true] Whether to skip the cache check and request the API + * @returns {Promise<Message>} + */ + fetch(force = true) { + if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached)); + return this.channel.messages.fetch({ message: this.id, force }); + } + + /** + * Fetches the webhook used to create this message. + * @returns {Promise<?Webhook>} + */ + fetchWebhook() { + if (!this.webhookId) return Promise.reject(new DiscordjsError(ErrorCodes.WebhookMessage)); + if (this.webhookId === this.applicationId) return Promise.reject(new DiscordjsError(ErrorCodes.WebhookApplication)); + return this.client.fetchWebhook(this.webhookId); + } + + /** + * Suppresses or unsuppresses embeds on a message. + * @param {boolean} [suppress=true] If the embeds should be suppressed or not + * @returns {Promise<Message>} + */ + suppressEmbeds(suppress = true) { + const flags = new MessageFlagsBitField(this.flags.bitfield); + + if (suppress) { + flags.add(MessageFlags.SuppressEmbeds); + } else { + flags.remove(MessageFlags.SuppressEmbeds); + } + + return this.edit({ flags }); + } + + /** + * Removes the attachments from this message. + * @returns {Promise<Message>} + */ + removeAttachments() { + return this.edit({ attachments: [] }); + } + + /** + * Resolves a component by a custom id. + * @param {string} customId The custom id to resolve against + * @returns {?MessageActionRowComponent} + */ + resolveComponent(customId) { + return this.components.flatMap(row => row.components).find(component => component.customId === customId) ?? null; + } + + /** + * Used mainly internally. Whether two messages are identical in properties. If you want to compare messages + * without checking all the properties, use `message.id === message2.id`, which is much more efficient. This + * method allows you to see if there are differences in content, embeds, attachments, nonce and tts properties. + * @param {Message} message The message to compare it to + * @param {APIMessage} rawData Raw data passed through the WebSocket about this message + * @returns {boolean} + */ + equals(message, rawData) { + if (!message) return false; + const embedUpdate = !message.author && !message.attachments; + if (embedUpdate) return this.id === message.id && this.embeds.length === message.embeds.length; + + let equal = + this.id === message.id && + this.author.id === message.author.id && + this.content === message.content && + this.tts === message.tts && + this.nonce === message.nonce && + this.embeds.length === message.embeds.length && + this.attachments.length === message.attachments.length; + + if (equal && rawData) { + equal = + this.mentions.everyone === message.mentions.everyone && + this.createdTimestamp === Date.parse(rawData.timestamp) && + this.editedTimestamp === Date.parse(rawData.edited_timestamp); + } + + return equal; + } + + /** + * Whether this message is from a guild. + * @returns {boolean} + */ + inGuild() { + return Boolean(this.guildId); + } + + /** + * When concatenated with a string, this automatically concatenates the message's content instead of the object. + * @returns {string} + * @example + * // Logs: Message: This is a message! + * console.log(`Message: ${message}`); + */ + toString() { + return this.content; + } + + toJSON() { + return super.toJSON({ + channel: 'channelId', + author: 'authorId', + groupActivityApplication: 'groupActivityApplicationId', + guild: 'guildId', + cleanContent: true, + member: false, + reactions: false, + }); + } +} + +exports.Message = Message; diff --git a/node_modules/discord.js/src/structures/MessageCollector.js b/node_modules/discord.js/src/structures/MessageCollector.js new file mode 100644 index 0000000..7101965 --- /dev/null +++ b/node_modules/discord.js/src/structures/MessageCollector.js @@ -0,0 +1,146 @@ +'use strict'; + +const Collector = require('./interfaces/Collector'); +const Events = require('../util/Events'); + +/** + * @typedef {CollectorOptions} MessageCollectorOptions + * @property {number} max The maximum amount of messages to collect + * @property {number} maxProcessed The maximum amount of messages to process + */ + +/** + * Collects messages on a channel. + * Will automatically stop if the channel ({@link Client#event:channelDelete channelDelete}), + * thread ({@link Client#event:threadDelete threadDelete}), or + * guild ({@link Client#event:guildDelete guildDelete}) is deleted. + * @extends {Collector} + */ +class MessageCollector extends Collector { + /** + * @param {TextBasedChannels} channel The channel + * @param {MessageCollectorOptions} options The options to be applied to this collector + * @emits MessageCollector#message + */ + constructor(channel, options = {}) { + super(channel.client, options); + + /** + * The channel + * @type {TextBasedChannels} + */ + this.channel = channel; + + /** + * Total number of messages that were received in the channel during message collection + * @type {number} + */ + this.received = 0; + + const bulkDeleteListener = messages => { + for (const message of messages.values()) this.handleDispose(message); + }; + + this._handleChannelDeletion = this._handleChannelDeletion.bind(this); + this._handleThreadDeletion = this._handleThreadDeletion.bind(this); + this._handleGuildDeletion = this._handleGuildDeletion.bind(this); + + this.client.incrementMaxListeners(); + this.client.on(Events.MessageCreate, this.handleCollect); + this.client.on(Events.MessageDelete, this.handleDispose); + this.client.on(Events.MessageBulkDelete, bulkDeleteListener); + this.client.on(Events.ChannelDelete, this._handleChannelDeletion); + this.client.on(Events.ThreadDelete, this._handleThreadDeletion); + this.client.on(Events.GuildDelete, this._handleGuildDeletion); + + this.once('end', () => { + this.client.removeListener(Events.MessageCreate, this.handleCollect); + this.client.removeListener(Events.MessageDelete, this.handleDispose); + this.client.removeListener(Events.MessageBulkDelete, bulkDeleteListener); + this.client.removeListener(Events.ChannelDelete, this._handleChannelDeletion); + this.client.removeListener(Events.ThreadDelete, this._handleThreadDeletion); + this.client.removeListener(Events.GuildDelete, this._handleGuildDeletion); + this.client.decrementMaxListeners(); + }); + } + + /** + * Handles a message for possible collection. + * @param {Message} message The message that could be collected + * @returns {?Snowflake} + * @private + */ + collect(message) { + /** + * Emitted whenever a message is collected. + * @event MessageCollector#collect + * @param {Message} message The message that was collected + */ + if (message.channelId !== this.channel.id) return null; + this.received++; + return message.id; + } + + /** + * Handles a message for possible disposal. + * @param {Message} message The message that could be disposed of + * @returns {?Snowflake} + */ + dispose(message) { + /** + * Emitted whenever a message is disposed of. + * @event MessageCollector#dispose + * @param {Message} message The message that was disposed of + */ + return message.channelId === this.channel.id ? message.id : null; + } + + /** + * The reason this collector has ended with, or null if it hasn't ended yet + * @type {?string} + * @readonly + */ + get endReason() { + if (this.options.max && this.collected.size >= this.options.max) return 'limit'; + if (this.options.maxProcessed && this.received === this.options.maxProcessed) return 'processedLimit'; + return super.endReason; + } + + /** + * Handles checking if the channel has been deleted, and if so, stops the collector with the reason 'channelDelete'. + * @private + * @param {GuildChannel} channel The channel that was deleted + * @returns {void} + */ + _handleChannelDeletion(channel) { + if (channel.id === this.channel.id || channel.id === this.channel.parentId) { + this.stop('channelDelete'); + } + } + + /** + * Handles checking if the thread has been deleted, and if so, stops the collector with the reason 'threadDelete'. + * @private + * @param {ThreadChannel} thread The thread that was deleted + * @returns {void} + */ + _handleThreadDeletion(thread) { + if (thread.id === this.channel.id) { + this.stop('threadDelete'); + } + } + + /** + * Handles checking if the guild has been deleted, and if so, stops the collector with the reason 'guildDelete'. + * @private + * @param {Guild} guild The guild that was deleted + * @returns {void} + */ + _handleGuildDeletion(guild) { + if (guild.id === this.channel.guild?.id) { + this.stop('guildDelete'); + } + } +} + +module.exports = MessageCollector; diff --git a/node_modules/discord.js/src/structures/MessageComponentInteraction.js b/node_modules/discord.js/src/structures/MessageComponentInteraction.js new file mode 100644 index 0000000..47b31e0 --- /dev/null +++ b/node_modules/discord.js/src/structures/MessageComponentInteraction.js @@ -0,0 +1,107 @@ +'use strict'; + +const { lazy } = require('@discordjs/util'); +const BaseInteraction = require('./BaseInteraction'); +const InteractionWebhook = require('./InteractionWebhook'); +const InteractionResponses = require('./interfaces/InteractionResponses'); + +const getMessage = lazy(() => require('./Message').Message); + +/** + * Represents a message component interaction. + * @extends {BaseInteraction} + * @implements {InteractionResponses} + */ +class MessageComponentInteraction extends BaseInteraction { + constructor(client, data) { + super(client, data); + + /** + * The id of the channel this interaction was sent in + * @type {Snowflake} + * @name MessageComponentInteraction#channelId + */ + + /** + * The message to which the component was attached + * @type {Message} + */ + this.message = this.channel?.messages._add(data.message) ?? new (getMessage())(client, data.message); + + /** + * The custom id of the component which was interacted with + * @type {string} + */ + this.customId = data.data.custom_id; + + /** + * The type of component which was interacted with + * @type {ComponentType} + */ + this.componentType = data.data.component_type; + + /** + * Whether the reply to this interaction has been deferred + * @type {boolean} + */ + this.deferred = false; + + /** + * Whether the reply to this interaction is ephemeral + * @type {?boolean} + */ + this.ephemeral = null; + + /** + * Whether this interaction has already been replied to + * @type {boolean} + */ + this.replied = false; + + /** + * An associated interaction webhook, can be used to further interact with this interaction + * @type {InteractionWebhook} + */ + this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token); + } + + /** + * Components that can be placed in an action row for messages. + * * ButtonComponent + * * StringSelectMenuComponent + * * UserSelectMenuComponent + * * RoleSelectMenuComponent + * * MentionableSelectMenuComponent + * * ChannelSelectMenuComponent + * @typedef {ButtonComponent|StringSelectMenuComponent|UserSelectMenuComponent| + * RoleSelectMenuComponent|MentionableSelectMenuComponent|ChannelSelectMenuComponent} MessageActionRowComponent + */ + + /** + * The component which was interacted with + * @type {MessageActionRowComponent|APIMessageActionRowComponent} + * @readonly + */ + get component() { + return this.message.components + .flatMap(row => row.components) + .find(component => (component.customId ?? component.custom_id) === this.customId); + } + + // These are here only for documentation purposes - they are implemented by InteractionResponses + /* eslint-disable no-empty-function */ + deferReply() {} + reply() {} + fetchReply() {} + editReply() {} + deleteReply() {} + followUp() {} + deferUpdate() {} + update() {} + showModal() {} + awaitModalSubmit() {} +} + +InteractionResponses.applyToClass(MessageComponentInteraction); + +module.exports = MessageComponentInteraction; diff --git a/node_modules/discord.js/src/structures/MessageContextMenuCommandInteraction.js b/node_modules/discord.js/src/structures/MessageContextMenuCommandInteraction.js new file mode 100644 index 0000000..1100591 --- /dev/null +++ b/node_modules/discord.js/src/structures/MessageContextMenuCommandInteraction.js @@ -0,0 +1,20 @@ +'use strict'; + +const ContextMenuCommandInteraction = require('./ContextMenuCommandInteraction'); + +/** + * Represents a message context menu interaction. + * @extends {ContextMenuCommandInteraction} + */ +class MessageContextMenuCommandInteraction extends ContextMenuCommandInteraction { + /** + * The message this interaction was sent from + * @type {Message|APIMessage} + * @readonly + */ + get targetMessage() { + return this.options.getMessage('message'); + } +} + +module.exports = MessageContextMenuCommandInteraction; diff --git a/node_modules/discord.js/src/structures/MessageMentions.js b/node_modules/discord.js/src/structures/MessageMentions.js new file mode 100644 index 0000000..a07e77f --- /dev/null +++ b/node_modules/discord.js/src/structures/MessageMentions.js @@ -0,0 +1,297 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { FormattingPatterns } = require('discord-api-types/v10'); +const { flatten } = require('../util/Util'); + +/** + * Keeps track of mentions in a {@link Message}. + */ +class MessageMentions { + /** + * A regular expression that matches `@everyone` and `@here`. + * The `mention` group property is present on the `exec` result of this expression. + * @type {RegExp} + * @memberof MessageMentions + */ + static EveryonePattern = /@(?<mention>everyone|here)/; + + /** + * A regular expression that matches user mentions like `<@81440962496172032>`. + * The `id` group property is present on the `exec` result of this expression. + * @type {RegExp} + * @memberof MessageMentions + */ + static UsersPattern = FormattingPatterns.UserWithOptionalNickname; + + /** + * A regular expression that matches role mentions like `<@&297577916114403338>`. + * The `id` group property is present on the `exec` result of this expression. + * @type {RegExp} + * @memberof MessageMentions + */ + static RolesPattern = FormattingPatterns.Role; + + /** + * A regular expression that matches channel mentions like `<#222079895583457280>`. + * The `id` group property is present on the `exec` result of this expression. + * @type {RegExp} + * @memberof MessageMentions + */ + static ChannelsPattern = FormattingPatterns.Channel; + + /** + * A global regular expression variant of {@link MessageMentions.ChannelsPattern}. + * @type {RegExp} + * @memberof MessageMentions + * @private + */ + static GlobalChannelsPattern = new RegExp(this.ChannelsPattern.source, 'g'); + + /** + * A global regular expression variant of {@link MessageMentions.UsersPattern}. + * @type {RegExp} + * @memberof MessageMentions + * @private + */ + static GlobalUsersPattern = new RegExp(this.UsersPattern.source, 'g'); + + constructor(message, users, roles, everyone, crosspostedChannels, repliedUser) { + /** + * The client the message is from + * @type {Client} + * @readonly + */ + Object.defineProperty(this, 'client', { value: message.client }); + + /** + * The guild the message is in + * @type {?Guild} + * @readonly + */ + Object.defineProperty(this, 'guild', { value: message.guild }); + + /** + * The initial message content + * @type {string} + * @readonly + * @private + */ + Object.defineProperty(this, '_content', { value: message.content }); + + /** + * Whether `@everyone` or `@here` were mentioned + * @type {boolean} + */ + this.everyone = Boolean(everyone); + + if (users) { + if (users instanceof Collection) { + /** + * Any users that were mentioned + * <info>Order as received from the API, not as they appear in the message content</info> + * @type {Collection<Snowflake, User>} + */ + this.users = new Collection(users); + } else { + this.users = new Collection(); + for (const mention of users) { + if (mention.member && message.guild) { + message.guild.members._add(Object.assign(mention.member, { user: mention })); + } + const user = message.client.users._add(mention); + this.users.set(user.id, user); + } + } + } else { + this.users = new Collection(); + } + + if (roles instanceof Collection) { + /** + * Any roles that were mentioned + * <info>Order as received from the API, not as they appear in the message content</info> + * @type {Collection<Snowflake, Role>} + */ + this.roles = new Collection(roles); + } else if (roles) { + this.roles = new Collection(); + const guild = message.guild; + if (guild) { + for (const mention of roles) { + const role = guild.roles.cache.get(mention); + if (role) this.roles.set(role.id, role); + } + } + } else { + this.roles = new Collection(); + } + + /** + * Cached members for {@link MessageMentions#members} + * @type {?Collection<Snowflake, GuildMember>} + * @private + */ + this._members = null; + + /** + * Cached channels for {@link MessageMentions#channels} + * @type {?Collection<Snowflake, BaseChannel>} + * @private + */ + this._channels = null; + + /** + * Cached users for {@link MessageMentions#parsedUsers} + * @type {?Collection<Snowflake, User>} + * @private + */ + this._parsedUsers = null; + + /** + * Crossposted channel data. + * @typedef {Object} CrosspostedChannel + * @property {Snowflake} channelId The mentioned channel's id + * @property {Snowflake} guildId The id of the guild that has the channel + * @property {ChannelType} type The channel's type + * @property {string} name The channel's name + */ + + if (crosspostedChannels) { + if (crosspostedChannels instanceof Collection) { + /** + * A collection of crossposted channels + * <info>Order as received from the API, not as they appear in the message content</info> + * @type {Collection<Snowflake, CrosspostedChannel>} + */ + this.crosspostedChannels = new Collection(crosspostedChannels); + } else { + this.crosspostedChannels = new Collection(); + for (const d of crosspostedChannels) { + this.crosspostedChannels.set(d.id, { + channelId: d.id, + guildId: d.guild_id, + type: d.type, + name: d.name, + }); + } + } + } else { + this.crosspostedChannels = new Collection(); + } + + /** + * The author of the message that this message is a reply to + * @type {?User} + */ + this.repliedUser = repliedUser ? this.client.users._add(repliedUser) : null; + } + + /** + * Any members that were mentioned (only in {@link Guild}s) + * <info>Order as received from the API, not as they appear in the message content</info> + * @type {?Collection<Snowflake, GuildMember>} + * @readonly + */ + get members() { + if (this._members) return this._members; + if (!this.guild) return null; + this._members = new Collection(); + this.users.forEach(user => { + const member = this.guild.members.resolve(user); + if (member) this._members.set(member.user.id, member); + }); + return this._members; + } + + /** + * Any channels that were mentioned + * <info>Order as they appear first in the message content</info> + * @type {Collection<Snowflake, BaseChannel>} + * @readonly + */ + get channels() { + if (this._channels) return this._channels; + this._channels = new Collection(); + let matches; + + while ((matches = this.constructor.GlobalChannelsPattern.exec(this._content)) !== null) { + const channel = this.client.channels.cache.get(matches.groups.id); + if (channel) this._channels.set(channel.id, channel); + } + + return this._channels; + } + + /** + * Any user mentions that were included in the message content + * <info>Order as they appear first in the message content</info> + * @type {Collection<Snowflake, User>} + * @readonly + */ + get parsedUsers() { + if (this._parsedUsers) return this._parsedUsers; + this._parsedUsers = new Collection(); + let matches; + while ((matches = this.constructor.GlobalUsersPattern.exec(this._content)) !== null) { + const user = this.client.users.cache.get(matches[1]); + if (user) this._parsedUsers.set(user.id, user); + } + return this._parsedUsers; + } + + /** + * Options used to check for a mention. + * @typedef {Object} MessageMentionsHasOptions + * @property {boolean} [ignoreDirect=false] Whether to ignore direct mentions to the item + * @property {boolean} [ignoreRoles=false] Whether to ignore role mentions to a guild member + * @property {boolean} [ignoreRepliedUser=false] Whether to ignore replied user mention to an user + * @property {boolean} [ignoreEveryone=false] Whether to ignore `@everyone`/`@here` mentions + */ + + /** + * Checks if a user, guild member, thread member, role, or channel is mentioned. + * Takes into account user mentions, role mentions, channel mentions, + * replied user mention, and `@everyone`/`@here` mentions. + * @param {UserResolvable|RoleResolvable|ChannelResolvable} data The User/Role/Channel to check for + * @param {MessageMentionsHasOptions} [options] The options for the check + * @returns {boolean} + */ + has(data, { ignoreDirect = false, ignoreRoles = false, ignoreRepliedUser = false, ignoreEveryone = false } = {}) { + const user = this.client.users.resolve(data); + + if (!ignoreEveryone && user && this.everyone) return true; + + const userWasRepliedTo = user && this.repliedUser?.id === user.id; + + if (!ignoreRepliedUser && userWasRepliedTo && this.users.has(user.id)) return true; + + if (!ignoreDirect) { + if (user && (!ignoreRepliedUser || this.parsedUsers.has(user.id)) && this.users.has(user.id)) return true; + + const role = this.guild?.roles.resolve(data); + if (role && this.roles.has(role.id)) return true; + + const channel = this.client.channels.resolve(data); + if (channel && this.channels.has(channel.id)) return true; + } + + if (!ignoreRoles) { + const member = this.guild?.members.resolve(data); + if (member) { + for (const mentionedRole of this.roles.values()) if (member.roles.cache.has(mentionedRole.id)) return true; + } + } + + return false; + } + + toJSON() { + return flatten(this, { + members: true, + channels: true, + }); + } +} + +module.exports = MessageMentions; diff --git a/node_modules/discord.js/src/structures/MessagePayload.js b/node_modules/discord.js/src/structures/MessagePayload.js new file mode 100644 index 0000000..e237309 --- /dev/null +++ b/node_modules/discord.js/src/structures/MessagePayload.js @@ -0,0 +1,299 @@ +'use strict'; + +const { Buffer } = require('node:buffer'); +const { lazy, isJSONEncodable } = require('@discordjs/util'); +const { MessageFlags } = require('discord-api-types/v10'); +const ActionRowBuilder = require('./ActionRowBuilder'); +const { DiscordjsRangeError, ErrorCodes } = require('../errors'); +const DataResolver = require('../util/DataResolver'); +const MessageFlagsBitField = require('../util/MessageFlagsBitField'); +const { basename, verifyString } = require('../util/Util'); + +const getBaseInteraction = lazy(() => require('./BaseInteraction')); + +/** + * Represents a message to be sent to the API. + */ +class MessagePayload { + /** + * @param {MessageTarget} target The target for this message to be sent to + * @param {MessagePayloadOption} options The payload of this message + */ + constructor(target, options) { + /** + * The target for this message to be sent to + * @type {MessageTarget} + */ + this.target = target; + + /** + * The payload of this message. + * @type {MessagePayloadOption} + */ + this.options = options; + + /** + * Body sendable to the API + * @type {?APIMessage} + */ + this.body = null; + + /** + * Files sendable to the API + * @type {?RawFile[]} + */ + this.files = null; + } + + /** + * Whether or not the target is a {@link Webhook} or a {@link WebhookClient} + * @type {boolean} + * @readonly + */ + get isWebhook() { + const Webhook = require('./Webhook'); + const WebhookClient = require('../client/WebhookClient'); + return this.target instanceof Webhook || this.target instanceof WebhookClient; + } + + /** + * Whether or not the target is a {@link User} + * @type {boolean} + * @readonly + */ + get isUser() { + const User = require('./User'); + const { GuildMember } = require('./GuildMember'); + return this.target instanceof User || this.target instanceof GuildMember; + } + + /** + * Whether or not the target is a {@link Message} + * @type {boolean} + * @readonly + */ + get isMessage() { + const { Message } = require('./Message'); + return this.target instanceof Message; + } + + /** + * Whether or not the target is a {@link MessageManager} + * @type {boolean} + * @readonly + */ + get isMessageManager() { + const MessageManager = require('../managers/MessageManager'); + return this.target instanceof MessageManager; + } + + /** + * Whether or not the target is an {@link BaseInteraction} or an {@link InteractionWebhook} + * @type {boolean} + * @readonly + */ + get isInteraction() { + const BaseInteraction = getBaseInteraction(); + const InteractionWebhook = require('./InteractionWebhook'); + return this.target instanceof BaseInteraction || this.target instanceof InteractionWebhook; + } + + /** + * Makes the content of this message. + * @returns {?string} + */ + makeContent() { + let content; + if (this.options.content === null) { + content = ''; + } else if (this.options.content !== undefined) { + content = verifyString(this.options.content, DiscordjsRangeError, ErrorCodes.MessageContentType, true); + } + + return content; + } + + /** + * Resolves the body. + * @returns {MessagePayload} + */ + resolveBody() { + if (this.body) return this; + const isInteraction = this.isInteraction; + const isWebhook = this.isWebhook; + + const content = this.makeContent(); + const tts = Boolean(this.options.tts); + + let nonce; + if (this.options.nonce !== undefined) { + nonce = this.options.nonce; + if (typeof nonce === 'number' ? !Number.isInteger(nonce) : typeof nonce !== 'string') { + throw new DiscordjsRangeError(ErrorCodes.MessageNonceType); + } + } + + const components = this.options.components?.map(c => (isJSONEncodable(c) ? c : new ActionRowBuilder(c)).toJSON()); + + let username; + let avatarURL; + let threadName; + if (isWebhook) { + username = this.options.username ?? this.target.name; + if (this.options.avatarURL) avatarURL = this.options.avatarURL; + if (this.options.threadName) threadName = this.options.threadName; + } + + let flags; + if ( + this.options.flags !== undefined || + (this.isMessage && this.options.reply === undefined) || + this.isMessageManager + ) { + flags = + // eslint-disable-next-line eqeqeq + this.options.flags != null + ? new MessageFlagsBitField(this.options.flags).bitfield + : this.target.flags?.bitfield; + } + + if (isInteraction && this.options.ephemeral) { + flags |= MessageFlags.Ephemeral; + } + + let allowedMentions = + this.options.allowedMentions === undefined + ? this.target.client.options.allowedMentions + : this.options.allowedMentions; + + if (allowedMentions?.repliedUser !== undefined) { + allowedMentions = { ...allowedMentions, replied_user: allowedMentions.repliedUser }; + delete allowedMentions.repliedUser; + } + + let message_reference; + if (typeof this.options.reply === 'object') { + const reference = this.options.reply.messageReference; + const message_id = this.isMessage ? reference.id ?? reference : this.target.messages.resolveId(reference); + if (message_id) { + message_reference = { + message_id, + fail_if_not_exists: this.options.reply.failIfNotExists ?? this.target.client.options.failIfNotExists, + }; + } + } + + const attachments = this.options.files?.map((file, index) => ({ + id: index.toString(), + description: file.description, + })); + if (Array.isArray(this.options.attachments)) { + this.options.attachments.push(...(attachments ?? [])); + } else { + this.options.attachments = attachments; + } + + this.body = { + content, + tts, + nonce, + embeds: this.options.embeds?.map(embed => + isJSONEncodable(embed) ? embed.toJSON() : this.target.client.options.jsonTransformer(embed), + ), + components, + username, + avatar_url: avatarURL, + allowed_mentions: content === undefined && message_reference === undefined ? undefined : allowedMentions, + flags, + message_reference, + attachments: this.options.attachments, + sticker_ids: this.options.stickers?.map(sticker => sticker.id ?? sticker), + thread_name: threadName, + }; + return this; + } + + /** + * Resolves files. + * @returns {Promise<MessagePayload>} + */ + async resolveFiles() { + if (this.files) return this; + + this.files = await Promise.all(this.options.files?.map(file => this.constructor.resolveFile(file)) ?? []); + return this; + } + + /** + * Resolves a single file into an object sendable to the API. + * @param {AttachmentPayload|BufferResolvable|Stream} fileLike Something that could be resolved to a file + * @returns {Promise<RawFile>} + */ + static async resolveFile(fileLike) { + let attachment; + let name; + + const findName = thing => { + if (typeof thing === 'string') { + return basename(thing); + } + + if (thing.path) { + return basename(thing.path); + } + + return 'file.jpg'; + }; + + const ownAttachment = + typeof fileLike === 'string' || fileLike instanceof Buffer || typeof fileLike.pipe === 'function'; + if (ownAttachment) { + attachment = fileLike; + name = findName(attachment); + } else { + attachment = fileLike.attachment; + name = fileLike.name ?? findName(attachment); + } + + const { data, contentType } = await DataResolver.resolveFile(attachment); + return { data, name, contentType }; + } + + /** + * Creates a {@link MessagePayload} from user-level arguments. + * @param {MessageTarget} target Target to send to + * @param {string|MessagePayloadOption} options Options or content to use + * @param {MessagePayloadOption} [extra={}] Extra options to add onto specified options + * @returns {MessagePayload} + */ + static create(target, options, extra = {}) { + return new this( + target, + typeof options !== 'object' || options === null ? { content: options, ...extra } : { ...options, ...extra }, + ); + } +} + +module.exports = MessagePayload; + +/** + * A target for a message. + * @typedef {TextBasedChannels|User|GuildMember|Webhook|WebhookClient|BaseInteraction|InteractionWebhook| + * Message|MessageManager} MessageTarget + */ + +/** + * A possible payload option. + * @typedef {MessageCreateOptions|MessageEditOptions|WebhookMessageCreateOptions|WebhookMessageEditOptions| + * InteractionReplyOptions|InteractionUpdateOptions} MessagePayloadOption + */ + +/** + * @external APIMessage + * @see {@link https://discord.com/developers/docs/resources/channel#message-object} + */ + +/** + * @external RawFile + * @see {@link https://discord.js.org/docs/packages/rest/stable/RawFile:Interface} + */ diff --git a/node_modules/discord.js/src/structures/MessageReaction.js b/node_modules/discord.js/src/structures/MessageReaction.js new file mode 100644 index 0000000..43f05e3 --- /dev/null +++ b/node_modules/discord.js/src/structures/MessageReaction.js @@ -0,0 +1,142 @@ +'use strict'; + +const { Routes } = require('discord-api-types/v10'); +const GuildEmoji = require('./GuildEmoji'); +const ReactionEmoji = require('./ReactionEmoji'); +const ReactionUserManager = require('../managers/ReactionUserManager'); +const { flatten } = require('../util/Util'); + +/** + * Represents a reaction to a message. + */ +class MessageReaction { + constructor(client, data, message) { + /** + * The client that instantiated this message reaction + * @name MessageReaction#client + * @type {Client} + * @readonly + */ + Object.defineProperty(this, 'client', { value: client }); + + /** + * The message that this reaction refers to + * @type {Message} + */ + this.message = message; + + /** + * Whether the client has given this reaction + * @type {boolean} + */ + this.me = data.me; + + /** + * A manager of the users that have given this reaction + * @type {ReactionUserManager} + */ + this.users = new ReactionUserManager(this, this.me ? [client.user] : []); + + this._emoji = new ReactionEmoji(this, data.emoji); + + this._patch(data); + } + + _patch(data) { + if ('count' in data) { + /** + * The number of people that have given the same reaction + * @type {?number} + */ + this.count ??= data.count; + } + } + + /** + * Makes the client user react with this reaction + * @returns {Promise<MessageReaction>} + */ + react() { + return this.message.react(this.emoji); + } + + /** + * Removes all users from this reaction. + * @returns {Promise<MessageReaction>} + */ + async remove() { + await this.client.rest.delete( + Routes.channelMessageReaction(this.message.channelId, this.message.id, this._emoji.identifier), + ); + return this; + } + + /** + * The emoji of this reaction. Either a {@link GuildEmoji} object for known custom emojis, or a {@link ReactionEmoji} + * object which has fewer properties. Whatever the prototype of the emoji, it will still have + * `name`, `id`, `identifier` and `toString()` + * @type {GuildEmoji|ReactionEmoji} + * @readonly + */ + get emoji() { + if (this._emoji instanceof GuildEmoji) return this._emoji; + // Check to see if the emoji has become known to the client + if (this._emoji.id) { + const emojis = this.message.client.emojis.cache; + if (emojis.has(this._emoji.id)) { + const emoji = emojis.get(this._emoji.id); + this._emoji = emoji; + return emoji; + } + } + return this._emoji; + } + + /** + * Whether or not this reaction is a partial + * @type {boolean} + * @readonly + */ + get partial() { + return this.count === null; + } + + /** + * Fetch this reaction. + * @returns {Promise<MessageReaction>} + */ + async fetch() { + const message = await this.message.fetch(); + const existing = message.reactions.cache.get(this.emoji.id ?? this.emoji.name); + // The reaction won't get set when it has been completely removed + this._patch(existing ?? { count: 0 }); + return this; + } + + toJSON() { + return flatten(this, { emoji: 'emojiId', message: 'messageId' }); + } + + valueOf() { + return this._emoji.id ?? this._emoji.name; + } + + _add(user) { + if (this.partial) return; + this.users.cache.set(user.id, user); + if (!this.me || user.id !== this.message.client.user.id || this.count === 0) this.count++; + this.me ||= user.id === this.message.client.user.id; + } + + _remove(user) { + if (this.partial) return; + this.users.cache.delete(user.id); + if (!this.me || user.id !== this.message.client.user.id) this.count--; + if (user.id === this.message.client.user.id) this.me = false; + if (this.count <= 0 && this.users.cache.size === 0) { + this.message.reactions.cache.delete(this.emoji.id ?? this.emoji.name); + } + } +} + +module.exports = MessageReaction; diff --git a/node_modules/discord.js/src/structures/ModalBuilder.js b/node_modules/discord.js/src/structures/ModalBuilder.js new file mode 100644 index 0000000..535b4a5 --- /dev/null +++ b/node_modules/discord.js/src/structures/ModalBuilder.js @@ -0,0 +1,34 @@ +'use strict'; + +const { ModalBuilder: BuildersModal, ComponentBuilder } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { toSnakeCase } = require('../util/Transformers'); + +/** + * Represents a modal builder. + * @extends {BuildersModal} + */ +class ModalBuilder extends BuildersModal { + constructor({ components, ...data } = {}) { + super({ + ...toSnakeCase(data), + components: components?.map(c => (c instanceof ComponentBuilder ? c : toSnakeCase(c))), + }); + } + + /** + * Creates a new modal builder from JSON data + * @param {ModalBuilder|APIModalComponent} other The other data + * @returns {ModalBuilder} + */ + static from(other) { + return new this(isJSONEncodable(other) ? other.toJSON() : other); + } +} + +module.exports = ModalBuilder; + +/** + * @external BuildersModal + * @see {@link https://discord.js.org/docs/packages/builders/stable/ModalBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/ModalSubmitFields.js b/node_modules/discord.js/src/structures/ModalSubmitFields.js new file mode 100644 index 0000000..8e67b21 --- /dev/null +++ b/node_modules/discord.js/src/structures/ModalSubmitFields.js @@ -0,0 +1,55 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { ComponentType } = require('discord-api-types/v10'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * Represents the serialized fields from a modal submit interaction + */ +class ModalSubmitFields { + constructor(components) { + /** + * The components within the modal + * @type {ActionRowModalData[]} + */ + this.components = components; + + /** + * The extracted fields from the modal + * @type {Collection<string, ModalData>} + */ + this.fields = components.reduce((accumulator, next) => { + next.components.forEach(c => accumulator.set(c.customId, c)); + return accumulator; + }, new Collection()); + } + + /** + * Gets a field given a custom id from a component + * @param {string} customId The custom id of the component + * @param {ComponentType} [type] The type of the component + * @returns {ModalData} + */ + getField(customId, type) { + const field = this.fields.get(customId); + if (!field) throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionFieldNotFound, customId); + + if (type !== undefined && type !== field.type) { + throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionFieldType, customId, field.type, type); + } + + return field; + } + + /** + * Gets the value of a text input component given a custom id + * @param {string} customId The custom id of the text input component + * @returns {string} + */ + getTextInputValue(customId) { + return this.getField(customId, ComponentType.TextInput).value; + } +} + +module.exports = ModalSubmitFields; diff --git a/node_modules/discord.js/src/structures/ModalSubmitInteraction.js b/node_modules/discord.js/src/structures/ModalSubmitInteraction.js new file mode 100644 index 0000000..8f0ccf1 --- /dev/null +++ b/node_modules/discord.js/src/structures/ModalSubmitInteraction.js @@ -0,0 +1,122 @@ +'use strict'; + +const { lazy } = require('@discordjs/util'); +const BaseInteraction = require('./BaseInteraction'); +const InteractionWebhook = require('./InteractionWebhook'); +const ModalSubmitFields = require('./ModalSubmitFields'); +const InteractionResponses = require('./interfaces/InteractionResponses'); + +const getMessage = lazy(() => require('./Message').Message); + +/** + * @typedef {Object} ModalData + * @property {string} value The value of the field + * @property {ComponentType} type The component type of the field + * @property {string} customId The custom id of the field + */ + +/** + * @typedef {Object} ActionRowModalData + * @property {ModalData[]} components The components of this action row + * @property {ComponentType} type The component type of the action row + */ + +/** + * Represents a modal interaction + * @extends {BaseInteraction} + * @implements {InteractionResponses} + */ +class ModalSubmitInteraction extends BaseInteraction { + constructor(client, data) { + super(client, data); + /** + * The custom id of the modal. + * @type {string} + */ + this.customId = data.data.custom_id; + + if ('message' in data) { + /** + * The message associated with this interaction + * @type {?Message} + */ + this.message = this.channel?.messages._add(data.message) ?? new (getMessage())(this.client, data.message); + } else { + this.message = null; + } + + /** + * The components within the modal + * @type {ActionRowModalData[]} + */ + this.components = data.data.components?.map(c => ModalSubmitInteraction.transformComponent(c)); + + /** + * The fields within the modal + * @type {ModalSubmitFields} + */ + this.fields = new ModalSubmitFields(this.components); + + /** + * Whether the reply to this interaction has been deferred + * @type {boolean} + */ + this.deferred = false; + + /** + * Whether this interaction has already been replied to + * @type {boolean} + */ + this.replied = false; + + /** + * Whether the reply to this interaction is ephemeral + * @type {?boolean} + */ + this.ephemeral = null; + + /** + * An associated interaction webhook, can be used to further interact with this interaction + * @type {InteractionWebhook} + */ + this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token); + } + + /** + * Transforms component data to discord.js-compatible data + * @param {*} rawComponent The data to transform + * @returns {ModalData[]} + */ + static transformComponent(rawComponent) { + return rawComponent.components + ? { type: rawComponent.type, components: rawComponent.components.map(c => this.transformComponent(c)) } + : { + value: rawComponent.value, + type: rawComponent.type, + customId: rawComponent.custom_id, + }; + } + + /** + * Whether this is from a {@link MessageComponentInteraction}. + * @returns {boolean} + */ + isFromMessage() { + return Boolean(this.message); + } + + // These are here only for documentation purposes - they are implemented by InteractionResponses + /* eslint-disable no-empty-function */ + deferReply() {} + reply() {} + fetchReply() {} + editReply() {} + deleteReply() {} + followUp() {} + deferUpdate() {} + update() {} +} + +InteractionResponses.applyToClass(ModalSubmitInteraction, 'showModal'); + +module.exports = ModalSubmitInteraction; diff --git a/node_modules/discord.js/src/structures/NewsChannel.js b/node_modules/discord.js/src/structures/NewsChannel.js new file mode 100644 index 0000000..3f5aff3 --- /dev/null +++ b/node_modules/discord.js/src/structures/NewsChannel.js @@ -0,0 +1,32 @@ +'use strict'; + +const { Routes } = require('discord-api-types/v10'); +const BaseGuildTextChannel = require('./BaseGuildTextChannel'); +const { DiscordjsError, ErrorCodes } = require('../errors'); + +/** + * Represents a guild news channel on Discord. + * @extends {BaseGuildTextChannel} + */ +class NewsChannel extends BaseGuildTextChannel { + /** + * Adds the target to this channel's followers. + * @param {TextChannelResolvable} channel The channel where the webhook should be created + * @param {string} [reason] Reason for creating the webhook + * @returns {Promise<NewsChannel>} + * @example + * if (channel.type === ChannelType.GuildAnnouncement) { + * channel.addFollower('222197033908436994', 'Important announcements') + * .then(() => console.log('Added follower')) + * .catch(console.error); + * } + */ + async addFollower(channel, reason) { + const channelId = this.guild.channels.resolveId(channel); + if (!channelId) throw new DiscordjsError(ErrorCodes.GuildChannelResolve); + await this.client.rest.post(Routes.channelFollowers(this.id), { body: { webhook_channel_id: channelId }, reason }); + return this; + } +} + +module.exports = NewsChannel; diff --git a/node_modules/discord.js/src/structures/OAuth2Guild.js b/node_modules/discord.js/src/structures/OAuth2Guild.js new file mode 100644 index 0000000..d5104ac --- /dev/null +++ b/node_modules/discord.js/src/structures/OAuth2Guild.js @@ -0,0 +1,28 @@ +'use strict'; + +const BaseGuild = require('./BaseGuild'); +const PermissionsBitField = require('../util/PermissionsBitField'); + +/** + * A partial guild received when using {@link GuildManager#fetch} to fetch multiple guilds. + * @extends {BaseGuild} + */ +class OAuth2Guild extends BaseGuild { + constructor(client, data) { + super(client, data); + + /** + * Whether the client user is the owner of the guild + * @type {boolean} + */ + this.owner = data.owner; + + /** + * The permissions that the client user has in this guild + * @type {Readonly<PermissionsBitField>} + */ + this.permissions = new PermissionsBitField(BigInt(data.permissions)).freeze(); + } +} + +module.exports = OAuth2Guild; diff --git a/node_modules/discord.js/src/structures/PartialGroupDMChannel.js b/node_modules/discord.js/src/structures/PartialGroupDMChannel.js new file mode 100644 index 0000000..ecbb878 --- /dev/null +++ b/node_modules/discord.js/src/structures/PartialGroupDMChannel.js @@ -0,0 +1,60 @@ +'use strict'; + +const { BaseChannel } = require('./BaseChannel'); +const { DiscordjsError, ErrorCodes } = require('../errors'); + +/** + * Represents a Partial Group DM Channel on Discord. + * @extends {BaseChannel} + */ +class PartialGroupDMChannel extends BaseChannel { + constructor(client, data) { + super(client, data); + + // No flags are present when fetching partial group DM channels. + this.flags = null; + + /** + * The name of this Group DM Channel + * @type {?string} + */ + this.name = data.name; + + /** + * The hash of the channel icon + * @type {?string} + */ + this.icon = data.icon; + + /** + * Recipient data received in a {@link PartialGroupDMChannel}. + * @typedef {Object} PartialRecipient + * @property {string} username The username of the recipient + */ + + /** + * The recipients of this Group DM Channel. + * @type {PartialRecipient[]} + */ + this.recipients = data.recipients; + } + + /** + * The URL to this channel's icon. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + iconURL(options = {}) { + return this.icon && this.client.rest.cdn.channelIcon(this.id, this.icon, options); + } + + delete() { + return Promise.reject(new DiscordjsError(ErrorCodes.DeleteGroupDMChannel)); + } + + fetch() { + return Promise.reject(new DiscordjsError(ErrorCodes.FetchGroupDMChannel)); + } +} + +module.exports = PartialGroupDMChannel; diff --git a/node_modules/discord.js/src/structures/PermissionOverwrites.js b/node_modules/discord.js/src/structures/PermissionOverwrites.js new file mode 100644 index 0000000..2cdc827 --- /dev/null +++ b/node_modules/discord.js/src/structures/PermissionOverwrites.js @@ -0,0 +1,196 @@ +'use strict'; + +const { OverwriteType } = require('discord-api-types/v10'); +const Base = require('./Base'); +const { Role } = require('./Role'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +const PermissionsBitField = require('../util/PermissionsBitField'); + +/** + * Represents a permission overwrite for a role or member in a guild channel. + * @extends {Base} + */ +class PermissionOverwrites extends Base { + constructor(client, data, channel) { + super(client); + + /** + * The GuildChannel this overwrite is for + * @name PermissionOverwrites#channel + * @type {GuildChannel} + * @readonly + */ + Object.defineProperty(this, 'channel', { value: channel }); + + if (data) this._patch(data); + } + + _patch(data) { + /** + * The overwrite's id, either a {@link User} or a {@link Role} id + * @type {Snowflake} + */ + this.id = data.id; + + if ('type' in data) { + /** + * The type of this overwrite + * @type {OverwriteType} + */ + this.type = data.type; + } + + if ('deny' in data) { + /** + * The permissions that are denied for the user or role. + * @type {Readonly<PermissionsBitField>} + */ + this.deny = new PermissionsBitField(BigInt(data.deny)).freeze(); + } + + if ('allow' in data) { + /** + * The permissions that are allowed for the user or role. + * @type {Readonly<PermissionsBitField>} + */ + this.allow = new PermissionsBitField(BigInt(data.allow)).freeze(); + } + } + + /** + * Edits this Permission Overwrite. + * @param {PermissionOverwriteOptions} options The options for the update + * @param {string} [reason] Reason for creating/editing this overwrite + * @returns {Promise<PermissionOverwrites>} + * @example + * // Update permission overwrites + * permissionOverwrites.edit({ + * SendMessages: false + * }) + * .then(channel => console.log(channel.permissionOverwrites.get(message.author.id))) + * .catch(console.error); + */ + async edit(options, reason) { + await this.channel.permissionOverwrites.upsert(this.id, options, { type: this.type, reason }, this); + return this; + } + + /** + * Deletes this Permission Overwrite. + * @param {string} [reason] Reason for deleting this overwrite + * @returns {Promise<PermissionOverwrites>} + */ + async delete(reason) { + await this.channel.permissionOverwrites.delete(this.id, reason); + return this; + } + + toJSON() { + return { + id: this.id, + type: this.type, + allow: this.allow, + deny: this.deny, + }; + } + + /** + * An object mapping permission flags to `true` (enabled), `null` (unset) or `false` (disabled). + * ```js + * { + * 'SendMessages': true, + * 'EmbedLinks': null, + * 'AttachFiles': false, + * } + * ``` + * @typedef {Object} PermissionOverwriteOptions + */ + + /** + * @typedef {Object} ResolvedOverwriteOptions + * @property {PermissionsBitField} allow The allowed permissions + * @property {PermissionsBitField} deny The denied permissions + */ + + /** + * Resolves bitfield permissions overwrites from an object. + * @param {PermissionOverwriteOptions} options The options for the update + * @param {ResolvedOverwriteOptions} initialPermissions The initial permissions + * @returns {ResolvedOverwriteOptions} + */ + static resolveOverwriteOptions(options, { allow, deny } = {}) { + allow = new PermissionsBitField(allow); + deny = new PermissionsBitField(deny); + + for (const [perm, value] of Object.entries(options)) { + if (value === true) { + allow.add(perm); + deny.remove(perm); + } else if (value === false) { + allow.remove(perm); + deny.add(perm); + } else if (value === null) { + allow.remove(perm); + deny.remove(perm); + } + } + + return { allow, deny }; + } + + /** + * The raw data for a permission overwrite + * @typedef {Object} RawOverwriteData + * @property {Snowflake} id The id of the {@link Role} or {@link User} this overwrite belongs to + * @property {string} allow The permissions to allow + * @property {string} deny The permissions to deny + * @property {number} type The type of this OverwriteData + */ + + /** + * Data that can be resolved into {@link RawOverwriteData}. This can be: + * * PermissionOverwrites + * * OverwriteData + * @typedef {PermissionOverwrites|OverwriteData} OverwriteResolvable + */ + + /** + * Data that can be used for a permission overwrite + * @typedef {Object} OverwriteData + * @property {GuildMemberResolvable|RoleResolvable} id Member or role this overwrite is for + * @property {PermissionResolvable} [allow] The permissions to allow + * @property {PermissionResolvable} [deny] The permissions to deny + * @property {OverwriteType} [type] The type of this OverwriteData + */ + + /** + * Resolves an overwrite into {@link RawOverwriteData}. + * @param {OverwriteResolvable} overwrite The overwrite-like data to resolve + * @param {Guild} [guild] The guild to resolve from + * @returns {RawOverwriteData} + */ + static resolve(overwrite, guild) { + if (overwrite instanceof this) return overwrite.toJSON(); + if (typeof overwrite.id === 'string' && overwrite.type in OverwriteType) { + return { + id: overwrite.id, + type: overwrite.type, + allow: PermissionsBitField.resolve(overwrite.allow ?? PermissionsBitField.DefaultBit).toString(), + deny: PermissionsBitField.resolve(overwrite.deny ?? PermissionsBitField.DefaultBit).toString(), + }; + } + + const userOrRole = guild.roles.resolve(overwrite.id) ?? guild.client.users.resolve(overwrite.id); + if (!userOrRole) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'parameter', 'User nor a Role'); + const type = userOrRole instanceof Role ? OverwriteType.Role : OverwriteType.Member; + + return { + id: userOrRole.id, + type, + allow: PermissionsBitField.resolve(overwrite.allow ?? PermissionsBitField.DefaultBit).toString(), + deny: PermissionsBitField.resolve(overwrite.deny ?? PermissionsBitField.DefaultBit).toString(), + }; + } +} + +module.exports = PermissionOverwrites; diff --git a/node_modules/discord.js/src/structures/Presence.js b/node_modules/discord.js/src/structures/Presence.js new file mode 100644 index 0000000..79ecb29 --- /dev/null +++ b/node_modules/discord.js/src/structures/Presence.js @@ -0,0 +1,378 @@ +'use strict'; + +const Base = require('./Base'); +const { Emoji } = require('./Emoji'); +const ActivityFlagsBitField = require('../util/ActivityFlagsBitField'); +const { flatten } = require('../util/Util'); + +/** + * Activity sent in a message. + * @typedef {Object} MessageActivity + * @property {string} [partyId] Id of the party represented in activity + * @property {MessageActivityType} type Type of activity sent + */ + +/** + * The status of this presence: + * * **`online`** - user is online + * * **`idle`** - user is AFK + * * **`offline`** - user is offline or invisible + * * **`dnd`** - user is in Do Not Disturb + * @typedef {string} PresenceStatus + */ + +/** + * The status of this presence: + * * **`online`** - user is online + * * **`idle`** - user is AFK + * * **`dnd`** - user is in Do Not Disturb + * @typedef {string} ClientPresenceStatus + */ + +/** + * Represents a user's presence. + * @extends {Base} + */ +class Presence extends Base { + constructor(client, data = {}) { + super(client); + + /** + * The presence's user id + * @type {Snowflake} + */ + this.userId = data.user.id; + + /** + * The guild this presence is in + * @type {?Guild} + */ + this.guild = data.guild ?? null; + + this._patch(data); + } + + /** + * The user of this presence + * @type {?User} + * @readonly + */ + get user() { + return this.client.users.resolve(this.userId); + } + + /** + * The member of this presence + * @type {?GuildMember} + * @readonly + */ + get member() { + return this.guild.members.resolve(this.userId); + } + + _patch(data) { + if ('status' in data) { + /** + * The status of this presence + * @type {PresenceStatus} + */ + this.status = data.status; + } else { + this.status ??= 'offline'; + } + + if ('activities' in data) { + /** + * The activities of this presence + * @type {Activity[]} + */ + this.activities = data.activities.map(activity => new Activity(this, activity)); + } else { + this.activities ??= []; + } + + if ('client_status' in data) { + /** + * The devices this presence is on + * @type {?Object} + * @property {?ClientPresenceStatus} web The current presence in the web application + * @property {?ClientPresenceStatus} mobile The current presence in the mobile application + * @property {?ClientPresenceStatus} desktop The current presence in the desktop application + */ + this.clientStatus = data.client_status; + } else { + this.clientStatus ??= null; + } + + return this; + } + + _clone() { + const clone = Object.assign(Object.create(this), this); + clone.activities = this.activities.map(activity => activity._clone()); + return clone; + } + + /** + * Whether this presence is equal to another. + * @param {Presence} presence The presence to compare with + * @returns {boolean} + */ + equals(presence) { + return ( + this === presence || + (presence && + this.status === presence.status && + this.activities.length === presence.activities.length && + this.activities.every((activity, index) => activity.equals(presence.activities[index])) && + this.clientStatus?.web === presence.clientStatus?.web && + this.clientStatus?.mobile === presence.clientStatus?.mobile && + this.clientStatus?.desktop === presence.clientStatus?.desktop) + ); + } + + toJSON() { + return flatten(this); + } +} + +/** + * Represents an activity that is part of a user's presence. + */ +class Activity { + constructor(presence, data) { + /** + * The presence of the Activity + * @type {Presence} + * @readonly + * @name Activity#presence + */ + Object.defineProperty(this, 'presence', { value: presence }); + + /** + * The activity's name + * @type {string} + */ + this.name = data.name; + + /** + * The activity status's type + * @type {ActivityType} + */ + this.type = data.type; + + /** + * If the activity is being streamed, a link to the stream + * @type {?string} + */ + this.url = data.url ?? null; + + /** + * Details about the activity + * @type {?string} + */ + this.details = data.details ?? null; + + /** + * State of the activity + * @type {?string} + */ + this.state = data.state ?? null; + + /** + * The id of the application associated with this activity + * @type {?Snowflake} + */ + this.applicationId = data.application_id ?? null; + + /** + * Represents timestamps of an activity + * @typedef {Object} ActivityTimestamps + * @property {?Date} start When the activity started + * @property {?Date} end When the activity will end + */ + + /** + * Timestamps for the activity + * @type {?ActivityTimestamps} + */ + this.timestamps = data.timestamps + ? { + start: data.timestamps.start ? new Date(Number(data.timestamps.start)) : null, + end: data.timestamps.end ? new Date(Number(data.timestamps.end)) : null, + } + : null; + + /** + * Represents a party of an activity + * @typedef {Object} ActivityParty + * @property {?string} id The party's id + * @property {number[]} size Size of the party as `[current, max]` + */ + + /** + * Party of the activity + * @type {?ActivityParty} + */ + this.party = data.party ?? null; + + /** + * Assets for rich presence + * @type {?RichPresenceAssets} + */ + this.assets = data.assets ? new RichPresenceAssets(this, data.assets) : null; + + /** + * Flags that describe the activity + * @type {Readonly<ActivityFlagsBitField>} + */ + this.flags = new ActivityFlagsBitField(data.flags).freeze(); + + /** + * Emoji for a custom activity + * @type {?Emoji} + */ + this.emoji = data.emoji ? new Emoji(presence.client, data.emoji) : null; + + /** + * The labels of the buttons of this rich presence + * @type {string[]} + */ + this.buttons = data.buttons ?? []; + + /** + * Creation date of the activity + * @type {number} + */ + this.createdTimestamp = data.created_at; + } + + /** + * Whether this activity is equal to another activity. + * @param {Activity} activity The activity to compare with + * @returns {boolean} + */ + equals(activity) { + return ( + this === activity || + (activity && + this.name === activity.name && + this.type === activity.type && + this.url === activity.url && + this.state === activity.state && + this.details === activity.details && + this.emoji?.id === activity.emoji?.id && + this.emoji?.name === activity.emoji?.name) + ); + } + + /** + * The time the activity was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * When concatenated with a string, this automatically returns the activity's name instead of the Activity object. + * @returns {string} + */ + toString() { + return this.name; + } + + _clone() { + return Object.assign(Object.create(this), this); + } +} + +/** + * Assets for a rich presence + */ +class RichPresenceAssets { + constructor(activity, assets) { + /** + * The activity of the RichPresenceAssets + * @type {Activity} + * @readonly + * @name RichPresenceAssets#activity + */ + Object.defineProperty(this, 'activity', { value: activity }); + + /** + * Hover text for the large image + * @type {?string} + */ + this.largeText = assets.large_text ?? null; + + /** + * Hover text for the small image + * @type {?string} + */ + this.smallText = assets.small_text ?? null; + + /** + * The large image asset's id + * @type {?Snowflake} + */ + this.largeImage = assets.large_image ?? null; + + /** + * The small image asset's id + * @type {?Snowflake} + */ + this.smallImage = assets.small_image ?? null; + } + + /** + * Gets the URL of the small image asset + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + smallImageURL(options = {}) { + if (!this.smallImage) return null; + if (this.smallImage.includes(':')) { + const [platform, id] = this.smallImage.split(':'); + switch (platform) { + case 'mp': + return `https://media.discordapp.net/${id}`; + default: + return null; + } + } + + return this.activity.presence.client.rest.cdn.appAsset(this.activity.applicationId, this.smallImage, options); + } + + /** + * Gets the URL of the large image asset + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + largeImageURL(options = {}) { + if (!this.largeImage) return null; + if (this.largeImage.includes(':')) { + const [platform, id] = this.largeImage.split(':'); + switch (platform) { + case 'mp': + return `https://media.discordapp.net/${id}`; + case 'spotify': + return `https://i.scdn.co/image/${id}`; + case 'youtube': + return `https://i.ytimg.com/vi/${id}/hqdefault_live.jpg`; + case 'twitch': + return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${id}.png`; + default: + return null; + } + } + + return this.activity.presence.client.rest.cdn.appAsset(this.activity.applicationId, this.largeImage, options); + } +} + +exports.Presence = Presence; +exports.Activity = Activity; +exports.RichPresenceAssets = RichPresenceAssets; diff --git a/node_modules/discord.js/src/structures/ReactionCollector.js b/node_modules/discord.js/src/structures/ReactionCollector.js new file mode 100644 index 0000000..924b33b --- /dev/null +++ b/node_modules/discord.js/src/structures/ReactionCollector.js @@ -0,0 +1,229 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const Collector = require('./interfaces/Collector'); +const Events = require('../util/Events'); + +/** + * @typedef {CollectorOptions} ReactionCollectorOptions + * @property {number} max The maximum total amount of reactions to collect + * @property {number} maxEmojis The maximum number of emojis to collect + * @property {number} maxUsers The maximum number of users to react + */ + +/** + * Collects reactions on messages. + * Will automatically stop if the message ({@link Client#event:messageDelete messageDelete} or + * {@link Client#event:messageDeleteBulk messageDeleteBulk}), + * channel ({@link Client#event:channelDelete channelDelete}), + * thread ({@link Client#event:threadDelete threadDelete}), or + * guild ({@link Client#event:guildDelete guildDelete}) is deleted. + * @extends {Collector} + */ +class ReactionCollector extends Collector { + /** + * @param {Message} message The message upon which to collect reactions + * @param {ReactionCollectorOptions} [options={}] The options to apply to this collector + */ + constructor(message, options = {}) { + super(message.client, options); + + /** + * The message upon which to collect reactions + * @type {Message} + */ + this.message = message; + + /** + * The users that have reacted to this message + * @type {Collection} + */ + this.users = new Collection(); + + /** + * The total number of reactions collected + * @type {number} + */ + this.total = 0; + + this.empty = this.empty.bind(this); + this._handleChannelDeletion = this._handleChannelDeletion.bind(this); + this._handleThreadDeletion = this._handleThreadDeletion.bind(this); + this._handleGuildDeletion = this._handleGuildDeletion.bind(this); + this._handleMessageDeletion = this._handleMessageDeletion.bind(this); + + const bulkDeleteListener = messages => { + if (messages.has(this.message.id)) this.stop('messageDelete'); + }; + + this.client.incrementMaxListeners(); + this.client.on(Events.MessageReactionAdd, this.handleCollect); + this.client.on(Events.MessageReactionRemove, this.handleDispose); + this.client.on(Events.MessageReactionRemoveAll, this.empty); + this.client.on(Events.MessageDelete, this._handleMessageDeletion); + this.client.on(Events.MessageBulkDelete, bulkDeleteListener); + this.client.on(Events.ChannelDelete, this._handleChannelDeletion); + this.client.on(Events.ThreadDelete, this._handleThreadDeletion); + this.client.on(Events.GuildDelete, this._handleGuildDeletion); + + this.once('end', () => { + this.client.removeListener(Events.MessageReactionAdd, this.handleCollect); + this.client.removeListener(Events.MessageReactionRemove, this.handleDispose); + this.client.removeListener(Events.MessageReactionRemoveAll, this.empty); + this.client.removeListener(Events.MessageDelete, this._handleMessageDeletion); + this.client.removeListener(Events.MessageBulkDelete, bulkDeleteListener); + this.client.removeListener(Events.ChannelDelete, this._handleChannelDeletion); + this.client.removeListener(Events.ThreadDelete, this._handleThreadDeletion); + this.client.removeListener(Events.GuildDelete, this._handleGuildDeletion); + this.client.decrementMaxListeners(); + }); + + this.on('collect', (reaction, user) => { + /** + * Emitted whenever a reaction is newly created on a message. Will emit only when a new reaction is + * added to the message, as opposed to {@link Collector#collect} which will + * be emitted even when a reaction has already been added to the message. + * @event ReactionCollector#create + * @param {MessageReaction} reaction The reaction that was added + * @param {User} user The user that added the reaction + */ + if (reaction.count === 1) { + this.emit('create', reaction, user); + } + this.total++; + this.users.set(user.id, user); + }); + + this.on('remove', (reaction, user) => { + this.total--; + if (!this.collected.some(r => r.users.cache.has(user.id))) this.users.delete(user.id); + }); + } + + /** + * Handles an incoming reaction for possible collection. + * @param {MessageReaction} reaction The reaction to possibly collect + * @param {User} user The user that added the reaction + * @returns {?(Snowflake|string)} + * @private + */ + collect(reaction) { + /** + * Emitted whenever a reaction is collected. + * @event ReactionCollector#collect + * @param {MessageReaction} reaction The reaction that was collected + * @param {User} user The user that added the reaction + */ + if (reaction.message.id !== this.message.id) return null; + + return ReactionCollector.key(reaction); + } + + /** + * Handles a reaction deletion for possible disposal. + * @param {MessageReaction} reaction The reaction to possibly dispose of + * @param {User} user The user that removed the reaction + * @returns {?(Snowflake|string)} + */ + dispose(reaction, user) { + /** + * Emitted when the reaction had all the users removed and the `dispose` option is set to true. + * @event ReactionCollector#dispose + * @param {MessageReaction} reaction The reaction that was disposed of + * @param {User} user The user that removed the reaction + */ + if (reaction.message.id !== this.message.id) return null; + + /** + * Emitted when the reaction had one user removed and the `dispose` option is set to true. + * @event ReactionCollector#remove + * @param {MessageReaction} reaction The reaction that was removed + * @param {User} user The user that removed the reaction + */ + if (this.collected.has(ReactionCollector.key(reaction)) && this.users.has(user.id)) { + this.emit('remove', reaction, user); + } + return reaction.count ? null : ReactionCollector.key(reaction); + } + + /** + * Empties this reaction collector. + */ + empty() { + this.total = 0; + this.collected.clear(); + this.users.clear(); + this.checkEnd(); + } + + /** + * The reason this collector has ended with, or null if it hasn't ended yet + * @type {?string} + * @readonly + */ + get endReason() { + if (this.options.max && this.total >= this.options.max) return 'limit'; + if (this.options.maxEmojis && this.collected.size >= this.options.maxEmojis) return 'emojiLimit'; + if (this.options.maxUsers && this.users.size >= this.options.maxUsers) return 'userLimit'; + return super.endReason; + } + + /** + * Handles checking if the message has been deleted, and if so, stops the collector with the reason 'messageDelete'. + * @private + * @param {Message} message The message that was deleted + * @returns {void} + */ + _handleMessageDeletion(message) { + if (message.id === this.message.id) { + this.stop('messageDelete'); + } + } + + /** + * Handles checking if the channel has been deleted, and if so, stops the collector with the reason 'channelDelete'. + * @private + * @param {GuildChannel} channel The channel that was deleted + * @returns {void} + */ + _handleChannelDeletion(channel) { + if (channel.id === this.message.channelId || channel.threads?.cache.has(this.message.channelId)) { + this.stop('channelDelete'); + } + } + + /** + * Handles checking if the thread has been deleted, and if so, stops the collector with the reason 'threadDelete'. + * @private + * @param {ThreadChannel} thread The thread that was deleted + * @returns {void} + */ + _handleThreadDeletion(thread) { + if (thread.id === this.message.channelId) { + this.stop('threadDelete'); + } + } + + /** + * Handles checking if the guild has been deleted, and if so, stops the collector with the reason 'guildDelete'. + * @private + * @param {Guild} guild The guild that was deleted + * @returns {void} + */ + _handleGuildDeletion(guild) { + if (guild.id === this.message.guild?.id) { + this.stop('guildDelete'); + } + } + + /** + * Gets the collector key for a reaction. + * @param {MessageReaction} reaction The message reaction to get the key for + * @returns {Snowflake|string} + */ + static key(reaction) { + return reaction.emoji.id ?? reaction.emoji.name; + } +} + +module.exports = ReactionCollector; diff --git a/node_modules/discord.js/src/structures/ReactionEmoji.js b/node_modules/discord.js/src/structures/ReactionEmoji.js new file mode 100644 index 0000000..08e2ea0 --- /dev/null +++ b/node_modules/discord.js/src/structures/ReactionEmoji.js @@ -0,0 +1,31 @@ +'use strict'; + +const { Emoji } = require('./Emoji'); +const { flatten } = require('../util/Util'); + +/** + * Represents a limited emoji set used for both custom and unicode emojis. Custom emojis + * will use this class opposed to the Emoji class when the client doesn't know enough + * information about them. + * @extends {Emoji} + */ +class ReactionEmoji extends Emoji { + constructor(reaction, emoji) { + super(reaction.message.client, emoji); + /** + * The message reaction this emoji refers to + * @type {MessageReaction} + */ + this.reaction = reaction; + } + + toJSON() { + return flatten(this, { identifier: true }); + } + + valueOf() { + return this.id; + } +} + +module.exports = ReactionEmoji; diff --git a/node_modules/discord.js/src/structures/Role.js b/node_modules/discord.js/src/structures/Role.js new file mode 100644 index 0000000..09a2a52 --- /dev/null +++ b/node_modules/discord.js/src/structures/Role.js @@ -0,0 +1,471 @@ +'use strict'; + +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { PermissionFlagsBits } = require('discord-api-types/v10'); +const Base = require('./Base'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const PermissionsBitField = require('../util/PermissionsBitField'); +const RoleFlagsBitField = require('../util/RoleFlagsBitField'); + +/** + * Represents a role on Discord. + * @extends {Base} + */ +class Role extends Base { + constructor(client, data, guild) { + super(client); + + /** + * The guild that the role belongs to + * @type {Guild} + */ + this.guild = guild; + + /** + * The icon hash of the role + * @type {?string} + */ + this.icon = null; + + /** + * The unicode emoji for the role + * @type {?string} + */ + this.unicodeEmoji = null; + + if (data) this._patch(data); + } + + _patch(data) { + /** + * The role's id (unique to the guild it is part of) + * @type {Snowflake} + */ + this.id = data.id; + if ('name' in data) { + /** + * The name of the role + * @type {string} + */ + this.name = data.name; + } + + if ('color' in data) { + /** + * The base 10 color of the role + * @type {number} + */ + this.color = data.color; + } + + if ('hoist' in data) { + /** + * If true, users that are part of this role will appear in a separate category in the users list + * @type {boolean} + */ + this.hoist = data.hoist; + } + + if ('position' in data) { + /** + * The raw position of the role from the API + * @type {number} + */ + this.rawPosition = data.position; + } + + if ('permissions' in data) { + /** + * The permissions of the role + * @type {Readonly<PermissionsBitField>} + */ + this.permissions = new PermissionsBitField(BigInt(data.permissions)).freeze(); + } + + if ('managed' in data) { + /** + * Whether or not the role is managed by an external service + * @type {boolean} + */ + this.managed = data.managed; + } + + if ('mentionable' in data) { + /** + * Whether or not the role can be mentioned by anyone + * @type {boolean} + */ + this.mentionable = data.mentionable; + } + + if ('icon' in data) this.icon = data.icon; + + if ('unicode_emoji' in data) this.unicodeEmoji = data.unicode_emoji; + + if ('flags' in data) { + /** + * The flags of this role + * @type {Readonly<RoleFlagsBitField>} + */ + this.flags = new RoleFlagsBitField(data.flags).freeze(); + } else { + this.flags ??= new RoleFlagsBitField().freeze(); + } + + /** + * The tags this role has + * @type {?Object} + * @property {Snowflake} [botId] The id of the bot this role belongs to + * @property {Snowflake|string} [integrationId] The id of the integration this role belongs to + * @property {true} [premiumSubscriberRole] Whether this is the guild's premium subscription role + * @property {Snowflake} [subscriptionListingId] The id of this role's subscription SKU and listing + * @property {true} [availableForPurchase] Whether this role is available for purchase + * @property {true} [guildConnections] Whether this role is a guild's linked role + */ + this.tags = data.tags ? {} : null; + if (data.tags) { + if ('bot_id' in data.tags) { + this.tags.botId = data.tags.bot_id; + } + if ('integration_id' in data.tags) { + this.tags.integrationId = data.tags.integration_id; + } + if ('premium_subscriber' in data.tags) { + this.tags.premiumSubscriberRole = true; + } + if ('subscription_listing_id' in data.tags) { + this.tags.subscriptionListingId = data.tags.subscription_listing_id; + } + if ('available_for_purchase' in data.tags) { + this.tags.availableForPurchase = true; + } + if ('guild_connections' in data.tags) { + this.tags.guildConnections = true; + } + } + } + + /** + * The timestamp the role was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the role was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The hexadecimal version of the role color, with a leading hashtag + * @type {string} + * @readonly + */ + get hexColor() { + return `#${this.color.toString(16).padStart(6, '0')}`; + } + + /** + * The cached guild members that have this role + * @type {Collection<Snowflake, GuildMember>} + * @readonly + */ + get members() { + return this.id === this.guild.id + ? this.guild.members.cache.clone() + : this.guild.members.cache.filter(m => m._roles.includes(this.id)); + } + + /** + * Whether the role is editable by the client user + * @type {boolean} + * @readonly + */ + get editable() { + if (this.managed) return false; + const clientMember = this.guild.members.resolve(this.client.user); + if (!clientMember.permissions.has(PermissionFlagsBits.ManageRoles)) return false; + return clientMember.roles.highest.comparePositionTo(this) > 0; + } + + /** + * The position of the role in the role manager + * @type {number} + * @readonly + */ + get position() { + return this.guild.roles.cache.reduce( + (acc, role) => + acc + + (this.rawPosition === role.rawPosition + ? BigInt(this.id) > BigInt(role.id) + : this.rawPosition > role.rawPosition), + 0, + ); + } + + /** + * Compares this role's position to another role's. + * @param {RoleResolvable} role Role to compare to this one + * @returns {number} Negative number if this role's position is lower (other role's is higher), + * positive number if this one is higher (other's is lower), 0 if equal + * @example + * // Compare the position of a role to another + * const roleCompare = role.comparePositionTo(otherRole); + * if (roleCompare >= 1) console.log(`${role.name} is higher than ${otherRole.name}`); + */ + comparePositionTo(role) { + return this.guild.roles.comparePositions(this, role); + } + + /** + * The data for a role. + * @typedef {Object} RoleData + * @property {string} [name] The name of the role + * @property {ColorResolvable} [color] The color of the role, either a hex string or a base 10 number + * @property {boolean} [hoist] Whether or not the role should be hoisted + * @property {number} [position] The position of the role + * @property {PermissionResolvable} [permissions] The permissions of the role + * @property {boolean} [mentionable] Whether or not the role should be mentionable + * @property {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} [icon] The icon for the role + * <warn>The `EmojiResolvable` should belong to the same guild as the role. + * If not, pass the emoji's URL directly</warn> + * @property {?string} [unicodeEmoji] The unicode emoji for the role + */ + + /** + * Edits the role. + * @param {RoleEditOptions} options The options to provide + * @returns {Promise<Role>} + * @example + * // Edit a role + * role.edit({ name: 'new role' }) + * .then(updated => console.log(`Edited role name to ${updated.name}`)) + * .catch(console.error); + */ + edit(options) { + return this.guild.roles.edit(this, options); + } + + /** + * Returns `channel.permissionsFor(role)`. Returns permissions for a role in a guild channel, + * taking into account permission overwrites. + * @param {GuildChannel|Snowflake} channel The guild channel to use as context + * @param {boolean} [checkAdmin=true] Whether having the {@link PermissionFlagsBits.Administrator} permission + * will return all permissions + * @returns {Readonly<PermissionsBitField>} + */ + permissionsIn(channel, checkAdmin = true) { + channel = this.guild.channels.resolve(channel); + if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve); + return channel.rolePermissions(this, checkAdmin); + } + + /** + * Sets a new name for the role. + * @param {string} name The new name of the role + * @param {string} [reason] Reason for changing the role's name + * @returns {Promise<Role>} + * @example + * // Set the name of the role + * role.setName('new role') + * .then(updated => console.log(`Updated role name to ${updated.name}`)) + * .catch(console.error); + */ + setName(name, reason) { + return this.edit({ name, reason }); + } + + /** + * Sets a new color for the role. + * @param {ColorResolvable} color The color of the role + * @param {string} [reason] Reason for changing the role's color + * @returns {Promise<Role>} + * @example + * // Set the color of a role + * role.setColor('#FF0000') + * .then(updated => console.log(`Set color of role to ${updated.color}`)) + * .catch(console.error); + */ + setColor(color, reason) { + return this.edit({ color, reason }); + } + + /** + * Sets whether or not the role should be hoisted. + * @param {boolean} [hoist=true] Whether or not to hoist the role + * @param {string} [reason] Reason for setting whether or not the role should be hoisted + * @returns {Promise<Role>} + * @example + * // Set the hoist of the role + * role.setHoist(true) + * .then(updated => console.log(`Role hoisted: ${updated.hoist}`)) + * .catch(console.error); + */ + setHoist(hoist = true, reason) { + return this.edit({ hoist, reason }); + } + + /** + * Sets the permissions of the role. + * @param {PermissionResolvable} permissions The permissions of the role + * @param {string} [reason] Reason for changing the role's permissions + * @returns {Promise<Role>} + * @example + * // Set the permissions of the role + * role.setPermissions([PermissionFlagsBits.KickMembers, PermissionFlagsBits.BanMembers]) + * .then(updated => console.log(`Updated permissions to ${updated.permissions.bitfield}`)) + * .catch(console.error); + * @example + * // Remove all permissions from a role + * role.setPermissions(0n) + * .then(updated => console.log(`Updated permissions to ${updated.permissions.bitfield}`)) + * .catch(console.error); + */ + setPermissions(permissions, reason) { + return this.edit({ permissions, reason }); + } + + /** + * Sets whether this role is mentionable. + * @param {boolean} [mentionable=true] Whether this role should be mentionable + * @param {string} [reason] Reason for setting whether or not this role should be mentionable + * @returns {Promise<Role>} + * @example + * // Make the role mentionable + * role.setMentionable(true) + * .then(updated => console.log(`Role updated ${updated.name}`)) + * .catch(console.error); + */ + setMentionable(mentionable = true, reason) { + return this.edit({ mentionable, reason }); + } + + /** + * Sets a new icon for the role. + * @param {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} icon The icon for the role + * <warn>The `EmojiResolvable` should belong to the same guild as the role. + * If not, pass the emoji's URL directly</warn> + * @param {string} [reason] Reason for changing the role's icon + * @returns {Promise<Role>} + */ + setIcon(icon, reason) { + return this.edit({ icon, reason }); + } + + /** + * Sets a new unicode emoji for the role. + * @param {?string} unicodeEmoji The new unicode emoji for the role + * @param {string} [reason] Reason for changing the role's unicode emoji + * @returns {Promise<Role>} + * @example + * // Set a new unicode emoji for the role + * role.setUnicodeEmoji('🤖') + * .then(updated => console.log(`Set unicode emoji for the role to ${updated.unicodeEmoji}`)) + * .catch(console.error); + */ + setUnicodeEmoji(unicodeEmoji, reason) { + return this.edit({ unicodeEmoji, reason }); + } + + /** + * Options used to set the position of a role. + * @typedef {Object} SetRolePositionOptions + * @property {boolean} [relative=false] Whether to change the position relative to its current value or not + * @property {string} [reason] The reason for changing the position + */ + + /** + * Sets the new position of the role. + * @param {number} position The new position for the role + * @param {SetRolePositionOptions} [options] Options for setting the position + * @returns {Promise<Role>} + * @example + * // Set the position of the role + * role.setPosition(1) + * .then(updated => console.log(`Role position: ${updated.position}`)) + * .catch(console.error); + */ + setPosition(position, options = {}) { + return this.guild.roles.setPosition(this, position, options); + } + + /** + * Deletes the role. + * @param {string} [reason] Reason for deleting this role + * @returns {Promise<Role>} + * @example + * // Delete a role + * role.delete('The role needed to go') + * .then(deleted => console.log(`Deleted role ${deleted.name}`)) + * .catch(console.error); + */ + async delete(reason) { + await this.guild.roles.delete(this.id, reason); + return this; + } + + /** + * A link to the role's icon + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + iconURL(options = {}) { + return this.icon && this.client.rest.cdn.roleIcon(this.id, this.icon, options); + } + + /** + * Whether this role equals another role. It compares all properties, so for most operations + * it is advisable to just compare `role.id === role2.id` as it is much faster and is often + * what most users need. + * @param {Role} role Role to compare with + * @returns {boolean} + */ + equals(role) { + return ( + role && + this.id === role.id && + this.name === role.name && + this.color === role.color && + this.hoist === role.hoist && + this.position === role.position && + this.permissions.bitfield === role.permissions.bitfield && + this.managed === role.managed && + this.icon === role.icon && + this.unicodeEmoji === role.unicodeEmoji + ); + } + + /** + * When concatenated with a string, this automatically returns the role's mention instead of the Role object. + * @returns {string} + * @example + * // Logs: Role: <@&123456789012345678> + * console.log(`Role: ${role}`); + */ + toString() { + if (this.id === this.guild.id) return '@everyone'; + return `<@&${this.id}>`; + } + + toJSON() { + return { + ...super.toJSON({ createdTimestamp: true }), + permissions: this.permissions.toJSON(), + }; + } +} + +exports.Role = Role; + +/** + * @external APIRole + * @see {@link https://discord.com/developers/docs/topics/permissions#role-object} + */ diff --git a/node_modules/discord.js/src/structures/RoleSelectMenuBuilder.js b/node_modules/discord.js/src/structures/RoleSelectMenuBuilder.js new file mode 100644 index 0000000..0d80de5 --- /dev/null +++ b/node_modules/discord.js/src/structures/RoleSelectMenuBuilder.js @@ -0,0 +1,31 @@ +'use strict'; + +const { RoleSelectMenuBuilder: BuildersRoleSelectMenu } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { toSnakeCase } = require('../util/Transformers'); + +/** + * Class used to build select menu components to be sent through the API + * @extends {BuildersRoleSelectMenu} + */ +class RoleSelectMenuBuilder extends BuildersRoleSelectMenu { + constructor(data = {}) { + super(toSnakeCase(data)); + } + + /** + * Creates a new select menu builder from JSON data + * @param {RoleSelectMenuBuilder|RoleSelectMenuComponent|APIRoleSelectComponent} other The other data + * @returns {RoleSelectMenuBuilder} + */ + static from(other) { + return new this(isJSONEncodable(other) ? other.toJSON() : other); + } +} + +module.exports = RoleSelectMenuBuilder; + +/** + * @external BuildersRoleSelectMenu + * @see {@link https://discord.js.org/docs/packages/builders/stable/RoleSelectMenuBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/RoleSelectMenuComponent.js b/node_modules/discord.js/src/structures/RoleSelectMenuComponent.js new file mode 100644 index 0000000..1b27942 --- /dev/null +++ b/node_modules/discord.js/src/structures/RoleSelectMenuComponent.js @@ -0,0 +1,11 @@ +'use strict'; + +const BaseSelectMenuComponent = require('./BaseSelectMenuComponent'); + +/** + * Represents a role select menu component + * @extends {BaseSelectMenuComponent} + */ +class RoleSelectMenuComponent extends BaseSelectMenuComponent {} + +module.exports = RoleSelectMenuComponent; diff --git a/node_modules/discord.js/src/structures/RoleSelectMenuInteraction.js b/node_modules/discord.js/src/structures/RoleSelectMenuInteraction.js new file mode 100644 index 0000000..eb42eff --- /dev/null +++ b/node_modules/discord.js/src/structures/RoleSelectMenuInteraction.js @@ -0,0 +1,33 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const MessageComponentInteraction = require('./MessageComponentInteraction'); + +/** + * Represents a {@link ComponentType.RoleSelect} select menu interaction. + * @extends {MessageComponentInteraction} + */ +class RoleSelectMenuInteraction extends MessageComponentInteraction { + constructor(client, data) { + super(client, data); + const { resolved, values } = data.data; + + /** + * An array of the selected role ids + * @type {Snowflake[]} + */ + this.values = values ?? []; + + /** + * Collection of the selected roles + * @type {Collection<Snowflake, Role|APIRole>} + */ + this.roles = new Collection(); + + for (const role of Object.values(resolved?.roles ?? {})) { + this.roles.set(role.id, this.guild?.roles._add(role) ?? role); + } + } +} + +module.exports = RoleSelectMenuInteraction; diff --git a/node_modules/discord.js/src/structures/SelectMenuBuilder.js b/node_modules/discord.js/src/structures/SelectMenuBuilder.js new file mode 100644 index 0000000..a779370 --- /dev/null +++ b/node_modules/discord.js/src/structures/SelectMenuBuilder.js @@ -0,0 +1,26 @@ +'use strict'; + +const process = require('node:process'); +const StringSelectMenuBuilder = require('./StringSelectMenuBuilder'); + +let deprecationEmitted = false; + +/** + * @deprecated Use {@link StringSelectMenuBuilder} instead. + * @extends {StringSelectMenuBuilder} + */ +class SelectMenuBuilder extends StringSelectMenuBuilder { + constructor(...params) { + super(...params); + + if (!deprecationEmitted) { + process.emitWarning( + 'The SelectMenuBuilder class is deprecated. Use StringSelectMenuBuilder instead.', + 'DeprecationWarning', + ); + deprecationEmitted = true; + } + } +} + +module.exports = SelectMenuBuilder; diff --git a/node_modules/discord.js/src/structures/SelectMenuComponent.js b/node_modules/discord.js/src/structures/SelectMenuComponent.js new file mode 100644 index 0000000..2cd8097 --- /dev/null +++ b/node_modules/discord.js/src/structures/SelectMenuComponent.js @@ -0,0 +1,26 @@ +'use strict'; + +const process = require('node:process'); +const StringSelectMenuComponent = require('./StringSelectMenuComponent'); + +let deprecationEmitted = false; + +/** + * @deprecated Use {@link StringSelectMenuComponent} instead. + * @extends {StringSelectMenuComponent} + */ +class SelectMenuComponent extends StringSelectMenuComponent { + constructor(...params) { + super(...params); + + if (!deprecationEmitted) { + process.emitWarning( + 'The SelectMenuComponent class is deprecated. Use StringSelectMenuComponent instead.', + 'DeprecationWarning', + ); + deprecationEmitted = true; + } + } +} + +module.exports = SelectMenuComponent; diff --git a/node_modules/discord.js/src/structures/SelectMenuInteraction.js b/node_modules/discord.js/src/structures/SelectMenuInteraction.js new file mode 100644 index 0000000..a096559 --- /dev/null +++ b/node_modules/discord.js/src/structures/SelectMenuInteraction.js @@ -0,0 +1,26 @@ +'use strict'; + +const process = require('node:process'); +const StringSelectMenuInteraction = require('./StringSelectMenuInteraction'); + +let deprecationEmitted = false; + +/** + * @deprecated Use {@link StringSelectMenuInteraction} instead. + * @extends {StringSelectMenuInteraction} + */ +class SelectMenuInteraction extends StringSelectMenuInteraction { + constructor(...params) { + super(...params); + + if (!deprecationEmitted) { + process.emitWarning( + 'The SelectMenuInteraction class is deprecated. Use StringSelectMenuInteraction instead.', + 'DeprecationWarning', + ); + deprecationEmitted = true; + } + } +} + +module.exports = SelectMenuInteraction; diff --git a/node_modules/discord.js/src/structures/SelectMenuOptionBuilder.js b/node_modules/discord.js/src/structures/SelectMenuOptionBuilder.js new file mode 100644 index 0000000..85309d1 --- /dev/null +++ b/node_modules/discord.js/src/structures/SelectMenuOptionBuilder.js @@ -0,0 +1,26 @@ +'use strict'; + +const process = require('node:process'); +const StringSelectMenuOptionBuilder = require('./StringSelectMenuOptionBuilder'); + +let deprecationEmitted = false; + +/** + * @deprecated Use {@link StringSelectMenuOptionBuilder} instead. + * @extends {StringSelectMenuOptionBuilder} + */ +class SelectMenuOptionBuilder extends StringSelectMenuOptionBuilder { + constructor(...params) { + super(...params); + + if (!deprecationEmitted) { + process.emitWarning( + 'The SelectMenuOptionBuilder class is deprecated. Use StringSelectMenuOptionBuilder instead.', + 'DeprecationWarning', + ); + deprecationEmitted = true; + } + } +} + +module.exports = SelectMenuOptionBuilder; diff --git a/node_modules/discord.js/src/structures/StageChannel.js b/node_modules/discord.js/src/structures/StageChannel.js new file mode 100644 index 0000000..2661489 --- /dev/null +++ b/node_modules/discord.js/src/structures/StageChannel.js @@ -0,0 +1,112 @@ +'use strict'; + +const BaseGuildVoiceChannel = require('./BaseGuildVoiceChannel'); + +/** + * Represents a guild stage channel on Discord. + * @extends {BaseGuildVoiceChannel} + */ +class StageChannel extends BaseGuildVoiceChannel { + _patch(data) { + super._patch(data); + + if ('topic' in data) { + /** + * The topic of the stage channel + * @type {?string} + */ + this.topic = data.topic; + } + } + + /** + * The stage instance of this stage channel, if it exists + * @type {?StageInstance} + * @readonly + */ + get stageInstance() { + return this.guild.stageInstances.cache.find(stageInstance => stageInstance.channelId === this.id) ?? null; + } + + /** + * Creates a stage instance associated with this stage channel. + * @param {StageInstanceCreateOptions} options The options to create the stage instance + * @returns {Promise<StageInstance>} + */ + createStageInstance(options) { + return this.guild.stageInstances.create(this.id, options); + } + + /** + * Sets a new topic for the guild channel. + * @param {?string} topic The new topic for the guild channel + * @param {string} [reason] Reason for changing the guild channel's topic + * @returns {Promise<StageChannel>} + * @example + * // Set a new channel topic + * stageChannel.setTopic('needs more rate limiting') + * .then(channel => console.log(`Channel's new topic is ${channel.topic}`)) + * .catch(console.error); + */ + setTopic(topic, reason) { + return this.edit({ topic, reason }); + } +} + +/** + * Sets the bitrate of the channel. + * @method setBitrate + * @memberof StageChannel + * @instance + * @param {number} bitrate The new bitrate + * @param {string} [reason] Reason for changing the channel's bitrate + * @returns {Promise<StageChannel>} + * @example + * // Set the bitrate of a voice channel + * stageChannel.setBitrate(48_000) + * .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`)) + * .catch(console.error); + */ + +/** + * Sets the RTC region of the channel. + * @method setRTCRegion + * @memberof StageChannel + * @instance + * @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel + * @param {string} [reason] The reason for modifying this region. + * @returns {Promise<StageChannel>} + * @example + * // Set the RTC region to sydney + * stageChannel.setRTCRegion('sydney'); + * @example + * // Remove a fixed region for this channel - let Discord decide automatically + * stageChannel.setRTCRegion(null, 'We want to let Discord decide.'); + */ + +/** + * Sets the user limit of the channel. + * @method setUserLimit + * @memberof StageChannel + * @instance + * @param {number} userLimit The new user limit + * @param {string} [reason] Reason for changing the user limit + * @returns {Promise<StageChannel>} + * @example + * // Set the user limit of a voice channel + * stageChannel.setUserLimit(42) + * .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`)) + * .catch(console.error); + */ + +/** + * Sets the camera video quality mode of the channel. + * @method setVideoQualityMode + * @memberof StageChannel + * @instance + * @param {VideoQualityMode} videoQualityMode The new camera video quality mode. + * @param {string} [reason] Reason for changing the camera video quality mode. + * @returns {Promise<StageChannel>} + */ + +module.exports = StageChannel; diff --git a/node_modules/discord.js/src/structures/StageInstance.js b/node_modules/discord.js/src/structures/StageInstance.js new file mode 100644 index 0000000..97f65df --- /dev/null +++ b/node_modules/discord.js/src/structures/StageInstance.js @@ -0,0 +1,167 @@ +'use strict'; + +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const Base = require('./Base'); + +/** + * Represents a stage instance. + * @extends {Base} + */ +class StageInstance extends Base { + constructor(client, data) { + super(client); + + /** + * The stage instance's id + * @type {Snowflake} + */ + this.id = data.id; + + this._patch(data); + } + + _patch(data) { + if ('guild_id' in data) { + /** + * The id of the guild associated with the stage channel + * @type {Snowflake} + */ + this.guildId = data.guild_id; + } + + if ('channel_id' in data) { + /** + * The id of the channel associated with the stage channel + * @type {Snowflake} + */ + this.channelId = data.channel_id; + } + + if ('topic' in data) { + /** + * The topic of the stage instance + * @type {string} + */ + this.topic = data.topic; + } + + if ('privacy_level' in data) { + /** + * The privacy level of the stage instance + * @type {StageInstancePrivacyLevel} + */ + this.privacyLevel = data.privacy_level; + } + + if ('discoverable_disabled' in data) { + /** + * Whether or not stage discovery is disabled + * @type {?boolean} + * @deprecated See https://github.com/discord/discord-api-docs/pull/4296 for more information + */ + this.discoverableDisabled = data.discoverable_disabled; + } else { + this.discoverableDisabled ??= null; + } + + if ('guild_scheduled_event_id' in data) { + /** + * The associated guild scheduled event id of this stage instance + * @type {?Snowflake} + */ + this.guildScheduledEventId = data.guild_scheduled_event_id; + } else { + this.guildScheduledEventId ??= null; + } + } + + /** + * The stage channel associated with this stage instance + * @type {?StageChannel} + * @readonly + */ + get channel() { + return this.client.channels.resolve(this.channelId); + } + + /** + * The guild this stage instance belongs to + * @type {?Guild} + * @readonly + */ + get guild() { + return this.client.guilds.resolve(this.guildId); + } + + /** + * The associated guild scheduled event of this stage instance + * @type {?GuildScheduledEvent} + * @readonly + */ + get guildScheduledEvent() { + return this.guild?.scheduledEvents.resolve(this.guildScheduledEventId) ?? null; + } + + /** + * Edits this stage instance. + * @param {StageInstanceEditOptions} options The options to edit the stage instance + * @returns {Promise<StageInstance>} + * @example + * // Edit a stage instance + * stageInstance.edit({ topic: 'new topic' }) + * .then(stageInstance => console.log(stageInstance)) + * .catch(console.error) + */ + edit(options) { + return this.guild.stageInstances.edit(this.channelId, options); + } + + /** + * Deletes this stage instance. + * @returns {Promise<StageInstance>} + * @example + * // Delete a stage instance + * stageInstance.delete() + * .then(stageInstance => console.log(stageInstance)) + * .catch(console.error); + */ + async delete() { + await this.guild.stageInstances.delete(this.channelId); + const clone = this._clone(); + return clone; + } + + /** + * Sets the topic of this stage instance. + * @param {string} topic The topic for the stage instance + * @returns {Promise<StageInstance>} + * @example + * // Set topic of a stage instance + * stageInstance.setTopic('new topic') + * .then(stageInstance => console.log(`Set the topic to: ${stageInstance.topic}`)) + * .catch(console.error); + */ + setTopic(topic) { + return this.guild.stageInstances.edit(this.channelId, { topic }); + } + + /** + * The timestamp this stage instances was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time this stage instance was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } +} + +exports.StageInstance = StageInstance; diff --git a/node_modules/discord.js/src/structures/Sticker.js b/node_modules/discord.js/src/structures/Sticker.js new file mode 100644 index 0000000..b0f2ef6 --- /dev/null +++ b/node_modules/discord.js/src/structures/Sticker.js @@ -0,0 +1,272 @@ +'use strict'; + +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { Routes } = require('discord-api-types/v10'); +const Base = require('./Base'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const { StickerFormatExtensionMap } = require('../util/Constants'); + +/** + * Represents a Sticker. + * @extends {Base} + */ +class Sticker extends Base { + constructor(client, sticker) { + super(client); + + this._patch(sticker); + } + + _patch(sticker) { + /** + * The sticker's id + * @type {Snowflake} + */ + this.id = sticker.id; + + if ('description' in sticker) { + /** + * The description of the sticker + * @type {?string} + */ + this.description = sticker.description; + } else { + this.description ??= null; + } + + if ('type' in sticker) { + /** + * The type of the sticker + * @type {?StickerType} + */ + this.type = sticker.type; + } else { + this.type ??= null; + } + + if ('format_type' in sticker) { + /** + * The format of the sticker + * @type {StickerFormatType} + */ + this.format = sticker.format_type; + } + + if ('name' in sticker) { + /** + * The name of the sticker + * @type {string} + */ + this.name = sticker.name; + } + + if ('pack_id' in sticker) { + /** + * The id of the pack the sticker is from, for standard stickers + * @type {?Snowflake} + */ + this.packId = sticker.pack_id; + } else { + this.packId ??= null; + } + + if ('tags' in sticker) { + /** + * Autocomplete/suggestions for the sticker + * @type {?string} + */ + this.tags = sticker.tags; + } else { + this.tags ??= null; + } + + if ('available' in sticker) { + /** + * Whether or not the guild sticker is available + * @type {?boolean} + */ + this.available = sticker.available; + } else { + this.available ??= null; + } + + if ('guild_id' in sticker) { + /** + * The id of the guild that owns this sticker + * @type {?Snowflake} + */ + this.guildId = sticker.guild_id; + } else { + this.guildId ??= null; + } + + if ('user' in sticker) { + /** + * The user that uploaded the guild sticker + * @type {?User} + */ + this.user = this.client.users._add(sticker.user); + } else { + this.user ??= null; + } + + if ('sort_value' in sticker) { + /** + * The standard sticker's sort order within its pack + * @type {?number} + */ + this.sortValue = sticker.sort_value; + } else { + this.sortValue ??= null; + } + } + + /** + * The timestamp the sticker was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the sticker was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * Whether this sticker is partial + * @type {boolean} + * @readonly + */ + get partial() { + return !this.type; + } + + /** + * The guild that owns this sticker + * @type {?Guild} + * @readonly + */ + get guild() { + return this.client.guilds.resolve(this.guildId); + } + + /** + * A link to the sticker + * <info>If the sticker's format is {@link StickerFormatType.Lottie}, it returns + * the URL of the Lottie JSON file.</info> + * @type {string} + * @readonly + */ + get url() { + return this.client.rest.cdn.sticker(this.id, StickerFormatExtensionMap[this.format]); + } + + /** + * Fetches this sticker. + * @returns {Promise<Sticker>} + */ + async fetch() { + const data = await this.client.rest.get(Routes.sticker(this.id)); + this._patch(data); + return this; + } + + /** + * Fetches the pack this sticker is part of from Discord, if this is a Nitro sticker. + * @returns {Promise<?StickerPack>} + */ + async fetchPack() { + return (this.packId && (await this.client.fetchPremiumStickerPacks()).get(this.packId)) ?? null; + } + + /** + * Fetches the user who uploaded this sticker, if this is a guild sticker. + * @returns {Promise<?User>} + */ + async fetchUser() { + if (this.partial) await this.fetch(); + if (!this.guildId) throw new DiscordjsError(ErrorCodes.NotGuildSticker); + return this.guild.stickers.fetchUser(this); + } + + /** + * Data for editing a sticker. + * @typedef {Object} GuildStickerEditOptions + * @property {string} [name] The name of the sticker + * @property {?string} [description] The description of the sticker + * @property {string} [tags] The Discord name of a unicode emoji representing the sticker's expression + * @property {string} [reason] Reason for editing this sticker + */ + + /** + * Edits the sticker. + * @param {GuildStickerEditOptions} options The options to provide + * @returns {Promise<Sticker>} + * @example + * // Update the name of a sticker + * sticker.edit({ name: 'new name' }) + * .then(s => console.log(`Updated the name of the sticker to ${s.name}`)) + * .catch(console.error); + */ + edit(options) { + return this.guild.stickers.edit(this, options); + } + + /** + * Deletes the sticker. + * @returns {Promise<Sticker>} + * @param {string} [reason] Reason for deleting this sticker + * @example + * // Delete a message + * sticker.delete() + * .then(s => console.log(`Deleted sticker ${s.name}`)) + * .catch(console.error); + */ + async delete(reason) { + await this.guild.stickers.delete(this, reason); + return this; + } + + /** + * Whether this sticker is the same as another one. + * @param {Sticker|APISticker} other The sticker to compare it to + * @returns {boolean} + */ + equals(other) { + if (other instanceof Sticker) { + return ( + other.id === this.id && + other.description === this.description && + other.type === this.type && + other.format === this.format && + other.name === this.name && + other.packId === this.packId && + other.tags === this.tags && + other.available === this.available && + other.guildId === this.guildId && + other.sortValue === this.sortValue + ); + } else { + return ( + other.id === this.id && + other.description === this.description && + other.name === this.name && + other.tags === this.tags + ); + } + } +} + +exports.Sticker = Sticker; + +/** + * @external APISticker + * @see {@link https://discord.com/developers/docs/resources/sticker#sticker-object} + */ diff --git a/node_modules/discord.js/src/structures/StickerPack.js b/node_modules/discord.js/src/structures/StickerPack.js new file mode 100644 index 0000000..7e599b7 --- /dev/null +++ b/node_modules/discord.js/src/structures/StickerPack.js @@ -0,0 +1,95 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const Base = require('./Base'); +const { Sticker } = require('./Sticker'); + +/** + * Represents a pack of standard stickers. + * @extends {Base} + */ +class StickerPack extends Base { + constructor(client, pack) { + super(client); + /** + * The Sticker pack's id + * @type {Snowflake} + */ + this.id = pack.id; + + /** + * The stickers in the pack + * @type {Collection<Snowflake, Sticker>} + */ + this.stickers = new Collection(pack.stickers.map(s => [s.id, new Sticker(client, s)])); + + /** + * The name of the sticker pack + * @type {string} + */ + this.name = pack.name; + + /** + * The id of the pack's SKU + * @type {Snowflake} + */ + this.skuId = pack.sku_id; + + /** + * The id of a sticker in the pack which is shown as the pack's icon + * @type {?Snowflake} + */ + this.coverStickerId = pack.cover_sticker_id ?? null; + + /** + * The description of the sticker pack + * @type {string} + */ + this.description = pack.description; + + /** + * The id of the sticker pack's banner image + * @type {?Snowflake} + */ + this.bannerId = pack.banner_asset_id ?? null; + } + + /** + * The timestamp the sticker was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the sticker was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The sticker which is shown as the pack's icon + * @type {?Sticker} + * @readonly + */ + get coverSticker() { + return this.coverStickerId && this.stickers.get(this.coverStickerId); + } + + /** + * The URL to this sticker pack's banner. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + bannerURL(options = {}) { + return this.bannerId && this.client.rest.cdn.stickerPackBanner(this.bannerId, options); + } +} + +module.exports = StickerPack; diff --git a/node_modules/discord.js/src/structures/StringSelectMenuBuilder.js b/node_modules/discord.js/src/structures/StringSelectMenuBuilder.js new file mode 100644 index 0000000..ac555e7 --- /dev/null +++ b/node_modules/discord.js/src/structures/StringSelectMenuBuilder.js @@ -0,0 +1,79 @@ +'use strict'; + +const { SelectMenuBuilder: BuildersSelectMenu, normalizeArray } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { toSnakeCase } = require('../util/Transformers'); +const { resolvePartialEmoji } = require('../util/Util'); + +/** + * Class used to build select menu components to be sent through the API + * @extends {BuildersSelectMenu} + */ +class StringSelectMenuBuilder extends BuildersSelectMenu { + constructor({ options, ...data } = {}) { + super( + toSnakeCase({ + ...data, + options: options?.map(({ emoji, ...option }) => ({ + ...option, + emoji: emoji && typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji, + })), + }), + ); + } + + /** + * Normalizes a select menu option emoji + * @param {SelectMenuOptionData|APISelectMenuOption} selectMenuOption The option to normalize + * @returns {SelectMenuOptionBuilder|APISelectMenuOption} + * @private + */ + static normalizeEmoji(selectMenuOption) { + if (isJSONEncodable(selectMenuOption)) { + return selectMenuOption; + } + + const { emoji, ...option } = selectMenuOption; + return { + ...option, + emoji: typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji, + }; + } + + /** + * Adds options to this select menu + * @param {RestOrArray<APISelectMenuOption>} options The options to add to this select menu + * @returns {StringSelectMenuBuilder} + */ + addOptions(...options) { + return super.addOptions(normalizeArray(options).map(option => StringSelectMenuBuilder.normalizeEmoji(option))); + } + + /** + * Sets the options on this select menu + * @param {RestOrArray<APISelectMenuOption>} options The options to set on this select menu + * @returns {StringSelectMenuBuilder} + */ + setOptions(...options) { + return super.setOptions(normalizeArray(options).map(option => StringSelectMenuBuilder.normalizeEmoji(option))); + } + + /** + * Creates a new select menu builder from json data + * @param {StringSelectMenuBuilder|StringSelectMenuComponent|APIStringSelectComponent} other The other data + * @returns {StringSelectMenuBuilder} + */ + static from(other) { + if (isJSONEncodable(other)) { + return new this(other.toJSON()); + } + return new this(other); + } +} + +module.exports = StringSelectMenuBuilder; + +/** + * @external BuildersSelectMenu + * @see {@link https://discord.js.org/docs/packages/builders/stable/StringSelectMenuBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/StringSelectMenuComponent.js b/node_modules/discord.js/src/structures/StringSelectMenuComponent.js new file mode 100644 index 0000000..e008ae5 --- /dev/null +++ b/node_modules/discord.js/src/structures/StringSelectMenuComponent.js @@ -0,0 +1,20 @@ +'use strict'; + +const BaseSelectMenuComponent = require('./BaseSelectMenuComponent'); + +/** + * Represents a string select menu component + * @extends {BaseSelectMenuComponent} + */ +class StringSelectMenuComponent extends BaseSelectMenuComponent { + /** + * The options in this select menu + * @type {APISelectMenuOption[]} + * @readonly + */ + get options() { + return this.data.options; + } +} + +module.exports = StringSelectMenuComponent; diff --git a/node_modules/discord.js/src/structures/StringSelectMenuInteraction.js b/node_modules/discord.js/src/structures/StringSelectMenuInteraction.js new file mode 100644 index 0000000..1db8c28 --- /dev/null +++ b/node_modules/discord.js/src/structures/StringSelectMenuInteraction.js @@ -0,0 +1,21 @@ +'use strict'; + +const MessageComponentInteraction = require('./MessageComponentInteraction'); + +/** + * Represents a {@link ComponentType.StringSelect} select menu interaction. + * @extends {MessageComponentInteraction} + */ +class StringSelectMenuInteraction extends MessageComponentInteraction { + constructor(client, data) { + super(client, data); + + /** + * The values selected + * @type {string[]} + */ + this.values = data.data.values ?? []; + } +} + +module.exports = StringSelectMenuInteraction; diff --git a/node_modules/discord.js/src/structures/StringSelectMenuOptionBuilder.js b/node_modules/discord.js/src/structures/StringSelectMenuOptionBuilder.js new file mode 100644 index 0000000..cc85750 --- /dev/null +++ b/node_modules/discord.js/src/structures/StringSelectMenuOptionBuilder.js @@ -0,0 +1,49 @@ +'use strict'; + +const { SelectMenuOptionBuilder: BuildersSelectMenuOption } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { toSnakeCase } = require('../util/Transformers'); +const { resolvePartialEmoji } = require('../util/Util'); + +/** + * Represents a select menu option builder. + * @extends {BuildersSelectMenuOption} + */ +class StringSelectMenuOptionBuilder extends BuildersSelectMenuOption { + constructor({ emoji, ...data } = {}) { + super( + toSnakeCase({ + ...data, + emoji: emoji && typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji, + }), + ); + } + + /** + * Sets the emoji to display on this option + * @param {ComponentEmojiResolvable} emoji The emoji to display on this option + * @returns {StringSelectMenuOptionBuilder} + */ + setEmoji(emoji) { + if (typeof emoji === 'string') { + return super.setEmoji(resolvePartialEmoji(emoji)); + } + return super.setEmoji(emoji); + } + + /** + * Creates a new select menu option builder from JSON data + * @param {StringSelectMenuOptionBuilder|APISelectMenuOption} other The other data + * @returns {StringSelectMenuOptionBuilder} + */ + static from(other) { + return new this(isJSONEncodable(other) ? other.toJSON() : other); + } +} + +module.exports = StringSelectMenuOptionBuilder; + +/** + * @external BuildersSelectMenuOption + * @see {@link https://discord.js.org/docs/packages/builders/stable/StringSelectMenuOptionBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/Team.js b/node_modules/discord.js/src/structures/Team.js new file mode 100644 index 0000000..98eb199 --- /dev/null +++ b/node_modules/discord.js/src/structures/Team.js @@ -0,0 +1,117 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const Base = require('./Base'); +const TeamMember = require('./TeamMember'); + +/** + * Represents a Client OAuth2 Application Team. + * @extends {Base} + */ +class Team extends Base { + constructor(client, data) { + super(client); + this._patch(data); + } + + _patch(data) { + /** + * The Team's id + * @type {Snowflake} + */ + this.id = data.id; + + if ('name' in data) { + /** + * The name of the Team + * @type {string} + */ + this.name = data.name; + } + + if ('icon' in data) { + /** + * The Team's icon hash + * @type {?string} + */ + this.icon = data.icon; + } else { + this.icon ??= null; + } + + if ('owner_user_id' in data) { + /** + * The Team's owner id + * @type {?Snowflake} + */ + this.ownerId = data.owner_user_id; + } else { + this.ownerId ??= null; + } + /** + * The Team's members + * @type {Collection<Snowflake, TeamMember>} + */ + this.members = new Collection(); + + for (const memberData of data.members) { + const member = new TeamMember(this, memberData); + this.members.set(member.id, member); + } + } + + /** + * The owner of this team + * @type {?TeamMember} + * @readonly + */ + get owner() { + return this.members.get(this.ownerId) ?? null; + } + + /** + * The timestamp the team was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the team was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * A link to the team's icon. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + iconURL(options = {}) { + return this.icon && this.client.rest.cdn.teamIcon(this.id, this.icon, options); + } + + /** + * When concatenated with a string, this automatically returns the Team's name instead of the + * Team object. + * @returns {string} + * @example + * // Logs: Team name: My Team + * console.log(`Team name: ${team}`); + */ + toString() { + return this.name; + } + + toJSON() { + return super.toJSON({ createdTimestamp: true }); + } +} + +module.exports = Team; diff --git a/node_modules/discord.js/src/structures/TeamMember.js b/node_modules/discord.js/src/structures/TeamMember.js new file mode 100644 index 0000000..9270418 --- /dev/null +++ b/node_modules/discord.js/src/structures/TeamMember.js @@ -0,0 +1,70 @@ +'use strict'; + +const Base = require('./Base'); + +/** + * Represents a Client OAuth2 Application Team Member. + * @extends {Base} + */ +class TeamMember extends Base { + constructor(team, data) { + super(team.client); + + /** + * The Team this member is part of + * @type {Team} + */ + this.team = team; + + this._patch(data); + } + + _patch(data) { + if ('permissions' in data) { + /** + * The permissions this Team Member has with regard to the team + * @type {string[]} + */ + this.permissions = data.permissions; + } + + if ('membership_state' in data) { + /** + * The permissions this Team Member has with regard to the team + * @type {TeamMemberMembershipState} + */ + this.membershipState = data.membership_state; + } + + if ('user' in data) { + /** + * The user for this Team Member + * @type {User} + */ + this.user = this.client.users._add(data.user); + } + } + + /** + * The Team Member's id + * @type {Snowflake} + * @readonly + */ + get id() { + return this.user.id; + } + + /** + * When concatenated with a string, this automatically returns the team member's mention instead of the + * TeamMember object. + * @returns {string} + * @example + * // Logs: Team Member's mention: <@123456789012345678> + * console.log(`Team Member's mention: ${teamMember}`); + */ + toString() { + return this.user.toString(); + } +} + +module.exports = TeamMember; diff --git a/node_modules/discord.js/src/structures/TextChannel.js b/node_modules/discord.js/src/structures/TextChannel.js new file mode 100644 index 0000000..66cc8c4 --- /dev/null +++ b/node_modules/discord.js/src/structures/TextChannel.js @@ -0,0 +1,33 @@ +'use strict'; + +const BaseGuildTextChannel = require('./BaseGuildTextChannel'); + +/** + * Represents a guild text channel on Discord. + * @extends {BaseGuildTextChannel} + */ +class TextChannel extends BaseGuildTextChannel { + _patch(data) { + super._patch(data); + + if ('rate_limit_per_user' in data) { + /** + * The rate limit per user (slowmode) for this channel in seconds + * @type {number} + */ + this.rateLimitPerUser = data.rate_limit_per_user; + } + } + + /** + * Sets the rate limit per user (slowmode) for this channel. + * @param {number} rateLimitPerUser The new rate limit in seconds + * @param {string} [reason] Reason for changing the channel's rate limit + * @returns {Promise<TextChannel>} + */ + setRateLimitPerUser(rateLimitPerUser, reason) { + return this.edit({ rateLimitPerUser, reason }); + } +} + +module.exports = TextChannel; diff --git a/node_modules/discord.js/src/structures/TextInputBuilder.js b/node_modules/discord.js/src/structures/TextInputBuilder.js new file mode 100644 index 0000000..9382154 --- /dev/null +++ b/node_modules/discord.js/src/structures/TextInputBuilder.js @@ -0,0 +1,31 @@ +'use strict'; + +const { TextInputBuilder: BuildersTextInput } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { toSnakeCase } = require('../util/Transformers'); + +/** + * Represents a text input builder. + * @extends {BuildersTextInput} + */ +class TextInputBuilder extends BuildersTextInput { + constructor(data) { + super(toSnakeCase(data)); + } + + /** + * Creates a new text input builder from JSON data + * @param {TextInputBuilder|TextInputComponent|APITextInputComponent} other The other data + * @returns {TextInputBuilder} + */ + static from(other) { + return new this(isJSONEncodable(other) ? other.toJSON() : other); + } +} + +module.exports = TextInputBuilder; + +/** + * @external BuildersTextInput + * @see {@link https://discord.js.org/docs/packages/builders/stable/TextInputBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/TextInputComponent.js b/node_modules/discord.js/src/structures/TextInputComponent.js new file mode 100644 index 0000000..3cc3115 --- /dev/null +++ b/node_modules/discord.js/src/structures/TextInputComponent.js @@ -0,0 +1,29 @@ +'use strict'; + +const Component = require('./Component'); + +/** + * Represents a text input component. + * @extends {Component} + */ +class TextInputComponent extends Component { + /** + * The custom id of this text input + * @type {string} + * @readonly + */ + get customId() { + return this.data.custom_id; + } + + /** + * The value for this text input + * @type {string} + * @readonly + */ + get value() { + return this.data.value; + } +} + +module.exports = TextInputComponent; diff --git a/node_modules/discord.js/src/structures/ThreadChannel.js b/node_modules/discord.js/src/structures/ThreadChannel.js new file mode 100644 index 0000000..96b4087 --- /dev/null +++ b/node_modules/discord.js/src/structures/ThreadChannel.js @@ -0,0 +1,606 @@ +'use strict'; + +const { ChannelType, PermissionFlagsBits, Routes, ChannelFlags } = require('discord-api-types/v10'); +const { BaseChannel } = require('./BaseChannel'); +const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const { DiscordjsRangeError, ErrorCodes } = require('../errors'); +const GuildMessageManager = require('../managers/GuildMessageManager'); +const ThreadMemberManager = require('../managers/ThreadMemberManager'); +const ChannelFlagsBitField = require('../util/ChannelFlagsBitField'); + +/** + * Represents a thread channel on Discord. + * @extends {BaseChannel} + * @implements {TextBasedChannel} + */ +class ThreadChannel extends BaseChannel { + constructor(guild, data, client) { + super(guild?.client ?? client, data, false); + + /** + * The guild the thread is in + * @type {Guild} + */ + this.guild = guild; + + /** + * The id of the guild the channel is in + * @type {Snowflake} + */ + this.guildId = guild?.id ?? data.guild_id; + + /** + * A manager of the messages sent to this thread + * @type {GuildMessageManager} + */ + this.messages = new GuildMessageManager(this); + + /** + * A manager of the members that are part of this thread + * @type {ThreadMemberManager} + */ + this.members = new ThreadMemberManager(this); + if (data) this._patch(data); + } + + _patch(data) { + super._patch(data); + + if ('message' in data) this.messages._add(data.message); + + if ('name' in data) { + /** + * The name of the thread + * @type {string} + */ + this.name = data.name; + } + + if ('guild_id' in data) { + this.guildId = data.guild_id; + } + + if ('parent_id' in data) { + /** + * The id of the parent channel of this thread + * @type {?Snowflake} + */ + this.parentId = data.parent_id; + } else { + this.parentId ??= null; + } + + if ('thread_metadata' in data) { + /** + * Whether the thread is locked + * @type {?boolean} + */ + this.locked = data.thread_metadata.locked ?? false; + + /** + * Whether members without the {@link PermissionFlagsBits.ManageThreads} permission + * can invite other members to this thread. + * <info>This property is always `null` in public threads.</info> + * @type {?boolean} + */ + this.invitable = this.type === ChannelType.PrivateThread ? data.thread_metadata.invitable ?? false : null; + + /** + * Whether the thread is archived + * @type {?boolean} + */ + this.archived = data.thread_metadata.archived; + + /** + * The amount of time (in minutes) after which the thread will automatically archive in case of no recent activity + * @type {?ThreadAutoArchiveDuration} + */ + this.autoArchiveDuration = data.thread_metadata.auto_archive_duration; + + /** + * The timestamp when the thread's archive status was last changed + * <info>If the thread was never archived or unarchived, this is the timestamp at which the thread was + * created</info> + * @type {?number} + */ + this.archiveTimestamp = Date.parse(data.thread_metadata.archive_timestamp); + + if ('create_timestamp' in data.thread_metadata) { + // Note: this is needed because we can't assign directly to getters + this._createdTimestamp = Date.parse(data.thread_metadata.create_timestamp); + } + } else { + this.locked ??= null; + this.archived ??= null; + this.autoArchiveDuration ??= null; + this.archiveTimestamp ??= null; + this.invitable ??= null; + } + + this._createdTimestamp ??= this.type === ChannelType.PrivateThread ? super.createdTimestamp : null; + + if ('owner_id' in data) { + /** + * The id of the member who created this thread + * @type {?Snowflake} + */ + this.ownerId = data.owner_id; + } else { + this.ownerId ??= null; + } + + if ('last_message_id' in data) { + /** + * The last message id sent in this thread, if one was sent + * @type {?Snowflake} + */ + this.lastMessageId = data.last_message_id; + } else { + this.lastMessageId ??= null; + } + + if ('last_pin_timestamp' in data) { + /** + * The timestamp when the last pinned message was pinned, if there was one + * @type {?number} + */ + this.lastPinTimestamp = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null; + } else { + this.lastPinTimestamp ??= null; + } + + if ('rate_limit_per_user' in data) { + /** + * The rate limit per user (slowmode) for this thread in seconds + * @type {?number} + */ + this.rateLimitPerUser = data.rate_limit_per_user ?? 0; + } else { + this.rateLimitPerUser ??= null; + } + + if ('message_count' in data) { + /** + * The approximate count of messages in this thread + * <info>Threads created before July 1, 2022 may have an inaccurate count. + * If you need an approximate value higher than that, use `ThreadChannel#messages.cache.size`</info> + * @type {?number} + */ + this.messageCount = data.message_count; + } else { + this.messageCount ??= null; + } + + if ('member_count' in data) { + /** + * The approximate count of users in this thread + * <info>This stops counting at 50. If you need an approximate value higher than that, use + * `ThreadChannel#members.cache.size`</info> + * @type {?number} + */ + this.memberCount = data.member_count; + } else { + this.memberCount ??= null; + } + + if ('total_message_sent' in data) { + /** + * The number of messages ever sent in a thread, similar to {@link ThreadChannel#messageCount} except it + * will not decrement whenever a message is deleted + * @type {?number} + */ + this.totalMessageSent = data.total_message_sent; + } else { + this.totalMessageSent ??= null; + } + + if (data.member && this.client.user) this.members._add({ user_id: this.client.user.id, ...data.member }); + if (data.messages) for (const message of data.messages) this.messages._add(message); + + if ('applied_tags' in data) { + /** + * The tags applied to this thread + * @type {Snowflake[]} + */ + this.appliedTags = data.applied_tags; + } else { + this.appliedTags ??= []; + } + } + + /** + * The timestamp when this thread was created. This isn't available for threads + * created before 2022-01-09 + * @type {?number} + * @readonly + */ + get createdTimestamp() { + return this._createdTimestamp; + } + + /** + * A collection of associated guild member objects of this thread's members + * @type {Collection<Snowflake, GuildMember>} + * @readonly + */ + get guildMembers() { + return this.members.cache.mapValues(member => member.guildMember); + } + + /** + * The time at which this thread's archive status was last changed + * <info>If the thread was never archived or unarchived, this is the time at which the thread was created</info> + * @type {?Date} + * @readonly + */ + get archivedAt() { + return this.archiveTimestamp && new Date(this.archiveTimestamp); + } + + /** + * The time the thread was created at + * @type {?Date} + * @readonly + */ + get createdAt() { + return this.createdTimestamp && new Date(this.createdTimestamp); + } + + /** + * The parent channel of this thread + * @type {?(NewsChannel|TextChannel|ForumChannel)} + * @readonly + */ + get parent() { + return this.guild.channels.resolve(this.parentId); + } + + /** + * Makes the client user join the thread. + * @returns {Promise<ThreadChannel>} + */ + async join() { + await this.members.add('@me'); + return this; + } + + /** + * Makes the client user leave the thread. + * @returns {Promise<ThreadChannel>} + */ + async leave() { + await this.members.remove('@me'); + return this; + } + + /** + * Gets the overall set of permissions for a member or role in this thread's parent channel, taking overwrites into + * account. + * @param {GuildMemberResolvable|RoleResolvable} memberOrRole The member or role to obtain the overall permissions for + * @param {boolean} [checkAdmin=true] Whether having the {@link PermissionFlagsBits.Administrator} permission + * will return all permissions + * @returns {?Readonly<PermissionsBitField>} + */ + permissionsFor(memberOrRole, checkAdmin) { + return this.parent?.permissionsFor(memberOrRole, checkAdmin) ?? null; + } + + /** + * Fetches the owner of this thread. If the thread member object isn't needed, + * use {@link ThreadChannel#ownerId} instead. + * @param {BaseFetchOptions} [options] The options for fetching the member + * @returns {Promise<?ThreadMember>} + */ + async fetchOwner({ cache = true, force = false } = {}) { + if (!force) { + const existing = this.members.cache.get(this.ownerId); + if (existing) return existing; + } + + // We cannot fetch a single thread member, as of this commit's date, Discord API responds with 405 + const members = await this.members.fetch({ cache }); + return members.get(this.ownerId) ?? null; + } + + /** + * Fetches the message that started this thread, if any. + * <info>The `Promise` will reject if the original message in a forum post is deleted + * or when the original message in the parent channel is deleted. + * If you just need the id of that message, use {@link ThreadChannel#id} instead.</info> + * @param {BaseFetchOptions} [options] Additional options for this fetch + * @returns {Promise<Message<true>|null>} + */ + // eslint-disable-next-line require-await + async fetchStarterMessage(options) { + const channel = this.parent?.type === ChannelType.GuildForum ? this : this.parent; + return channel?.messages.fetch({ message: this.id, ...options }) ?? null; + } + + /** + * The options used to edit a thread channel + * @typedef {Object} ThreadEditOptions + * @property {string} [name] The new name for the thread + * @property {boolean} [archived] Whether the thread is archived + * @property {ThreadAutoArchiveDuration} [autoArchiveDuration] The amount of time after which the thread + * should automatically archive in case of no recent activity + * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the thread in seconds + * @property {boolean} [locked] Whether the thread is locked + * @property {boolean} [invitable] Whether non-moderators can add other non-moderators to a thread + * <info>Can only be edited on {@link ChannelType.PrivateThread}</info> + * @property {Snowflake[]} [appliedTags] The tags to apply to the thread + * @property {ChannelFlagsResolvable} [flags] The flags to set on the channel + * @property {string} [reason] Reason for editing the thread + */ + + /** + * Edits this thread. + * @param {ThreadEditOptions} options The options to provide + * @returns {Promise<ThreadChannel>} + * @example + * // Edit a thread + * thread.edit({ name: 'new-thread' }) + * .then(editedThread => console.log(editedThread)) + * .catch(console.error); + */ + async edit(options) { + const newData = await this.client.rest.patch(Routes.channel(this.id), { + body: { + name: (options.name ?? this.name).trim(), + archived: options.archived, + auto_archive_duration: options.autoArchiveDuration, + rate_limit_per_user: options.rateLimitPerUser, + locked: options.locked, + invitable: this.type === ChannelType.PrivateThread ? options.invitable : undefined, + applied_tags: options.appliedTags, + flags: 'flags' in options ? ChannelFlagsBitField.resolve(options.flags) : undefined, + }, + reason: options.reason, + }); + + return this.client.actions.ChannelUpdate.handle(newData).updated; + } + + /** + * Sets whether the thread is archived. + * @param {boolean} [archived=true] Whether the thread is archived + * @param {string} [reason] Reason for archiving or unarchiving + * @returns {Promise<ThreadChannel>} + * @example + * // Archive the thread + * thread.setArchived(true) + * .then(newThread => console.log(`Thread is now ${newThread.archived ? 'archived' : 'active'}`)) + * .catch(console.error); + */ + setArchived(archived = true, reason) { + return this.edit({ archived, reason }); + } + + /** + * Sets the duration after which the thread will automatically archive in case of no recent activity. + * @param {ThreadAutoArchiveDuration} autoArchiveDuration The amount of time after which the thread + * should automatically archive in case of no recent activity + * @param {string} [reason] Reason for changing the auto archive duration + * @returns {Promise<ThreadChannel>} + * @example + * // Set the thread's auto archive time to 1 hour + * thread.setAutoArchiveDuration(ThreadAutoArchiveDuration.OneHour) + * .then(newThread => { + * console.log(`Thread will now archive after ${newThread.autoArchiveDuration} minutes of inactivity`); + * }); + * .catch(console.error); + */ + setAutoArchiveDuration(autoArchiveDuration, reason) { + return this.edit({ autoArchiveDuration, reason }); + } + + /** + * Sets whether members without the {@link PermissionFlagsBits.ManageThreads} permission + * can invite other members to this thread. + * @param {boolean} [invitable=true] Whether non-moderators can invite non-moderators to this thread + * @param {string} [reason] Reason for changing invite + * @returns {Promise<ThreadChannel>} + */ + setInvitable(invitable = true, reason) { + if (this.type !== ChannelType.PrivateThread) { + return Promise.reject(new DiscordjsRangeError(ErrorCodes.ThreadInvitableType, this.type)); + } + return this.edit({ invitable, reason }); + } + + /** + * Sets whether the thread can be **unarchived** by anyone with the + * {@link PermissionFlagsBits.SendMessages} permission. When a thread is locked, only members with the + * {@link PermissionFlagsBits.ManageThreads} permission can unarchive it. + * @param {boolean} [locked=true] Whether the thread is locked + * @param {string} [reason] Reason for locking or unlocking the thread + * @returns {Promise<ThreadChannel>} + * @example + * // Set the thread to locked + * thread.setLocked(true) + * .then(newThread => console.log(`Thread is now ${newThread.locked ? 'locked' : 'unlocked'}`)) + * .catch(console.error); + */ + setLocked(locked = true, reason) { + return this.edit({ locked, reason }); + } + + /** + * Sets a new name for this thread. + * @param {string} name The new name for the thread + * @param {string} [reason] Reason for changing the thread's name + * @returns {Promise<ThreadChannel>} + * @example + * // Change the thread's name + * thread.setName('not_general') + * .then(newThread => console.log(`Thread's new name is ${newThread.name}`)) + * .catch(console.error); + */ + setName(name, reason) { + return this.edit({ name, reason }); + } + + /** + * Sets the rate limit per user (slowmode) for this thread. + * @param {number} rateLimitPerUser The new rate limit in seconds + * @param {string} [reason] Reason for changing the thread's rate limit + * @returns {Promise<ThreadChannel>} + */ + setRateLimitPerUser(rateLimitPerUser, reason) { + return this.edit({ rateLimitPerUser, reason }); + } + + /** + * Set the applied tags for this channel (only applicable to forum threads) + * @param {Snowflake[]} appliedTags The tags to set for this channel + * @param {string} [reason] Reason for changing the thread's applied tags + * @returns {Promise<ThreadChannel>} + */ + setAppliedTags(appliedTags, reason) { + return this.edit({ appliedTags, reason }); + } + + /** + * Pins this thread from the forum channel (only applicable to forum threads). + * @param {string} [reason] Reason for pinning + * @returns {Promise<ThreadChannel>} + */ + pin(reason) { + return this.edit({ flags: this.flags.add(ChannelFlags.Pinned), reason }); + } + + /** + * Unpins this thread from the forum channel (only applicable to forum threads). + * @param {string} [reason] Reason for unpinning + * @returns {Promise<ThreadChannel>} + */ + unpin(reason) { + return this.edit({ flags: this.flags.remove(ChannelFlags.Pinned), reason }); + } + + /** + * Whether the client user is a member of the thread. + * @type {boolean} + * @readonly + */ + get joined() { + return this.members.cache.has(this.client.user?.id); + } + + /** + * Whether the thread is editable by the client user (name, archived, autoArchiveDuration) + * @type {boolean} + * @readonly + */ + get editable() { + return ( + (this.ownerId === this.client.user.id && (this.type !== ChannelType.PrivateThread || this.joined)) || + this.manageable + ); + } + + /** + * Whether the thread is joinable by the client user + * @type {boolean} + * @readonly + */ + get joinable() { + return ( + !this.archived && + !this.joined && + this.permissionsFor(this.client.user)?.has( + this.type === ChannelType.PrivateThread ? PermissionFlagsBits.ManageThreads : PermissionFlagsBits.ViewChannel, + false, + ) + ); + } + + /** + * Whether the thread is manageable by the client user, for deleting or editing rateLimitPerUser or locked. + * @type {boolean} + * @readonly + */ + get manageable() { + const permissions = this.permissionsFor(this.client.user); + if (!permissions) return false; + // This flag allows managing even if timed out + if (permissions.has(PermissionFlagsBits.Administrator, false)) return true; + + return ( + this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() && + permissions.has(PermissionFlagsBits.ManageThreads, false) + ); + } + + /** + * Whether the thread is viewable by the client user + * @type {boolean} + * @readonly + */ + get viewable() { + if (this.client.user.id === this.guild.ownerId) return true; + const permissions = this.permissionsFor(this.client.user); + if (!permissions) return false; + return permissions.has(PermissionFlagsBits.ViewChannel, false); + } + + /** + * Whether the client user can send messages in this thread + * @type {boolean} + * @readonly + */ + get sendable() { + const permissions = this.permissionsFor(this.client.user); + if (!permissions) return false; + // This flag allows sending even if timed out + if (permissions.has(PermissionFlagsBits.Administrator, false)) return true; + + return ( + !(this.archived && this.locked && !this.manageable) && + (this.type !== ChannelType.PrivateThread || this.joined || this.manageable) && + permissions.has(PermissionFlagsBits.SendMessagesInThreads, false) && + this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() + ); + } + + /** + * Whether the thread is unarchivable by the client user + * @type {boolean} + * @readonly + */ + get unarchivable() { + return this.archived && this.sendable && (!this.locked || this.manageable); + } + + /** + * Deletes this thread. + * @param {string} [reason] Reason for deleting this thread + * @returns {Promise<ThreadChannel>} + * @example + * // Delete the thread + * thread.delete('cleaning out old threads') + * .then(deletedThread => console.log(deletedThread)) + * .catch(console.error); + */ + async delete(reason) { + await this.guild.channels.delete(this.id, reason); + return this; + } + + // These are here only for documentation purposes - they are implemented by TextBasedChannel + /* eslint-disable no-empty-function */ + get lastMessage() {} + get lastPinAt() {} + send() {} + sendTyping() {} + createMessageCollector() {} + awaitMessages() {} + createMessageComponentCollector() {} + awaitMessageComponent() {} + bulkDelete() {} + // Doesn't work on Thread channels; setRateLimitPerUser() {} + // Doesn't work on Thread channels; setNSFW() {} +} + +TextBasedChannel.applyToClass(ThreadChannel, true, ['fetchWebhooks', 'setRateLimitPerUser', 'setNSFW']); + +module.exports = ThreadChannel; diff --git a/node_modules/discord.js/src/structures/ThreadMember.js b/node_modules/discord.js/src/structures/ThreadMember.js new file mode 100644 index 0000000..fc79dd0 --- /dev/null +++ b/node_modules/discord.js/src/structures/ThreadMember.js @@ -0,0 +1,113 @@ +'use strict'; + +const Base = require('./Base'); +const ThreadMemberFlagsBitField = require('../util/ThreadMemberFlagsBitField'); + +/** + * Represents a Member for a Thread. + * @extends {Base} + */ +class ThreadMember extends Base { + constructor(thread, data, extra = {}) { + super(thread.client); + + /** + * The thread that this member is a part of + * @type {ThreadChannel} + */ + this.thread = thread; + + /** + * The timestamp the member last joined the thread at + * @type {?number} + */ + this.joinedTimestamp = null; + + /** + * The flags for this thread member. This will be `null` if partial. + * @type {?ThreadMemberFlagsBitField} + */ + this.flags = null; + + /** + * The id of the thread member + * @type {Snowflake} + */ + this.id = data.user_id; + + this._patch(data, extra); + } + + _patch(data, extra = {}) { + if ('join_timestamp' in data) this.joinedTimestamp = Date.parse(data.join_timestamp); + if ('flags' in data) this.flags = new ThreadMemberFlagsBitField(data.flags).freeze(); + + if ('member' in data) { + /** + * The guild member associated with this thread member. + * @type {?GuildMember} + * @private + */ + this.member = this.thread.guild.members._add(data.member, extra.cache); + } else { + this.member ??= null; + } + } + + /** + * Whether this thread member is a partial + * @type {boolean} + * @readonly + */ + get partial() { + return this.flags === null; + } + + /** + * The guild member associated with this thread member + * @type {?GuildMember} + * @readonly + */ + get guildMember() { + return this.member ?? this.thread.guild.members.resolve(this.id); + } + + /** + * The last time this member joined the thread + * @type {?Date} + * @readonly + */ + get joinedAt() { + return this.joinedTimestamp && new Date(this.joinedTimestamp); + } + + /** + * The user associated with this thread member + * @type {?User} + * @readonly + */ + get user() { + return this.client.users.resolve(this.id); + } + + /** + * Whether the client user can manage this thread member + * @type {boolean} + * @readonly + */ + get manageable() { + return !this.thread.archived && this.thread.editable; + } + + /** + * Removes this member from the thread. + * @param {string} [reason] Reason for removing the member + * @returns {ThreadMember} + */ + async remove(reason) { + await this.thread.members.remove(this.id, reason); + return this; + } +} + +module.exports = ThreadMember; diff --git a/node_modules/discord.js/src/structures/Typing.js b/node_modules/discord.js/src/structures/Typing.js new file mode 100644 index 0000000..341d7ca --- /dev/null +++ b/node_modules/discord.js/src/structures/Typing.js @@ -0,0 +1,74 @@ +'use strict'; + +const Base = require('./Base'); + +/** + * Represents a typing state for a user in a channel. + * @extends {Base} + */ +class Typing extends Base { + constructor(channel, user, data) { + super(channel.client); + + /** + * The channel the status is from + * @type {TextBasedChannels} + */ + this.channel = channel; + + /** + * The user who is typing + * @type {User} + */ + this.user = user; + + this._patch(data); + } + + _patch(data) { + if ('timestamp' in data) { + /** + * The UNIX timestamp in milliseconds the user started typing at + * @type {number} + */ + this.startedTimestamp = data.timestamp * 1_000; + } + } + + /** + * Indicates whether the status is received from a guild. + * @returns {boolean} + */ + inGuild() { + return this.guild !== null; + } + + /** + * The time the user started typing at + * @type {Date} + * @readonly + */ + get startedAt() { + return new Date(this.startedTimestamp); + } + + /** + * The guild the status is from + * @type {?Guild} + * @readonly + */ + get guild() { + return this.channel.guild ?? null; + } + + /** + * The member who is typing + * @type {?GuildMember} + * @readonly + */ + get member() { + return this.guild?.members.resolve(this.user) ?? null; + } +} + +module.exports = Typing; diff --git a/node_modules/discord.js/src/structures/User.js b/node_modules/discord.js/src/structures/User.js new file mode 100644 index 0000000..4e38d2d --- /dev/null +++ b/node_modules/discord.js/src/structures/User.js @@ -0,0 +1,380 @@ +'use strict'; + +const { userMention } = require('@discordjs/builders'); +const { calculateUserDefaultAvatarIndex } = require('@discordjs/rest'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const Base = require('./Base'); +const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const UserFlagsBitField = require('../util/UserFlagsBitField'); + +/** + * Represents a user on Discord. + * @implements {TextBasedChannel} + * @extends {Base} + */ +class User extends Base { + constructor(client, data) { + super(client); + + /** + * The user's id + * @type {Snowflake} + */ + this.id = data.id; + + this.bot = null; + + this.system = null; + + this.flags = null; + + this._patch(data); + } + + _patch(data) { + if ('username' in data) { + /** + * The username of the user + * @type {?string} + */ + this.username = data.username; + } else { + this.username ??= null; + } + + if ('global_name' in data) { + /** + * The global name of this user + * @type {?string} + */ + this.globalName = data.global_name; + } else { + this.globalName ??= null; + } + + if ('bot' in data) { + /** + * Whether or not the user is a bot + * @type {?boolean} + */ + this.bot = Boolean(data.bot); + } else if (!this.partial && typeof this.bot !== 'boolean') { + this.bot = false; + } + + if ('discriminator' in data) { + /** + * The discriminator of this user + * <info>`'0'`, or a 4-digit stringified number if they're using the legacy username system</info> + * @type {?string} + */ + this.discriminator = data.discriminator; + } else { + this.discriminator ??= null; + } + + if ('avatar' in data) { + /** + * The user avatar's hash + * @type {?string} + */ + this.avatar = data.avatar; + } else { + this.avatar ??= null; + } + + if ('banner' in data) { + /** + * The user banner's hash + * <info>The user must be force fetched for this property to be present or be updated</info> + * @type {?string} + */ + this.banner = data.banner; + } else if (this.banner !== null) { + this.banner ??= undefined; + } + + if ('accent_color' in data) { + /** + * The base 10 accent color of the user's banner + * <info>The user must be force fetched for this property to be present or be updated</info> + * @type {?number} + */ + this.accentColor = data.accent_color; + } else if (this.accentColor !== null) { + this.accentColor ??= undefined; + } + + if ('system' in data) { + /** + * Whether the user is an Official Discord System user (part of the urgent message system) + * @type {?boolean} + */ + this.system = Boolean(data.system); + } else if (!this.partial && typeof this.system !== 'boolean') { + this.system = false; + } + + if ('public_flags' in data) { + /** + * The flags for this user + * @type {?UserFlagsBitField} + */ + this.flags = new UserFlagsBitField(data.public_flags); + } + + if ('avatar_decoration' in data) { + /** + * The user avatar decoration's hash + * @type {?string} + */ + this.avatarDecoration = data.avatar_decoration; + } else { + this.avatarDecoration ??= null; + } + } + + /** + * Whether this User is a partial + * @type {boolean} + * @readonly + */ + get partial() { + return typeof this.username !== 'string'; + } + + /** + * The timestamp the user was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the user was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * A link to the user's avatar. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + avatarURL(options = {}) { + return this.avatar && this.client.rest.cdn.avatar(this.id, this.avatar, options); + } + + /** + * A link to the user's avatar decoration. + * @param {BaseImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + avatarDecorationURL(options = {}) { + return this.avatarDecoration && this.client.rest.cdn.avatarDecoration(this.id, this.avatarDecoration, options); + } + + /** + * A link to the user's default avatar + * @type {string} + * @readonly + */ + get defaultAvatarURL() { + const index = this.discriminator === '0' ? calculateUserDefaultAvatarIndex(this.id) : this.discriminator % 5; + return this.client.rest.cdn.defaultAvatar(index); + } + + /** + * A link to the user's avatar if they have one. + * Otherwise a link to their default avatar will be returned. + * @param {ImageURLOptions} [options={}] Options for the Image URL + * @returns {string} + */ + displayAvatarURL(options) { + return this.avatarURL(options) ?? this.defaultAvatarURL; + } + + /** + * The hexadecimal version of the user accent color, with a leading hash + * <info>The user must be force fetched for this property to be present</info> + * @type {?string} + * @readonly + */ + get hexAccentColor() { + if (typeof this.accentColor !== 'number') return this.accentColor; + return `#${this.accentColor.toString(16).padStart(6, '0')}`; + } + + /** + * A link to the user's banner. See {@link User#banner} for more info + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + bannerURL(options = {}) { + return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options); + } + + /** + * The tag of this user + * <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`) + * if they're using the legacy username system</info> + * @type {?string} + * @readonly + */ + get tag() { + return typeof this.username === 'string' + ? this.discriminator === '0' + ? this.username + : `${this.username}#${this.discriminator}` + : null; + } + + /** + * The global name of this user, or their username if they don't have one + * @type {?string} + * @readonly + */ + get displayName() { + return this.globalName ?? this.username; + } + + /** + * The DM between the client's user and this user + * @type {?DMChannel} + * @readonly + */ + get dmChannel() { + return this.client.users.dmChannel(this.id); + } + + /** + * Creates a DM channel between the client and the user. + * @param {boolean} [force=false] Whether to skip the cache check and request the API + * @returns {Promise<DMChannel>} + */ + createDM(force = false) { + return this.client.users.createDM(this.id, { force }); + } + + /** + * Deletes a DM channel (if one exists) between the client and the user. Resolves with the channel if successful. + * @returns {Promise<DMChannel>} + */ + deleteDM() { + return this.client.users.deleteDM(this.id); + } + + /** + * Checks if the user is equal to another. + * It compares id, username, discriminator, avatar, banner, accent color, and bot flags. + * It is recommended to compare equality by using `user.id === user2.id` unless you want to compare all properties. + * @param {User} user User to compare with + * @returns {boolean} + */ + equals(user) { + return ( + user && + this.id === user.id && + this.username === user.username && + this.discriminator === user.discriminator && + this.globalName === user.globalName && + this.avatar === user.avatar && + this.flags?.bitfield === user.flags?.bitfield && + this.banner === user.banner && + this.accentColor === user.accentColor + ); + } + + /** + * Compares the user with an API user object + * @param {APIUser} user The API user object to compare + * @returns {boolean} + * @private + */ + _equals(user) { + return ( + user && + this.id === user.id && + this.username === user.username && + this.discriminator === user.discriminator && + this.globalName === user.global_name && + this.avatar === user.avatar && + this.flags?.bitfield === user.public_flags && + ('banner' in user ? this.banner === user.banner : true) && + ('accent_color' in user ? this.accentColor === user.accent_color : true) + ); + } + + /** + * Fetches this user's flags. + * @param {boolean} [force=false] Whether to skip the cache check and request the API + * @returns {Promise<UserFlagsBitField>} + */ + fetchFlags(force = false) { + return this.client.users.fetchFlags(this.id, { force }); + } + + /** + * Fetches this user. + * @param {boolean} [force=true] Whether to skip the cache check and request the API + * @returns {Promise<User>} + */ + fetch(force = true) { + return this.client.users.fetch(this.id, { force }); + } + + /** + * When concatenated with a string, this automatically returns the user's mention instead of the User object. + * @returns {string} + * @example + * // Logs: Hello from <@123456789012345678>! + * console.log(`Hello from ${user}!`); + */ + toString() { + return userMention(this.id); + } + + toJSON(...props) { + const json = super.toJSON( + { + createdTimestamp: true, + defaultAvatarURL: true, + hexAccentColor: true, + tag: true, + }, + ...props, + ); + json.avatarURL = this.avatarURL(); + json.displayAvatarURL = this.displayAvatarURL(); + json.bannerURL = this.banner ? this.bannerURL() : this.banner; + return json; + } +} + +/** + * Sends a message to this user. + * @method send + * @memberof User + * @instance + * @param {string|MessagePayload|MessageCreateOptions} options The options to provide + * @returns {Promise<Message>} + * @example + * // Send a direct message + * user.send('Hello!') + * .then(message => console.log(`Sent message: ${message.content} to ${user.tag}`)) + * .catch(console.error); + */ + +TextBasedChannel.applyToClass(User); + +module.exports = User; + +/** + * @external APIUser + * @see {@link https://discord.com/developers/docs/resources/user#user-object} + */ diff --git a/node_modules/discord.js/src/structures/UserContextMenuCommandInteraction.js b/node_modules/discord.js/src/structures/UserContextMenuCommandInteraction.js new file mode 100644 index 0000000..2e9dc7c --- /dev/null +++ b/node_modules/discord.js/src/structures/UserContextMenuCommandInteraction.js @@ -0,0 +1,29 @@ +'use strict'; + +const ContextMenuCommandInteraction = require('./ContextMenuCommandInteraction'); + +/** + * Represents a user context menu interaction. + * @extends {ContextMenuCommandInteraction} + */ +class UserContextMenuCommandInteraction extends ContextMenuCommandInteraction { + /** + * The target user from this interaction + * @type {User} + * @readonly + */ + get targetUser() { + return this.options.getUser('user'); + } + + /** + * The target member from this interaction + * @type {?(GuildMember|APIGuildMember)} + * @readonly + */ + get targetMember() { + return this.options.getMember('user'); + } +} + +module.exports = UserContextMenuCommandInteraction; diff --git a/node_modules/discord.js/src/structures/UserSelectMenuBuilder.js b/node_modules/discord.js/src/structures/UserSelectMenuBuilder.js new file mode 100644 index 0000000..61bdbb8 --- /dev/null +++ b/node_modules/discord.js/src/structures/UserSelectMenuBuilder.js @@ -0,0 +1,31 @@ +'use strict'; + +const { UserSelectMenuBuilder: BuildersUserSelectMenu } = require('@discordjs/builders'); +const { isJSONEncodable } = require('@discordjs/util'); +const { toSnakeCase } = require('../util/Transformers'); + +/** + * Class used to build select menu components to be sent through the API + * @extends {BuildersUserSelectMenu} + */ +class UserSelectMenuBuilder extends BuildersUserSelectMenu { + constructor(data = {}) { + super(toSnakeCase(data)); + } + + /** + * Creates a new select menu builder from JSON data + * @param {UserSelectMenuBuilder|UserSelectMenuComponent|APIUserSelectComponent} other The other data + * @returns {UserSelectMenuBuilder} + */ + static from(other) { + return new this(isJSONEncodable(other) ? other.toJSON() : other); + } +} + +module.exports = UserSelectMenuBuilder; + +/** + * @external BuildersUserSelectMenu + * @see {@link https://discord.js.org/docs/packages/builders/stable/UserSelectMenuBuilder:Class} + */ diff --git a/node_modules/discord.js/src/structures/UserSelectMenuComponent.js b/node_modules/discord.js/src/structures/UserSelectMenuComponent.js new file mode 100644 index 0000000..0acacdf --- /dev/null +++ b/node_modules/discord.js/src/structures/UserSelectMenuComponent.js @@ -0,0 +1,11 @@ +'use strict'; + +const BaseSelectMenuComponent = require('./BaseSelectMenuComponent'); + +/** + * Represents a user select menu component + * @extends {BaseSelectMenuComponent} + */ +class UserSelectMenuComponent extends BaseSelectMenuComponent {} + +module.exports = UserSelectMenuComponent; diff --git a/node_modules/discord.js/src/structures/UserSelectMenuInteraction.js b/node_modules/discord.js/src/structures/UserSelectMenuInteraction.js new file mode 100644 index 0000000..5e23239 --- /dev/null +++ b/node_modules/discord.js/src/structures/UserSelectMenuInteraction.js @@ -0,0 +1,51 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const MessageComponentInteraction = require('./MessageComponentInteraction'); +const Events = require('../util/Events'); + +/** + * Represents a {@link ComponentType.UserSelect} select menu interaction. + * @extends {MessageComponentInteraction} + */ +class UserSelectMenuInteraction extends MessageComponentInteraction { + constructor(client, data) { + super(client, data); + const { resolved, values } = data.data; + + /** + * An array of the selected user ids + * @type {Snowflake[]} + */ + this.values = values ?? []; + + /** + * Collection of the selected users + * @type {Collection<Snowflake, User>} + */ + this.users = new Collection(); + + /** + * Collection of the selected members + * @type {Collection<Snowflake, GuildMember|APIGuildMember>} + */ + this.members = new Collection(); + + for (const user of Object.values(resolved?.users ?? {})) { + this.users.set(user.id, this.client.users._add(user)); + } + + for (const [id, member] of Object.entries(resolved?.members ?? {})) { + const user = resolved.users[id]; + + if (!user) { + this.client.emit(Events.Debug, `[UserSelectMenuInteraction] Received a member without a user, skipping ${id}`); + continue; + } + + this.members.set(id, this.guild?.members._add({ user, ...member }) ?? { user, ...member }); + } + } +} + +module.exports = UserSelectMenuInteraction; diff --git a/node_modules/discord.js/src/structures/VoiceChannel.js b/node_modules/discord.js/src/structures/VoiceChannel.js new file mode 100644 index 0000000..d4f33ca --- /dev/null +++ b/node_modules/discord.js/src/structures/VoiceChannel.js @@ -0,0 +1,96 @@ +'use strict'; + +const { PermissionFlagsBits } = require('discord-api-types/v10'); +const BaseGuildVoiceChannel = require('./BaseGuildVoiceChannel'); + +/** + * Represents a guild voice channel on Discord. + * @extends {BaseGuildVoiceChannel} + */ +class VoiceChannel extends BaseGuildVoiceChannel { + /** + * Whether the channel is joinable by the client user + * @type {boolean} + * @readonly + */ + get joinable() { + if (!super.joinable) return false; + if (this.full && !this.permissionsFor(this.client.user).has(PermissionFlagsBits.MoveMembers, false)) return false; + return true; + } + + /** + * Checks if the client has permission to send audio to the voice channel + * @type {boolean} + * @readonly + */ + get speakable() { + const permissions = this.permissionsFor(this.client.user); + if (!permissions) return false; + // This flag allows speaking even if timed out + if (permissions.has(PermissionFlagsBits.Administrator, false)) return true; + + return ( + this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() && + permissions.has(PermissionFlagsBits.Speak, false) + ); + } +} + +/** + * Sets the bitrate of the channel. + * @method setBitrate + * @memberof VoiceChannel + * @instance + * @param {number} bitrate The new bitrate + * @param {string} [reason] Reason for changing the channel's bitrate + * @returns {Promise<VoiceChannel>} + * @example + * // Set the bitrate of a voice channel + * voiceChannel.setBitrate(48_000) + * .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`)) + * .catch(console.error); + */ + +/** + * Sets the RTC region of the channel. + * @method setRTCRegion + * @memberof VoiceChannel + * @instance + * @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel + * @param {string} [reason] The reason for modifying this region. + * @returns {Promise<VoiceChannel>} + * @example + * // Set the RTC region to sydney + * voiceChannel.setRTCRegion('sydney'); + * @example + * // Remove a fixed region for this channel - let Discord decide automatically + * voiceChannel.setRTCRegion(null, 'We want to let Discord decide.'); + */ + +/** + * Sets the user limit of the channel. + * @method setUserLimit + * @memberof VoiceChannel + * @instance + * @param {number} userLimit The new user limit + * @param {string} [reason] Reason for changing the user limit + * @returns {Promise<VoiceChannel>} + * @example + * // Set the user limit of a voice channel + * voiceChannel.setUserLimit(42) + * .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`)) + * .catch(console.error); + */ + +/** + * Sets the camera video quality mode of the channel. + * @method setVideoQualityMode + * @memberof VoiceChannel + * @instance + * @param {VideoQualityMode} videoQualityMode The new camera video quality mode. + * @param {string} [reason] Reason for changing the camera video quality mode. + * @returns {Promise<VoiceChannel>} + */ + +module.exports = VoiceChannel; diff --git a/node_modules/discord.js/src/structures/VoiceRegion.js b/node_modules/discord.js/src/structures/VoiceRegion.js new file mode 100644 index 0000000..1f5652a --- /dev/null +++ b/node_modules/discord.js/src/structures/VoiceRegion.js @@ -0,0 +1,46 @@ +'use strict'; + +const { flatten } = require('../util/Util'); + +/** + * Represents a Discord voice region for guilds. + */ +class VoiceRegion { + constructor(data) { + /** + * The region's id + * @type {string} + */ + this.id = data.id; + + /** + * Name of the region + * @type {string} + */ + this.name = data.name; + + /** + * Whether the region is deprecated + * @type {boolean} + */ + this.deprecated = data.deprecated; + + /** + * Whether the region is optimal + * @type {boolean} + */ + this.optimal = data.optimal; + + /** + * Whether the region is custom + * @type {boolean} + */ + this.custom = data.custom; + } + + toJSON() { + return flatten(this); + } +} + +module.exports = VoiceRegion; diff --git a/node_modules/discord.js/src/structures/VoiceState.js b/node_modules/discord.js/src/structures/VoiceState.js new file mode 100644 index 0000000..ae510f2 --- /dev/null +++ b/node_modules/discord.js/src/structures/VoiceState.js @@ -0,0 +1,303 @@ +'use strict'; + +const { ChannelType, Routes } = require('discord-api-types/v10'); +const Base = require('./Base'); +const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * Represents the voice state for a Guild Member. + * @extends {Base} + */ +class VoiceState extends Base { + constructor(guild, data) { + super(guild.client); + /** + * The guild of this voice state + * @type {Guild} + */ + this.guild = guild; + /** + * The id of the member of this voice state + * @type {Snowflake} + */ + this.id = data.user_id; + this._patch(data); + } + + _patch(data) { + if ('deaf' in data) { + /** + * Whether this member is deafened server-wide + * @type {?boolean} + */ + this.serverDeaf = data.deaf; + } else { + this.serverDeaf ??= null; + } + + if ('mute' in data) { + /** + * Whether this member is muted server-wide + * @type {?boolean} + */ + this.serverMute = data.mute; + } else { + this.serverMute ??= null; + } + + if ('self_deaf' in data) { + /** + * Whether this member is self-deafened + * @type {?boolean} + */ + this.selfDeaf = data.self_deaf; + } else { + this.selfDeaf ??= null; + } + + if ('self_mute' in data) { + /** + * Whether this member is self-muted + * @type {?boolean} + */ + this.selfMute = data.self_mute; + } else { + this.selfMute ??= null; + } + + if ('self_video' in data) { + /** + * Whether this member's camera is enabled + * @type {?boolean} + */ + this.selfVideo = data.self_video; + } else { + this.selfVideo ??= null; + } + + if ('session_id' in data) { + /** + * The session id for this member's connection + * @type {?string} + */ + this.sessionId = data.session_id; + } else { + this.sessionId ??= null; + } + + // The self_stream is property is omitted if false, check for another property + // here to avoid incorrectly clearing this when partial data is specified + if ('self_video' in data) { + /** + * Whether this member is streaming using "Screen Share" + * @type {?boolean} + */ + this.streaming = data.self_stream ?? false; + } else { + this.streaming ??= null; + } + + if ('channel_id' in data) { + /** + * The {@link VoiceChannel} or {@link StageChannel} id the member is in + * @type {?Snowflake} + */ + this.channelId = data.channel_id; + } else { + this.channelId ??= null; + } + + if ('suppress' in data) { + /** + * Whether this member is suppressed from speaking. This property is specific to stage channels only. + * @type {?boolean} + */ + this.suppress = data.suppress; + } else { + this.suppress ??= null; + } + + if ('request_to_speak_timestamp' in data) { + /** + * The time at which the member requested to speak. This property is specific to stage channels only. + * @type {?number} + */ + this.requestToSpeakTimestamp = data.request_to_speak_timestamp && Date.parse(data.request_to_speak_timestamp); + } else { + this.requestToSpeakTimestamp ??= null; + } + + return this; + } + + /** + * The member that this voice state belongs to + * @type {?GuildMember} + * @readonly + */ + get member() { + return this.guild.members.cache.get(this.id) ?? null; + } + + /** + * The channel that the member is connected to + * @type {?(VoiceChannel|StageChannel)} + * @readonly + */ + get channel() { + return this.guild.channels.cache.get(this.channelId) ?? null; + } + + /** + * Whether this member is either self-deafened or server-deafened + * @type {?boolean} + * @readonly + */ + get deaf() { + return this.serverDeaf || this.selfDeaf; + } + + /** + * Whether this member is either self-muted or server-muted + * @type {?boolean} + * @readonly + */ + get mute() { + return this.serverMute || this.selfMute; + } + + /** + * Mutes/unmutes the member of this voice state. + * @param {boolean} [mute=true] Whether or not the member should be muted + * @param {string} [reason] Reason for muting or unmuting + * @returns {Promise<GuildMember>} + */ + setMute(mute = true, reason) { + return this.guild.members.edit(this.id, { mute, reason }); + } + + /** + * Deafens/undeafens the member of this voice state. + * @param {boolean} [deaf=true] Whether or not the member should be deafened + * @param {string} [reason] Reason for deafening or undeafening + * @returns {Promise<GuildMember>} + */ + setDeaf(deaf = true, reason) { + return this.guild.members.edit(this.id, { deaf, reason }); + } + + /** + * Disconnects the member from the channel. + * @param {string} [reason] Reason for disconnecting the member from the channel + * @returns {Promise<GuildMember>} + */ + disconnect(reason) { + return this.setChannel(null, reason); + } + + /** + * Moves the member to a different channel, or disconnects them from the one they're in. + * @param {GuildVoiceChannelResolvable|null} channel Channel to move the member to, or `null` if you want to + * disconnect them from voice. + * @param {string} [reason] Reason for moving member to another channel or disconnecting + * @returns {Promise<GuildMember>} + */ + setChannel(channel, reason) { + return this.guild.members.edit(this.id, { channel, reason }); + } + + /** + * Data to edit the logged in user's own voice state with, when in a stage channel + * @typedef {Object} VoiceStateEditOptions + * @property {boolean} [requestToSpeak] Whether or not the client is requesting to become a speaker. + * <info>Only available to the logged in user's own voice state.</info> + * @property {boolean} [suppressed] Whether or not the user should be suppressed. + */ + + /** + * Edits this voice state. Currently only available when in a stage channel + * @param {VoiceStateEditOptions} options The options to provide + * @returns {Promise<VoiceState>} + */ + async edit(options) { + if (this.channel?.type !== ChannelType.GuildStageVoice) throw new DiscordjsError(ErrorCodes.VoiceNotStageChannel); + + const target = this.client.user.id === this.id ? '@me' : this.id; + + if (target !== '@me' && options.requestToSpeak !== undefined) { + throw new DiscordjsError(ErrorCodes.VoiceStateNotOwn); + } + + if (!['boolean', 'undefined'].includes(typeof options.requestToSpeak)) { + throw new DiscordjsTypeError(ErrorCodes.VoiceStateInvalidType, 'requestToSpeak'); + } + + if (!['boolean', 'undefined'].includes(typeof options.suppressed)) { + throw new DiscordjsTypeError(ErrorCodes.VoiceStateInvalidType, 'suppressed'); + } + + await this.client.rest.patch(Routes.guildVoiceState(this.guild.id, target), { + body: { + channel_id: this.channelId, + request_to_speak_timestamp: options.requestToSpeak + ? new Date().toISOString() + : options.requestToSpeak === false + ? null + : undefined, + suppress: options.suppressed, + }, + }); + return this; + } + + /** + * Toggles the request to speak in the channel. + * Only applicable for stage channels and for the client's own voice state. + * @param {boolean} [requestToSpeak=true] Whether or not the client is requesting to become a speaker. + * @example + * // Making the client request to speak in a stage channel (raise its hand) + * guild.members.me.voice.setRequestToSpeak(true); + * @example + * // Making the client cancel a request to speak + * guild.members.me.voice.setRequestToSpeak(false); + * @returns {Promise<VoiceState>} + */ + setRequestToSpeak(requestToSpeak = true) { + return this.edit({ requestToSpeak }); + } + + /** + * Suppress/unsuppress the user. Only applicable for stage channels. + * @param {boolean} [suppressed=true] Whether or not the user should be suppressed. + * @example + * // Making the client a speaker + * guild.members.me.voice.setSuppressed(false); + * @example + * // Making the client an audience member + * guild.members.me.voice.setSuppressed(true); + * @example + * // Inviting another user to speak + * voiceState.setSuppressed(false); + * @example + * // Moving another user to the audience, or cancelling their invite to speak + * voiceState.setSuppressed(true); + * @returns {Promise<VoiceState>} + */ + setSuppressed(suppressed = true) { + return this.edit({ suppressed }); + } + + toJSON() { + return super.toJSON({ + id: true, + serverDeaf: true, + serverMute: true, + selfDeaf: true, + selfMute: true, + sessionId: true, + channelId: 'channel', + }); + } +} + +module.exports = VoiceState; diff --git a/node_modules/discord.js/src/structures/Webhook.js b/node_modules/discord.js/src/structures/Webhook.js new file mode 100644 index 0000000..738d9e7 --- /dev/null +++ b/node_modules/discord.js/src/structures/Webhook.js @@ -0,0 +1,479 @@ +'use strict'; + +const { makeURLSearchParams } = require('@discordjs/rest'); +const { lazy } = require('@discordjs/util'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { Routes, WebhookType } = require('discord-api-types/v10'); +const MessagePayload = require('./MessagePayload'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const DataResolver = require('../util/DataResolver'); + +const getMessage = lazy(() => require('./Message').Message); + +/** + * Represents a webhook. + */ +class Webhook { + constructor(client, data) { + /** + * The client that instantiated the webhook + * @name Webhook#client + * @type {Client} + * @readonly + */ + Object.defineProperty(this, 'client', { value: client }); + if (data) this._patch(data); + } + + _patch(data) { + if ('name' in data) { + /** + * The name of the webhook + * @type {string} + */ + this.name = data.name; + } + + /** + * The token for the webhook, unavailable for follower webhooks and webhooks owned by another application. + * @name Webhook#token + * @type {?string} + */ + Object.defineProperty(this, 'token', { + value: data.token ?? null, + writable: true, + configurable: true, + }); + + if ('avatar' in data) { + /** + * The avatar for the webhook + * @type {?string} + */ + this.avatar = data.avatar; + } + + /** + * The webhook's id + * @type {Snowflake} + */ + this.id = data.id; + + if ('type' in data) { + /** + * The type of the webhook + * @type {WebhookType} + */ + this.type = data.type; + } + + if ('guild_id' in data) { + /** + * The guild the webhook belongs to + * @type {Snowflake} + */ + this.guildId = data.guild_id; + } + + if ('channel_id' in data) { + /** + * The id of the channel the webhook belongs to + * @type {Snowflake} + */ + this.channelId = data.channel_id; + } + + if ('user' in data) { + /** + * The owner of the webhook + * @type {?(User|APIUser)} + */ + this.owner = this.client.users?._add(data.user) ?? data.user; + } else { + this.owner ??= null; + } + + if ('application_id' in data) { + /** + * The application that created this webhook + * @type {?Snowflake} + */ + this.applicationId = data.application_id; + } else { + this.applicationId ??= null; + } + + if ('source_guild' in data) { + /** + * The source guild of the webhook + * @type {?(Guild|APIGuild)} + */ + this.sourceGuild = this.client.guilds?.resolve(data.source_guild.id) ?? data.source_guild; + } else { + this.sourceGuild ??= null; + } + + if ('source_channel' in data) { + /** + * The source channel of the webhook + * @type {?(NewsChannel|APIChannel)} + */ + this.sourceChannel = this.client.channels?.resolve(data.source_channel?.id) ?? data.source_channel; + } else { + this.sourceChannel ??= null; + } + } + + /** + * Options that can be passed into send. + * @typedef {BaseMessageOptions} WebhookMessageCreateOptions + * @property {boolean} [tts=false] Whether the message should be spoken aloud + * @property {MessageFlags} [flags] Which flags to set for the message. + * <info>Only the {@link MessageFlags.SuppressEmbeds} flag can be set.</info> + * @property {string} [username=this.name] Username override for the message + * @property {string} [avatarURL] Avatar URL override for the message + * @property {Snowflake} [threadId] The id of the thread in the channel to send to. + * <info>For interaction webhooks, this property is ignored</info> + * @property {string} [threadName] Name of the thread to create (only available if webhook is in a forum channel) + */ + + /** + * Options that can be passed into editMessage. + * @typedef {BaseMessageOptions} WebhookMessageEditOptions + * @property {Attachment[]} [attachments] Attachments to send with the message + * @property {Snowflake} [threadId] The id of the thread this message belongs to + * <info>For interaction webhooks, this property is ignored</info> + */ + + /** + * The channel the webhook belongs to + * @type {?(TextChannel|VoiceChannel|StageChannel|NewsChannel|ForumChannel)} + * @readonly + */ + get channel() { + return this.client.channels.resolve(this.channelId); + } + + /** + * Sends a message with this webhook. + * @param {string|MessagePayload|WebhookMessageCreateOptions} options The options to provide + * @returns {Promise<Message>} + * @example + * // Send a basic message + * webhook.send('hello!') + * .then(message => console.log(`Sent message: ${message.content}`)) + * .catch(console.error); + * @example + * // Send a basic message in a thread + * webhook.send({ content: 'hello!', threadId: '836856309672348295' }) + * .then(message => console.log(`Sent message: ${message.content}`)) + * .catch(console.error); + * @example + * // Send a remote file + * webhook.send({ + * files: ['https://cdn.discordapp.com/icons/222078108977594368/6e1019b3179d71046e463a75915e7244.png?size=2048'] + * }) + * .then(console.log) + * .catch(console.error); + * @example + * // Send a local file + * webhook.send({ + * files: [{ + * attachment: 'entire/path/to/file.jpg', + * name: 'file.jpg' + * }] + * }) + * .then(console.log) + * .catch(console.error); + * @example + * // Send an embed with a local image inside + * webhook.send({ + * content: 'This is an embed', + * embeds: [{ + * thumbnail: { + * url: 'attachment://file.jpg' + * } + * }], + * files: [{ + * attachment: 'entire/path/to/file.jpg', + * name: 'file.jpg' + * }] + * }) + * .then(console.log) + * .catch(console.error); + */ + async send(options) { + if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable); + + let messagePayload; + + if (options instanceof MessagePayload) { + messagePayload = options.resolveBody(); + } else { + messagePayload = MessagePayload.create(this, options).resolveBody(); + } + + const query = makeURLSearchParams({ + wait: true, + thread_id: messagePayload.options.threadId, + }); + + const { body, files } = await messagePayload.resolveFiles(); + const d = await this.client.rest.post(Routes.webhook(this.id, this.token), { + body, + files, + query, + auth: false, + }); + + if (!this.client.channels) return d; + return this.client.channels.cache.get(d.channel_id)?.messages._add(d, false) ?? new (getMessage())(this.client, d); + } + + /** + * Sends a raw slack message with this webhook. + * @param {Object} body The raw body to send + * @returns {Promise<boolean>} + * @example + * // Send a slack message + * webhook.sendSlackMessage({ + * 'username': 'Wumpus', + * 'attachments': [{ + * 'pretext': 'this looks pretty cool', + * 'color': '#F0F', + * 'footer_icon': 'http://snek.s3.amazonaws.com/topSnek.png', + * 'footer': 'Powered by sneks', + * 'ts': Date.now() / 1_000 + * }] + * }).catch(console.error); + * @see {@link https://api.slack.com/messaging/webhooks} + */ + async sendSlackMessage(body) { + if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable); + + const data = await this.client.rest.post(Routes.webhookPlatform(this.id, this.token, 'slack'), { + query: makeURLSearchParams({ wait: true }), + auth: false, + body, + }); + return data.toString() === 'ok'; + } + + /** + * Options used to edit a {@link Webhook}. + * @typedef {Object} WebhookEditOptions + * @property {string} [name=this.name] The new name for the webhook + * @property {?(BufferResolvable)} [avatar] The new avatar for the webhook + * @property {GuildTextChannelResolvable|VoiceChannel|StageChannel|ForumChannel} [channel] + * The new channel for the webhook + * @property {string} [reason] Reason for editing the webhook + */ + + /** + * Edits this webhook. + * @param {WebhookEditOptions} options Options for editing the webhook + * @returns {Promise<Webhook>} + */ + async edit({ name = this.name, avatar, channel, reason }) { + if (avatar && !(typeof avatar === 'string' && avatar.startsWith('data:'))) { + avatar = await DataResolver.resolveImage(avatar); + } + channel &&= channel.id ?? channel; + const data = await this.client.rest.patch(Routes.webhook(this.id, channel ? undefined : this.token), { + body: { name, avatar, channel_id: channel }, + reason, + auth: !this.token || Boolean(channel), + }); + + this.name = data.name; + this.avatar = data.avatar; + this.channelId = data.channel_id; + return this; + } + + /** + * Options that can be passed into fetchMessage. + * @typedef {options} WebhookFetchMessageOptions + * @property {boolean} [cache=true] Whether to cache the message. + * @property {Snowflake} [threadId] The id of the thread this message belongs to. + * <info>For interaction webhooks, this property is ignored</info> + */ + + /** + * Gets a message that was sent by this webhook. + * @param {Snowflake|'@original'} message The id of the message to fetch + * @param {WebhookFetchMessageOptions} [options={}] The options to provide to fetch the message. + * @returns {Promise<Message>} Returns the message sent by this webhook + */ + async fetchMessage(message, { threadId } = {}) { + if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable); + + const data = await this.client.rest.get(Routes.webhookMessage(this.id, this.token, message), { + query: threadId ? makeURLSearchParams({ thread_id: threadId }) : undefined, + auth: false, + }); + + if (!this.client.channels) return data; + return ( + this.client.channels.cache.get(data.channel_id)?.messages._add(data, false) ?? + new (getMessage())(this.client, data) + ); + } + + /** + * Edits a message that was sent by this webhook. + * @param {MessageResolvable|'@original'} message The message to edit + * @param {string|MessagePayload|WebhookMessageEditOptions} options The options to provide + * @returns {Promise<Message>} Returns the message edited by this webhook + */ + async editMessage(message, options) { + if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable); + + let messagePayload; + + if (options instanceof MessagePayload) messagePayload = options; + else messagePayload = MessagePayload.create(this, options); + + const { body, files } = await messagePayload.resolveBody().resolveFiles(); + + const d = await this.client.rest.patch( + Routes.webhookMessage(this.id, this.token, typeof message === 'string' ? message : message.id), + { + body, + files, + query: messagePayload.options.threadId + ? makeURLSearchParams({ thread_id: messagePayload.options.threadId }) + : undefined, + auth: false, + }, + ); + + const channelManager = this.client.channels; + if (!channelManager) return d; + + const messageManager = channelManager.cache.get(d.channel_id)?.messages; + if (!messageManager) return new (getMessage())(this.client, d); + + const existing = messageManager.cache.get(d.id); + if (!existing) return messageManager._add(d); + + const clone = existing._clone(); + clone._patch(d); + return clone; + } + + /** + * Deletes the webhook. + * @param {string} [reason] Reason for deleting this webhook + * @returns {Promise<void>} + */ + delete(reason) { + return this.client.deleteWebhook(this.id, { token: this.token, reason }); + } + + /** + * Delete a message that was sent by this webhook. + * @param {MessageResolvable|'@original'} message The message to delete + * @param {Snowflake} [threadId] The id of the thread this message belongs to + * @returns {Promise<void>} + */ + async deleteMessage(message, threadId) { + if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable); + + await this.client.rest.delete( + Routes.webhookMessage(this.id, this.token, typeof message === 'string' ? message : message.id), + { + query: threadId ? makeURLSearchParams({ thread_id: threadId }) : undefined, + auth: false, + }, + ); + } + + /** + * The timestamp the webhook was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the webhook was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * The URL of this webhook + * @type {string} + * @readonly + */ + get url() { + return this.client.options.rest.api + Routes.webhook(this.id, this.token); + } + + /** + * A link to the webhook's avatar. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + avatarURL(options = {}) { + return this.avatar && this.client.rest.cdn.avatar(this.id, this.avatar, options); + } + + /** + * Whether this webhook is created by a user. + * @returns {boolean} + */ + isUserCreated() { + return Boolean(this.type === WebhookType.Incoming && this.owner && !this.owner.bot); + } + + /** + * Whether this webhook is created by an application. + * @returns {boolean} + */ + isApplicationCreated() { + return this.type === WebhookType.Application; + } + + /** + * Whether or not this webhook is a channel follower webhook. + * @returns {boolean} + */ + isChannelFollower() { + return this.type === WebhookType.ChannelFollower; + } + + /** + * Whether or not this webhook is an incoming webhook. + * @returns {boolean} + */ + isIncoming() { + return this.type === WebhookType.Incoming; + } + + static applyToClass(structure, ignore = []) { + for (const prop of [ + 'send', + 'sendSlackMessage', + 'fetchMessage', + 'edit', + 'editMessage', + 'delete', + 'deleteMessage', + 'createdTimestamp', + 'createdAt', + 'url', + ]) { + if (ignore.includes(prop)) continue; + Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(Webhook.prototype, prop)); + } + } +} + +module.exports = Webhook; diff --git a/node_modules/discord.js/src/structures/WelcomeChannel.js b/node_modules/discord.js/src/structures/WelcomeChannel.js new file mode 100644 index 0000000..d783e06 --- /dev/null +++ b/node_modules/discord.js/src/structures/WelcomeChannel.js @@ -0,0 +1,60 @@ +'use strict'; + +const Base = require('./Base'); +const { Emoji } = require('./Emoji'); + +/** + * Represents a channel link in a guild's welcome screen. + * @extends {Base} + */ +class WelcomeChannel extends Base { + constructor(guild, data) { + super(guild.client); + + /** + * The guild for this welcome channel + * @type {Guild|InviteGuild} + */ + this.guild = guild; + + /** + * The description of this welcome channel + * @type {string} + */ + this.description = data.description; + + /** + * The raw emoji data + * @type {Object} + * @private + */ + this._emoji = { + name: data.emoji_name, + id: data.emoji_id, + }; + + /** + * The id of this welcome channel + * @type {Snowflake} + */ + this.channelId = data.channel_id; + } + + /** + * The channel of this welcome channel + * @type {?(TextChannel|NewsChannel|ForumChannel)} + */ + get channel() { + return this.client.channels.resolve(this.channelId); + } + + /** + * The emoji of this welcome channel + * @type {GuildEmoji|Emoji} + */ + get emoji() { + return this.client.emojis.resolve(this._emoji.id) ?? new Emoji(this.client, this._emoji); + } +} + +module.exports = WelcomeChannel; diff --git a/node_modules/discord.js/src/structures/WelcomeScreen.js b/node_modules/discord.js/src/structures/WelcomeScreen.js new file mode 100644 index 0000000..9ff79bc --- /dev/null +++ b/node_modules/discord.js/src/structures/WelcomeScreen.js @@ -0,0 +1,49 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { GuildFeature } = require('discord-api-types/v10'); +const Base = require('./Base'); +const WelcomeChannel = require('./WelcomeChannel'); + +/** + * Represents a welcome screen. + * @extends {Base} + */ +class WelcomeScreen extends Base { + constructor(guild, data) { + super(guild.client); + + /** + * The guild for this welcome screen + * @type {Guild} + */ + this.guild = guild; + + /** + * The description of this welcome screen + * @type {?string} + */ + this.description = data.description ?? null; + + /** + * Collection of welcome channels belonging to this welcome screen + * @type {Collection<Snowflake, WelcomeChannel>} + */ + this.welcomeChannels = new Collection(); + + for (const channel of data.welcome_channels) { + const welcomeChannel = new WelcomeChannel(this.guild, channel); + this.welcomeChannels.set(welcomeChannel.channelId, welcomeChannel); + } + } + + /** + * Whether the welcome screen is enabled on the guild + * @type {boolean} + */ + get enabled() { + return this.guild.features.includes(GuildFeature.WelcomeScreenEnabled); + } +} + +module.exports = WelcomeScreen; diff --git a/node_modules/discord.js/src/structures/Widget.js b/node_modules/discord.js/src/structures/Widget.js new file mode 100644 index 0000000..344c81a --- /dev/null +++ b/node_modules/discord.js/src/structures/Widget.js @@ -0,0 +1,88 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { Routes } = require('discord-api-types/v10'); +const Base = require('./Base'); +const WidgetMember = require('./WidgetMember'); + +/** + * Represents a Widget. + * @extends {Base} + */ +class Widget extends Base { + constructor(client, data) { + super(client); + this._patch(data); + } + + /** + * Represents a channel in a Widget + * @typedef {Object} WidgetChannel + * @property {Snowflake} id Id of the channel + * @property {string} name Name of the channel + * @property {number} position Position of the channel + */ + + _patch(data) { + /** + * The id of the guild. + * @type {Snowflake} + */ + this.id = data.id; + + if ('name' in data) { + /** + * The name of the guild. + * @type {string} + */ + this.name = data.name; + } + + if ('instant_invite' in data) { + /** + * The invite of the guild. + * @type {?string} + */ + this.instantInvite = data.instant_invite; + } + + /** + * The list of channels in the guild. + * @type {Collection<Snowflake, WidgetChannel>} + */ + this.channels = new Collection(); + for (const channel of data.channels) { + this.channels.set(channel.id, channel); + } + + /** + * The list of members in the guild. + * These strings are just arbitrary numbers, they aren't Snowflakes. + * @type {Collection<string, WidgetMember>} + */ + this.members = new Collection(); + for (const member of data.members) { + this.members.set(member.id, new WidgetMember(this.client, member)); + } + + if ('presence_count' in data) { + /** + * The number of members online. + * @type {number} + */ + this.presenceCount = data.presence_count; + } + } + + /** + * Update the Widget. + * @returns {Promise<Widget>} + */ + async fetch() { + const data = await this.client.rest.get(Routes.guildWidgetJSON(this.id)); + this._patch(data); + return this; + } +} + +module.exports = Widget; diff --git a/node_modules/discord.js/src/structures/WidgetMember.js b/node_modules/discord.js/src/structures/WidgetMember.js new file mode 100644 index 0000000..d7aca21 --- /dev/null +++ b/node_modules/discord.js/src/structures/WidgetMember.js @@ -0,0 +1,99 @@ +'use strict'; + +const Base = require('./Base'); + +/** + * Represents a WidgetMember. + * @extends {Base} + */ +class WidgetMember extends Base { + /** + * Activity sent in a {@link WidgetMember}. + * @typedef {Object} WidgetActivity + * @property {string} name The name of the activity + */ + + constructor(client, data) { + super(client); + + /** + * The id of the user. It's an arbitrary number. + * @type {string} + */ + this.id = data.id; + + /** + * The username of the member. + * @type {string} + */ + this.username = data.username; + + /** + * The discriminator of the member. + * @type {string} + */ + this.discriminator = data.discriminator; + + /** + * The avatar of the member. + * @type {?string} + */ + this.avatar = data.avatar; + + /** + * The status of the member. + * @type {PresenceStatus} + */ + this.status = data.status; + + /** + * If the member is server deafened + * @type {?boolean} + */ + this.deaf = data.deaf ?? null; + + /** + * If the member is server muted + * @type {?boolean} + */ + this.mute = data.mute ?? null; + + /** + * If the member is self deafened + * @type {?boolean} + */ + this.selfDeaf = data.self_deaf ?? null; + + /** + * If the member is self muted + * @type {?boolean} + */ + this.selfMute = data.self_mute ?? null; + + /** + * If the member is suppressed + * @type {?boolean} + */ + this.suppress = data.suppress ?? null; + + /** + * The id of the voice channel the member is in, if any + * @type {?Snowflake} + */ + this.channelId = data.channel_id ?? null; + + /** + * The avatar URL of the member. + * @type {string} + */ + this.avatarURL = data.avatar_url; + + /** + * The activity of the member. + * @type {?WidgetActivity} + */ + this.activity = data.activity ?? null; + } +} + +module.exports = WidgetMember; diff --git a/node_modules/discord.js/src/structures/interfaces/Application.js b/node_modules/discord.js/src/structures/interfaces/Application.js new file mode 100644 index 0000000..5e81465 --- /dev/null +++ b/node_modules/discord.js/src/structures/interfaces/Application.js @@ -0,0 +1,108 @@ +'use strict'; + +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const Base = require('../Base'); + +/** + * Represents an OAuth2 Application. + * @extends {Base} + * @abstract + */ +class Application extends Base { + constructor(client, data) { + super(client); + this._patch(data); + } + + _patch(data) { + /** + * The application's id + * @type {Snowflake} + */ + this.id = data.id; + + if ('name' in data) { + /** + * The name of the application + * @type {?string} + */ + this.name = data.name; + } else { + this.name ??= null; + } + + if ('description' in data) { + /** + * The application's description + * @type {?string} + */ + this.description = data.description; + } else { + this.description ??= null; + } + + if ('icon' in data) { + /** + * The application's icon hash + * @type {?string} + */ + this.icon = data.icon; + } else { + this.icon ??= null; + } + } + + /** + * The timestamp the application was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } + + /** + * The time the application was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * A link to the application's icon. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + iconURL(options = {}) { + return this.icon && this.client.rest.cdn.appIcon(this.id, this.icon, options); + } + + /** + * A link to this application's cover image. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + coverURL(options = {}) { + return this.cover && this.client.rest.cdn.appIcon(this.id, this.cover, options); + } + + /** + * When concatenated with a string, this automatically returns the application's name instead of the + * Application object. + * @returns {?string} + * @example + * // Logs: Application name: My App + * console.log(`Application name: ${application}`); + */ + toString() { + return this.name; + } + + toJSON() { + return super.toJSON({ createdTimestamp: true }); + } +} + +module.exports = Application; diff --git a/node_modules/discord.js/src/structures/interfaces/Collector.js b/node_modules/discord.js/src/structures/interfaces/Collector.js new file mode 100644 index 0000000..65f4117 --- /dev/null +++ b/node_modules/discord.js/src/structures/interfaces/Collector.js @@ -0,0 +1,335 @@ +'use strict'; + +const EventEmitter = require('node:events'); +const { setTimeout, clearTimeout } = require('node:timers'); +const { Collection } = require('@discordjs/collection'); +const { DiscordjsTypeError, ErrorCodes } = require('../../errors'); +const { flatten } = require('../../util/Util'); + +/** + * Filter to be applied to the collector. + * @typedef {Function} CollectorFilter + * @param {...*} args Any arguments received by the listener + * @param {Collection} collection The items collected by this collector + * @returns {boolean|Promise<boolean>} + */ + +/** + * Options to be applied to the collector. + * @typedef {Object} CollectorOptions + * @property {CollectorFilter} [filter] The filter applied to this collector + * @property {number} [time] How long to run the collector for in milliseconds + * @property {number} [idle] How long to stop the collector after inactivity in milliseconds + * @property {boolean} [dispose=false] Whether to dispose data when it's deleted + */ + +/** + * Abstract class for defining a new Collector. + * @extends {EventEmitter} + * @abstract + */ +class Collector extends EventEmitter { + constructor(client, options = {}) { + super(); + + /** + * The client that instantiated this Collector + * @name Collector#client + * @type {Client} + * @readonly + */ + Object.defineProperty(this, 'client', { value: client }); + + /** + * The filter applied to this collector + * @type {CollectorFilter} + * @returns {boolean|Promise<boolean>} + */ + this.filter = options.filter ?? (() => true); + + /** + * The options of this collector + * @type {CollectorOptions} + */ + this.options = options; + + /** + * The items collected by this collector + * @type {Collection} + */ + this.collected = new Collection(); + + /** + * Whether this collector has finished collecting + * @type {boolean} + */ + this.ended = false; + + /** + * Timeout for cleanup + * @type {?Timeout} + * @private + */ + this._timeout = null; + + /** + * Timeout for cleanup due to inactivity + * @type {?Timeout} + * @private + */ + this._idletimeout = null; + + /** + * The reason the collector ended + * @type {string|null} + * @private + */ + this._endReason = null; + + if (typeof this.filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options.filter', 'function'); + } + + this.handleCollect = this.handleCollect.bind(this); + this.handleDispose = this.handleDispose.bind(this); + + if (options.time) this._timeout = setTimeout(() => this.stop('time'), options.time).unref(); + if (options.idle) this._idletimeout = setTimeout(() => this.stop('idle'), options.idle).unref(); + + /** + * The timestamp at which this collector last collected an item + * @type {?number} + */ + this.lastCollectedTimestamp = null; + } + + /** + * The Date at which this collector last collected an item + * @type {?Date} + */ + get lastCollectedAt() { + return this.lastCollectedTimestamp && new Date(this.lastCollectedTimestamp); + } + + /** + * Call this to handle an event as a collectable element. Accepts any event data as parameters. + * @param {...*} args The arguments emitted by the listener + * @returns {Promise<void>} + * @emits Collector#collect + */ + async handleCollect(...args) { + const collectedId = await this.collect(...args); + + if (collectedId) { + const filterResult = await this.filter(...args, this.collected); + if (filterResult) { + this.collected.set(collectedId, args[0]); + + /** + * Emitted whenever an element is collected. + * @event Collector#collect + * @param {...*} args The arguments emitted by the listener + */ + this.emit('collect', ...args); + + this.lastCollectedTimestamp = Date.now(); + if (this._idletimeout) { + clearTimeout(this._idletimeout); + this._idletimeout = setTimeout(() => this.stop('idle'), this.options.idle).unref(); + } + } else { + /** + * Emitted whenever an element is not collected by the collector. + * @event Collector#ignore + * @param {...*} args The arguments emitted by the listener + */ + this.emit('ignore', ...args); + } + } + this.checkEnd(); + } + + /** + * Call this to remove an element from the collection. Accepts any event data as parameters. + * @param {...*} args The arguments emitted by the listener + * @returns {Promise<void>} + * @emits Collector#dispose + */ + async handleDispose(...args) { + if (!this.options.dispose) return; + + const dispose = this.dispose(...args); + if (!dispose || !(await this.filter(...args)) || !this.collected.has(dispose)) return; + this.collected.delete(dispose); + + /** + * Emitted whenever an element is disposed of. + * @event Collector#dispose + * @param {...*} args The arguments emitted by the listener + */ + this.emit('dispose', ...args); + this.checkEnd(); + } + + /** + * Returns a promise that resolves with the next collected element; + * rejects with collected elements if the collector finishes without receiving a next element + * @type {Promise} + * @readonly + */ + get next() { + return new Promise((resolve, reject) => { + if (this.ended) { + reject(this.collected); + return; + } + + const cleanup = () => { + this.removeListener('collect', onCollect); + this.removeListener('end', onEnd); + }; + + const onCollect = item => { + cleanup(); + resolve(item); + }; + + const onEnd = () => { + cleanup(); + reject(this.collected); + }; + + this.on('collect', onCollect); + this.on('end', onEnd); + }); + } + + /** + * Stops this collector and emits the `end` event. + * @param {string} [reason='user'] The reason this collector is ending + * @emits Collector#end + */ + stop(reason = 'user') { + if (this.ended) return; + + if (this._timeout) { + clearTimeout(this._timeout); + this._timeout = null; + } + if (this._idletimeout) { + clearTimeout(this._idletimeout); + this._idletimeout = null; + } + + this._endReason = reason; + this.ended = true; + + /** + * Emitted when the collector is finished collecting. + * @event Collector#end + * @param {Collection} collected The elements collected by the collector + * @param {string} reason The reason the collector ended + */ + this.emit('end', this.collected, reason); + } + + /** + * Options used to reset the timeout and idle timer of a {@link Collector}. + * @typedef {Object} CollectorResetTimerOptions + * @property {number} [time] How long to run the collector for (in milliseconds) + * @property {number} [idle] How long to wait to stop the collector after inactivity (in milliseconds) + */ + + /** + * Resets the collector's timeout and idle timer. + * @param {CollectorResetTimerOptions} [options] Options for resetting + */ + resetTimer({ time, idle } = {}) { + if (this._timeout) { + clearTimeout(this._timeout); + this._timeout = setTimeout(() => this.stop('time'), time ?? this.options.time).unref(); + } + if (this._idletimeout) { + clearTimeout(this._idletimeout); + this._idletimeout = setTimeout(() => this.stop('idle'), idle ?? this.options.idle).unref(); + } + } + + /** + * Checks whether the collector should end, and if so, ends it. + * @returns {boolean} Whether the collector ended or not + */ + checkEnd() { + const reason = this.endReason; + if (reason) this.stop(reason); + return Boolean(reason); + } + + /** + * Allows collectors to be consumed with for-await-of loops + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of} + */ + async *[Symbol.asyncIterator]() { + const queue = []; + const onCollect = (...item) => queue.push(item); + this.on('collect', onCollect); + + try { + while (queue.length || !this.ended) { + if (queue.length) { + yield queue.shift(); + } else { + // eslint-disable-next-line no-await-in-loop + await new Promise(resolve => { + const tick = () => { + this.removeListener('collect', tick); + this.removeListener('end', tick); + return resolve(); + }; + this.on('collect', tick); + this.on('end', tick); + }); + } + } + } finally { + this.removeListener('collect', onCollect); + } + } + + toJSON() { + return flatten(this); + } + + /* eslint-disable no-empty-function */ + /** + * The reason this collector has ended with, or null if it hasn't ended yet + * @type {?string} + * @readonly + */ + get endReason() { + return this._endReason; + } + + /** + * Handles incoming events from the `handleCollect` function. Returns null if the event should not + * be collected, or returns an object describing the data that should be stored. + * @see Collector#handleCollect + * @param {...*} args Any args the event listener emits + * @returns {?(*|Promise<?*>)} Data to insert into collection, if any + * @abstract + */ + collect() {} + + /** + * Handles incoming events from the `handleDispose`. Returns null if the event should not + * be disposed, or returns the key that should be removed. + * @see Collector#handleDispose + * @param {...*} args Any args the event listener emits + * @returns {?*} Key to remove from the collection, if any + * @abstract + */ + dispose() {} + /* eslint-enable no-empty-function */ +} + +module.exports = Collector; diff --git a/node_modules/discord.js/src/structures/interfaces/InteractionResponses.js b/node_modules/discord.js/src/structures/interfaces/InteractionResponses.js new file mode 100644 index 0000000..15256e3 --- /dev/null +++ b/node_modules/discord.js/src/structures/interfaces/InteractionResponses.js @@ -0,0 +1,320 @@ +'use strict'; + +const { isJSONEncodable } = require('@discordjs/util'); +const { InteractionResponseType, MessageFlags, Routes, InteractionType } = require('discord-api-types/v10'); +const { DiscordjsError, ErrorCodes } = require('../../errors'); +const InteractionCollector = require('../InteractionCollector'); +const InteractionResponse = require('../InteractionResponse'); +const MessagePayload = require('../MessagePayload'); + +/** + * @typedef {Object} ModalComponentData + * @property {string} title The title of the modal + * @property {string} customId The custom id of the modal + * @property {ActionRow[]} components The components within this modal + */ + +/** + * Interface for classes that support shared interaction response types. + * @interface + */ +class InteractionResponses { + /** + * Options for deferring the reply to an {@link BaseInteraction}. + * @typedef {Object} InteractionDeferReplyOptions + * @property {boolean} [ephemeral] Whether the reply should be ephemeral + * @property {boolean} [fetchReply] Whether to fetch the reply + */ + + /** + * Options for deferring and updating the reply to a {@link MessageComponentInteraction}. + * @typedef {Object} InteractionDeferUpdateOptions + * @property {boolean} [fetchReply] Whether to fetch the reply + */ + + /** + * Options for a reply to a {@link BaseInteraction}. + * @typedef {BaseMessageOptions} InteractionReplyOptions + * @property {boolean} [tts=false] Whether the message should be spoken aloud + * @property {boolean} [ephemeral] Whether the reply should be ephemeral + * @property {boolean} [fetchReply] Whether to fetch the reply + * @property {MessageFlags} [flags] Which flags to set for the message. + * <info>Only `MessageFlags.SuppressEmbeds` and `MessageFlags.Ephemeral` can be set.</info> + */ + + /** + * Options for updating the message received from a {@link MessageComponentInteraction}. + * @typedef {MessageEditOptions} InteractionUpdateOptions + * @property {boolean} [fetchReply] Whether to fetch the reply + */ + + /** + * Defers the reply to this interaction. + * @param {InteractionDeferReplyOptions} [options] Options for deferring the reply to this interaction + * @returns {Promise<Message|InteractionResponse>} + * @example + * // Defer the reply to this interaction + * interaction.deferReply() + * .then(console.log) + * .catch(console.error) + * @example + * // Defer to send an ephemeral reply later + * interaction.deferReply({ ephemeral: true }) + * .then(console.log) + * .catch(console.error); + */ + async deferReply(options = {}) { + if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied); + this.ephemeral = options.ephemeral ?? false; + await this.client.rest.post(Routes.interactionCallback(this.id, this.token), { + body: { + type: InteractionResponseType.DeferredChannelMessageWithSource, + data: { + flags: options.ephemeral ? MessageFlags.Ephemeral : undefined, + }, + }, + auth: false, + }); + this.deferred = true; + + return options.fetchReply ? this.fetchReply() : new InteractionResponse(this); + } + + /** + * Creates a reply to this interaction. + * <info>Use the `fetchReply` option to get the bot's reply message.</info> + * @param {string|MessagePayload|InteractionReplyOptions} options The options for the reply + * @returns {Promise<Message|InteractionResponse>} + * @example + * // Reply to the interaction and fetch the response + * interaction.reply({ content: 'Pong!', fetchReply: true }) + * .then((message) => console.log(`Reply sent with content ${message.content}`)) + * .catch(console.error); + * @example + * // Create an ephemeral reply with an embed + * const embed = new EmbedBuilder().setDescription('Pong!'); + * + * interaction.reply({ embeds: [embed], ephemeral: true }) + * .then(() => console.log('Reply sent.')) + * .catch(console.error); + */ + async reply(options) { + if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied); + this.ephemeral = options.ephemeral ?? false; + + let messagePayload; + if (options instanceof MessagePayload) messagePayload = options; + else messagePayload = MessagePayload.create(this, options); + + const { body: data, files } = await messagePayload.resolveBody().resolveFiles(); + + await this.client.rest.post(Routes.interactionCallback(this.id, this.token), { + body: { + type: InteractionResponseType.ChannelMessageWithSource, + data, + }, + files, + auth: false, + }); + this.replied = true; + + return options.fetchReply ? this.fetchReply() : new InteractionResponse(this); + } + + /** + * Fetches a reply to this interaction. + * @see Webhook#fetchMessage + * @param {Snowflake|'@original'} [message='@original'] The response to fetch + * @returns {Promise<Message>} + * @example + * // Fetch the initial reply to this interaction + * interaction.fetchReply() + * .then(reply => console.log(`Replied with ${reply.content}`)) + * .catch(console.error); + */ + fetchReply(message = '@original') { + return this.webhook.fetchMessage(message); + } + + /** + * Options that can be passed into {@link InteractionResponses#editReply}. + * @typedef {WebhookMessageEditOptions} InteractionEditReplyOptions + * @property {MessageResolvable|'@original'} [message='@original'] The response to edit + */ + + /** + * Edits a reply to this interaction. + * @see Webhook#editMessage + * @param {string|MessagePayload|InteractionEditReplyOptions} options The new options for the message + * @returns {Promise<Message>} + * @example + * // Edit the initial reply to this interaction + * interaction.editReply('New content') + * .then(console.log) + * .catch(console.error); + */ + async editReply(options) { + if (!this.deferred && !this.replied) throw new DiscordjsError(ErrorCodes.InteractionNotReplied); + const msg = await this.webhook.editMessage(options.message ?? '@original', options); + this.replied = true; + return msg; + } + + /** + * Deletes a reply to this interaction. + * @see Webhook#deleteMessage + * @param {MessageResolvable|'@original'} [message='@original'] The response to delete + * @returns {Promise<void>} + * @example + * // Delete the initial reply to this interaction + * interaction.deleteReply() + * .then(console.log) + * .catch(console.error); + */ + async deleteReply(message = '@original') { + await this.webhook.deleteMessage(message); + } + + /** + * Send a follow-up message to this interaction. + * @param {string|MessagePayload|InteractionReplyOptions} options The options for the reply + * @returns {Promise<Message>} + */ + followUp(options) { + if (!this.deferred && !this.replied) return Promise.reject(new DiscordjsError(ErrorCodes.InteractionNotReplied)); + return this.webhook.send(options); + } + + /** + * Defers an update to the message to which the component was attached. + * @param {InteractionDeferUpdateOptions} [options] Options for deferring the update to this interaction + * @returns {Promise<Message|InteractionResponse>} + * @example + * // Defer updating and reset the component's loading state + * interaction.deferUpdate() + * .then(console.log) + * .catch(console.error); + */ + async deferUpdate(options = {}) { + if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied); + await this.client.rest.post(Routes.interactionCallback(this.id, this.token), { + body: { + type: InteractionResponseType.DeferredMessageUpdate, + }, + auth: false, + }); + this.deferred = true; + + return options.fetchReply ? this.fetchReply() : new InteractionResponse(this, this.message?.interaction?.id); + } + + /** + * Updates the original message of the component on which the interaction was received on. + * @param {string|MessagePayload|InteractionUpdateOptions} options The options for the updated message + * @returns {Promise<Message|void>} + * @example + * // Remove the components from the message + * interaction.update({ + * content: "A component interaction was received", + * components: [] + * }) + * .then(console.log) + * .catch(console.error); + */ + async update(options) { + if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied); + + let messagePayload; + if (options instanceof MessagePayload) messagePayload = options; + else messagePayload = MessagePayload.create(this, options); + + const { body: data, files } = await messagePayload.resolveBody().resolveFiles(); + + await this.client.rest.post(Routes.interactionCallback(this.id, this.token), { + body: { + type: InteractionResponseType.UpdateMessage, + data, + }, + files, + auth: false, + }); + this.replied = true; + + return options.fetchReply ? this.fetchReply() : new InteractionResponse(this, this.message.interaction?.id); + } + + /** + * Shows a modal component + * @param {ModalBuilder|ModalComponentData|APIModalInteractionResponseCallbackData} modal The modal to show + * @returns {Promise<void>} + */ + async showModal(modal) { + if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied); + await this.client.rest.post(Routes.interactionCallback(this.id, this.token), { + body: { + type: InteractionResponseType.Modal, + data: isJSONEncodable(modal) ? modal.toJSON() : this.client.options.jsonTransformer(modal), + }, + auth: false, + }); + this.replied = true; + } + + /** + * An object containing the same properties as {@link CollectorOptions}, but a few less: + * @typedef {Object} AwaitModalSubmitOptions + * @property {CollectorFilter} [filter] The filter applied to this collector + * @property {number} time Time in milliseconds to wait for an interaction before rejecting + */ + + /** + * Collects a single modal submit interaction that passes the filter. + * The Promise will reject if the time expires. + * @param {AwaitModalSubmitOptions} options Options to pass to the internal collector + * @returns {Promise<ModalSubmitInteraction>} + * @example + * // Collect a modal submit interaction + * const filter = (interaction) => interaction.customId === 'modal'; + * interaction.awaitModalSubmit({ filter, time: 15_000 }) + * .then(interaction => console.log(`${interaction.customId} was submitted!`)) + * .catch(console.error); + */ + awaitModalSubmit(options) { + if (typeof options.time !== 'number') throw new DiscordjsError(ErrorCodes.InvalidType, 'time', 'number'); + const _options = { ...options, max: 1, interactionType: InteractionType.ModalSubmit }; + return new Promise((resolve, reject) => { + const collector = new InteractionCollector(this.client, _options); + collector.once('end', (interactions, reason) => { + const interaction = interactions.first(); + if (interaction) resolve(interaction); + else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason)); + }); + }); + } + + static applyToClass(structure, ignore = []) { + const props = [ + 'deferReply', + 'reply', + 'fetchReply', + 'editReply', + 'deleteReply', + 'followUp', + 'deferUpdate', + 'update', + 'showModal', + 'awaitModalSubmit', + ]; + + for (const prop of props) { + if (ignore.includes(prop)) continue; + Object.defineProperty( + structure.prototype, + prop, + Object.getOwnPropertyDescriptor(InteractionResponses.prototype, prop), + ); + } + } +} + +module.exports = InteractionResponses; diff --git a/node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js b/node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js new file mode 100644 index 0000000..cf455b9 --- /dev/null +++ b/node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js @@ -0,0 +1,413 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { DiscordSnowflake } = require('@sapphire/snowflake'); +const { InteractionType, Routes } = require('discord-api-types/v10'); +const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../../errors'); +const { MaxBulkDeletableMessageAge } = require('../../util/Constants'); +const InteractionCollector = require('../InteractionCollector'); +const MessageCollector = require('../MessageCollector'); +const MessagePayload = require('../MessagePayload'); + +/** + * Interface for classes that have text-channel-like features. + * @interface + */ +class TextBasedChannel { + constructor() { + /** + * A manager of the messages sent to this channel + * @type {GuildMessageManager} + */ + this.messages = new GuildMessageManager(this); + + /** + * The channel's last message id, if one was sent + * @type {?Snowflake} + */ + this.lastMessageId = null; + + /** + * The timestamp when the last pinned message was pinned, if there was one + * @type {?number} + */ + this.lastPinTimestamp = null; + } + + /** + * The Message object of the last message in the channel, if one was sent + * @type {?Message} + * @readonly + */ + get lastMessage() { + return this.messages.resolve(this.lastMessageId); + } + + /** + * The date when the last pinned message was pinned, if there was one + * @type {?Date} + * @readonly + */ + get lastPinAt() { + return this.lastPinTimestamp && new Date(this.lastPinTimestamp); + } + + /** + * The base message options for messages. + * @typedef {Object} BaseMessageOptions + * @property {string|null} [content=''] The content for the message. This can only be `null` when editing a message. + * @property {Array<(EmbedBuilder|Embed|APIEmbed)>} [embeds] The embeds for the message + * @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content + * (see [here](https://discord.com/developers/docs/resources/channel#allowed-mentions-object) for more details) + * @property {Array<(AttachmentBuilder|Attachment|AttachmentPayload|BufferResolvable)>} [files] + * The files to send with the message. + * @property {Array<(ActionRowBuilder|ActionRow|APIActionRowComponent)>} [components] + * Action rows containing interactive components for the message (buttons, select menus) + */ + + /** + * Options for sending a message with a reply. + * @typedef {Object} ReplyOptions + * @property {MessageResolvable} messageReference The message to reply to (must be in the same channel and not system) + * @property {boolean} [failIfNotExists=this.client.options.failIfNotExists] Whether to error if the referenced + * message does not exist (creates a standard message in this case when false) + */ + + /** + * The options for sending a message. + * @typedef {BaseMessageOptions} BaseMessageCreateOptions + * @property {boolean} [tts=false] Whether the message should be spoken aloud + * @property {string} [nonce=''] The nonce for the message + * @property {StickerResolvable[]} [stickers=[]] The stickers to send in the message + * @property {MessageFlags} [flags] Which flags to set for the message. + * <info>Only `MessageFlags.SuppressEmbeds` and `MessageFlags.SuppressNotifications` can be set.</info> + */ + + /** + * The options for sending a message. + * @typedef {BaseMessageCreateOptions} MessageCreateOptions + * @property {ReplyOptions} [reply] The options for replying to a message + */ + + /** + * Options provided to control parsing of mentions by Discord + * @typedef {Object} MessageMentionOptions + * @property {MessageMentionTypes[]} [parse] Types of mentions to be parsed + * @property {Snowflake[]} [users] Snowflakes of Users to be parsed as mentions + * @property {Snowflake[]} [roles] Snowflakes of Roles to be parsed as mentions + * @property {boolean} [repliedUser=true] Whether the author of the Message being replied to should be pinged + */ + + /** + * Types of mentions to enable in MessageMentionOptions. + * - `roles` + * - `users` + * - `everyone` + * @typedef {string} MessageMentionTypes + */ + + /** + * @typedef {Object} FileOptions + * @property {BufferResolvable} attachment File to attach + * @property {string} [name='file.jpg'] Filename of the attachment + * @property {string} description The description of the file + */ + + /** + * Sends a message to this channel. + * @param {string|MessagePayload|MessageCreateOptions} options The options to provide + * @returns {Promise<Message>} + * @example + * // Send a basic message + * channel.send('hello!') + * .then(message => console.log(`Sent message: ${message.content}`)) + * .catch(console.error); + * @example + * // Send a remote file + * channel.send({ + * files: ['https://cdn.discordapp.com/icons/222078108977594368/6e1019b3179d71046e463a75915e7244.png?size=2048'] + * }) + * .then(console.log) + * .catch(console.error); + * @example + * // Send a local file + * channel.send({ + * files: [{ + * attachment: 'entire/path/to/file.jpg', + * name: 'file.jpg', + * description: 'A description of the file' + * }] + * }) + * .then(console.log) + * .catch(console.error); + */ + async send(options) { + const User = require('../User'); + const { GuildMember } = require('../GuildMember'); + + if (this instanceof User || this instanceof GuildMember) { + const dm = await this.createDM(); + return dm.send(options); + } + + let messagePayload; + + if (options instanceof MessagePayload) { + messagePayload = options.resolveBody(); + } else { + messagePayload = MessagePayload.create(this, options).resolveBody(); + } + + const { body, files } = await messagePayload.resolveFiles(); + const d = await this.client.rest.post(Routes.channelMessages(this.id), { body, files }); + + return this.messages.cache.get(d.id) ?? this.messages._add(d); + } + + /** + * Sends a typing indicator in the channel. + * @returns {Promise<void>} Resolves upon the typing status being sent + * @example + * // Start typing in a channel + * channel.sendTyping(); + */ + async sendTyping() { + await this.client.rest.post(Routes.channelTyping(this.id)); + } + + /** + * Creates a Message Collector. + * @param {MessageCollectorOptions} [options={}] The options to pass to the collector + * @returns {MessageCollector} + * @example + * // Create a message collector + * const filter = m => m.content.includes('discord'); + * const collector = channel.createMessageCollector({ filter, time: 15_000 }); + * collector.on('collect', m => console.log(`Collected ${m.content}`)); + * collector.on('end', collected => console.log(`Collected ${collected.size} items`)); + */ + createMessageCollector(options = {}) { + return new MessageCollector(this, options); + } + + /** + * An object containing the same properties as CollectorOptions, but a few more: + * @typedef {MessageCollectorOptions} AwaitMessagesOptions + * @property {string[]} [errors] Stop/end reasons that cause the promise to reject + */ + + /** + * Similar to createMessageCollector but in promise form. + * Resolves with a collection of messages that pass the specified filter. + * @param {AwaitMessagesOptions} [options={}] Optional options to pass to the internal collector + * @returns {Promise<Collection<Snowflake, Message>>} + * @example + * // Await !vote messages + * const filter = m => m.content.startsWith('!vote'); + * // Errors: ['time'] treats ending because of the time limit as an error + * channel.awaitMessages({ filter, max: 4, time: 60_000, errors: ['time'] }) + * .then(collected => console.log(collected.size)) + * .catch(collected => console.log(`After a minute, only ${collected.size} out of 4 voted.`)); + */ + awaitMessages(options = {}) { + return new Promise((resolve, reject) => { + const collector = this.createMessageCollector(options); + collector.once('end', (collection, reason) => { + if (options.errors?.includes(reason)) { + reject(collection); + } else { + resolve(collection); + } + }); + }); + } + + /** + * Creates a component interaction collector. + * @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector + * @returns {InteractionCollector} + * @example + * // Create a button interaction collector + * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId'; + * const collector = channel.createMessageComponentCollector({ filter, time: 15_000 }); + * collector.on('collect', i => console.log(`Collected ${i.customId}`)); + * collector.on('end', collected => console.log(`Collected ${collected.size} items`)); + */ + createMessageComponentCollector(options = {}) { + return new InteractionCollector(this.client, { + ...options, + interactionType: InteractionType.MessageComponent, + channel: this, + }); + } + + /** + * Collects a single component interaction that passes the filter. + * The Promise will reject if the time expires. + * @param {AwaitMessageComponentOptions} [options={}] Options to pass to the internal collector + * @returns {Promise<MessageComponentInteraction>} + * @example + * // Collect a message component interaction + * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId'; + * channel.awaitMessageComponent({ filter, time: 15_000 }) + * .then(interaction => console.log(`${interaction.customId} was clicked!`)) + * .catch(console.error); + */ + awaitMessageComponent(options = {}) { + const _options = { ...options, max: 1 }; + return new Promise((resolve, reject) => { + const collector = this.createMessageComponentCollector(_options); + collector.once('end', (interactions, reason) => { + const interaction = interactions.first(); + if (interaction) resolve(interaction); + else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason)); + }); + }); + } + + /** + * Bulk deletes given messages that are newer than two weeks. + * @param {Collection<Snowflake, Message>|MessageResolvable[]|number} messages + * Messages or number of messages to delete + * @param {boolean} [filterOld=false] Filter messages to remove those which are older than two weeks automatically + * @returns {Promise<Collection<Snowflake, Message|undefined>>} Returns the deleted messages + * @example + * // Bulk delete messages + * channel.bulkDelete(5) + * .then(messages => console.log(`Bulk deleted ${messages.size} messages`)) + * .catch(console.error); + */ + async bulkDelete(messages, filterOld = false) { + if (Array.isArray(messages) || messages instanceof Collection) { + let messageIds = messages instanceof Collection ? [...messages.keys()] : messages.map(m => m.id ?? m); + if (filterOld) { + messageIds = messageIds.filter( + id => Date.now() - DiscordSnowflake.timestampFrom(id) < MaxBulkDeletableMessageAge, + ); + } + if (messageIds.length === 0) return new Collection(); + if (messageIds.length === 1) { + const message = this.client.actions.MessageDelete.getMessage( + { + message_id: messageIds[0], + }, + this, + ); + await this.client.rest.delete(Routes.channelMessage(this.id, messageIds[0])); + return message ? new Collection([[message.id, message]]) : new Collection(); + } + await this.client.rest.post(Routes.channelBulkDelete(this.id), { body: { messages: messageIds } }); + return messageIds.reduce( + (col, id) => + col.set( + id, + this.client.actions.MessageDeleteBulk.getMessage( + { + message_id: id, + }, + this, + ), + ), + new Collection(), + ); + } + if (!isNaN(messages)) { + const msgs = await this.messages.fetch({ limit: messages }); + return this.bulkDelete(msgs, filterOld); + } + throw new DiscordjsTypeError(ErrorCodes.MessageBulkDeleteType); + } + + /** + * Fetches all webhooks for the channel. + * @returns {Promise<Collection<Snowflake, Webhook>>} + * @example + * // Fetch webhooks + * channel.fetchWebhooks() + * .then(hooks => console.log(`This channel has ${hooks.size} hooks`)) + * .catch(console.error); + */ + fetchWebhooks() { + return this.guild.channels.fetchWebhooks(this.id); + } + + /** + * Options used to create a {@link Webhook}. + * @typedef {Object} ChannelWebhookCreateOptions + * @property {string} name The name of the webhook + * @property {?(BufferResolvable|Base64Resolvable)} [avatar] Avatar for the webhook + * @property {string} [reason] Reason for creating the webhook + */ + + /** + * Creates a webhook for the channel. + * @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook + * @returns {Promise<Webhook>} Returns the created Webhook + * @example + * // Create a webhook for the current channel + * channel.createWebhook({ + * name: 'Snek', + * avatar: 'https://i.imgur.com/mI8XcpG.jpg', + * reason: 'Needed a cool new Webhook' + * }) + * .then(console.log) + * .catch(console.error) + */ + createWebhook(options) { + return this.guild.channels.createWebhook({ channel: this.id, ...options }); + } + + /** + * Sets the rate limit per user (slowmode) for this channel. + * @param {number} rateLimitPerUser The new rate limit in seconds + * @param {string} [reason] Reason for changing the channel's rate limit + * @returns {Promise<this>} + */ + setRateLimitPerUser(rateLimitPerUser, reason) { + return this.edit({ rateLimitPerUser, reason }); + } + + /** + * Sets whether this channel is flagged as NSFW. + * @param {boolean} [nsfw=true] Whether the channel should be considered NSFW + * @param {string} [reason] Reason for changing the channel's NSFW flag + * @returns {Promise<this>} + */ + setNSFW(nsfw = true, reason) { + return this.edit({ nsfw, reason }); + } + + static applyToClass(structure, full = false, ignore = []) { + const props = ['send']; + if (full) { + props.push( + 'lastMessage', + 'lastPinAt', + 'bulkDelete', + 'sendTyping', + 'createMessageCollector', + 'awaitMessages', + 'createMessageComponentCollector', + 'awaitMessageComponent', + 'fetchWebhooks', + 'createWebhook', + 'setRateLimitPerUser', + 'setNSFW', + ); + } + for (const prop of props) { + if (ignore.includes(prop)) continue; + Object.defineProperty( + structure.prototype, + prop, + Object.getOwnPropertyDescriptor(TextBasedChannel.prototype, prop), + ); + } + } +} + +module.exports = TextBasedChannel; + +// Fixes Circular +// eslint-disable-next-line import/order +const GuildMessageManager = require('../../managers/GuildMessageManager'); diff --git a/node_modules/discord.js/src/util/APITypes.js b/node_modules/discord.js/src/util/APITypes.js new file mode 100644 index 0000000..e8ab25a --- /dev/null +++ b/node_modules/discord.js/src/util/APITypes.js @@ -0,0 +1,476 @@ +/* eslint-disable max-len */ + +/** + * @external ActivityFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ActivityFlags} + */ + +/** + * @external ActivityType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ActivityType} + */ + +/** + * @external APIActionRowComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIActionRowComponent} + */ + +/** + * @external APIApplication + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIApplication} + */ + +/** + * @external APIApplicationCommand + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIApplicationCommand} + */ + +/** + * @external APIApplicationCommandOption + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIApplicationCommandOption} + */ + +/** + * @external APIAutoModerationAction + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIAutoModerationAction} + */ + +/** + * @external APIButtonComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIButtonComponent} + */ + +/** + * @external APIChannel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIChannel} + */ + +/** + * @external APIChannelSelectComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIChannelSelectComponent} + */ + +/** + * @external APIEmbed + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbed} + */ + +/** + * @external APIEmbedField + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbedField} + */ + +/** + * @external APIEmbedProvider + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbedProvider} + */ + +/** + * @external APIEmoji + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmoji} + */ + +/** + * @external APIGuild + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuild} + */ + +/** + * @external APIGuildForumDefaultReactionEmoji + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildForumDefaultReactionEmoji} + */ + +/** + * @external APIGuildForumTag + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildForumTag} + */ + +/** + * @external APIInteraction + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIInteraction} + */ + +/** + * @external APIInteractionDataResolvedChannel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionDataResolvedChannel} + */ + +/** + * @external APIInteractionDataResolvedGuildMember + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionDataResolvedGuildMember} + */ + +/** + * @external APIInteractionGuildMember + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionGuildMember} + */ + +/** + * @external APIMentionableSelectComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMentionableSelectComponent} + */ + +/** + * @external APIMessage + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessage} + */ + +/** + * @external APIMessageActionRowComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMessageActionRowComponent} + */ + +/** + * @external APIMessageComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMessageComponent} + */ + +/** + * @external APIMessageComponentEmoji + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessageComponentEmoji} + */ + +/** + * @external APIModalInteractionResponse + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponse} + */ + +/** + * @external APIModalInteractionResponseCallbackData + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponseCallbackData} + */ + +/** + * @external APIModalComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIModalComponent} + */ + +/** + * @external APIModalSubmission + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalSubmission} + */ + +/** + * @external APIPresence + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIPresence} + */ + +/** + * @external APIRoleSelectComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIRoleSelectComponent} + */ + +/** + * @external APISelectMenuOption + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuOption} + */ + +/** + * @external APIStringSelectComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIStringSelectComponent} + */ + +/** + * @external APITextInputComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APITextInputComponent} + */ + +/** + * @external APIUser + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIUser} + */ + +/** + * @external APIUserSelectComponent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIUserSelectComponent} + */ + +/** + * @external ApplicationCommandType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandType} + */ + +/** + * @external ApplicationCommandOptionType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandOptionType} + */ + +/** + * @external ApplicationCommandPermissionType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandPermissionType} + */ + +/** + * @external ApplicationFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationFlags} + */ + +/** + * @external ApplicationRoleConnectionMetadataType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationRoleConnectionMetadataType} + */ + +/** + * @external AttachmentFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AttachmentFlags} + */ + +/** + * @external AutoModerationActionType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationActionType} + */ + +/** + * @external AutoModerationRuleEventType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleEventType} + */ + +/** + * @external AutoModerationRuleTriggerType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleTriggerType} + */ + +/** + * @external AutoModerationRuleKeywordPresetType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleKeywordPresetType} + */ + +/** + * @external AuditLogEvent + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AuditLogEvent} + */ + +/** + * @external ButtonStyle + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ButtonStyle} + */ + +/** + * @external ChannelFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelFlags} + */ + +/** + * @external ChannelType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelType} + */ + +/** + * @external ComponentType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ComponentType} + */ + +/** + * @external ForumLayoutType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ForumLayoutType} + */ + +/** + * @external GatewayCloseCodes + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayCloseCodes} + */ + +/** + * @external GatewayDispatchEvents + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayDispatchEvents} + */ + +/** + * @external GatewayIntentBits + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayIntentBits} + */ + +/** + * @external GatewayOpcodes + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayOpcodes} + */ + +/** + * @external GuildDefaultMessageNotifications + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildDefaultMessageNotifications} + */ + +/** + * @external GuildExplicitContentFilter + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildExplicitContentFilter} + */ + +/** + * @external GuildFeature + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildFeature} + */ + +/** + * @external GuildMFALevel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildMFALevel} + */ + +/** + * @external GuildMemberFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildMemberFlags} + */ + +/** + * @external GuildNSFWLevel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildNSFWLevel} + */ + +/** + * @external GuildOnboardingPromptType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildOnboardingPromptType} + */ + +/** + * @external GuildPremiumTier + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildPremiumTier} + */ + +/** + * @external GuildScheduledEventEntityType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventEntityType} + */ + +/** + * @external GuildScheduledEventPrivacyLevel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventPrivacyLevel} + */ + +/** + * @external GuildScheduledEventStatus + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventStatus} + */ + +/** + * @external GuildSystemChannelFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildSystemChannelFlags} + */ + +/** + * @external GuildVerificationLevel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildVerificationLevel} + */ + +/** + * @external IntegrationExpireBehavior + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/IntegrationExpireBehavior} + */ + +/** + * @external InteractionType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionType} + */ + +/** + * @external InteractionResponseType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionResponseType} + */ + +/** + * @external InviteTargetType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InviteTargetType} + */ + +/** + * @external Locale + * @see {@link https://discord-api-types.dev/api/discord-api-types-rest/common/enum/Locale} + */ + +/** + * @external LocaleString + * @see {@link https://discord-api-types.dev/api/discord-api-types-rest/common#LocaleString} + */ + +/** + * @external MessageActivityType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageActivityType} + */ + +/** + * @external MessageType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageType} + */ + +/** + * @external MessageFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageFlags} + */ + +/** + * @external OAuth2Scopes + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/OAuth2Scopes} + */ + +/** + * @external OverwriteType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/OverwriteType} + */ + +/** + * @external PermissionFlagsBits + * @see {@link https://discord-api-types.dev/api/discord-api-types-payloads/common#PermissionFlagsBits} + */ + +/** + * @external RoleFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/RoleFlags} + */ + +/** + * @external RESTGetAPIGuildThreadsResult + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#RESTGetAPIGuildThreadsResult} + */ + +/** + * @external RESTJSONErrorCodes + * @see {@link https://discord-api-types.dev/api/discord-api-types-rest/common/enum/RESTJSONErrorCodes} + */ + +/** + * @external SortOrderType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/SortOrderType} + */ + +/** + * @external StageInstancePrivacyLevel + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/StageInstancePrivacyLevel} + */ + +/** + * @external StickerType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/StickerType} + */ + +/** + * @external StickerFormatType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/StickerFormatType} + */ + +/** + * @external TeamMemberMembershipState + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/TeamMemberMembershipState} + */ + +/** + * @external TextInputStyle + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/TextInputStyle} + */ + +/** + * @external ThreadAutoArchiveDuration + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ThreadAutoArchiveDuration} + */ + +/** + * @external UserFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/UserFlags} + */ + +/** + * @external VideoQualityMode + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/VideoQualityMode} + */ + +/** + * @external WebhookType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/WebhookType} + */ diff --git a/node_modules/discord.js/src/util/ActivityFlagsBitField.js b/node_modules/discord.js/src/util/ActivityFlagsBitField.js new file mode 100644 index 0000000..7c0ef76 --- /dev/null +++ b/node_modules/discord.js/src/util/ActivityFlagsBitField.js @@ -0,0 +1,26 @@ +'use strict'; + +const { ActivityFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with an {@link Activity#flags} bitfield. + * @extends {BitField} + */ +class ActivityFlagsBitField extends BitField { + /** + * Numeric activity flags. + * @type {ActivityFlags} + * @memberof ActivityFlagsBitField + */ + static Flags = ActivityFlags; +} + +/** + * @name ActivityFlagsBitField + * @kind constructor + * @memberof ActivityFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +module.exports = ActivityFlagsBitField; diff --git a/node_modules/discord.js/src/util/ApplicationFlagsBitField.js b/node_modules/discord.js/src/util/ApplicationFlagsBitField.js new file mode 100644 index 0000000..6a5a9fe --- /dev/null +++ b/node_modules/discord.js/src/util/ApplicationFlagsBitField.js @@ -0,0 +1,26 @@ +'use strict'; + +const { ApplicationFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link ClientApplication#flags} bitfield. + * @extends {BitField} + */ +class ApplicationFlagsBitField extends BitField { + /** + * Numeric application flags. All available properties: + * @type {ApplicationFlags} + * @memberof ApplicationFlagsBitField + */ + static Flags = ApplicationFlags; +} + +/** + * @name ApplicationFlagsBitField + * @kind constructor + * @memberof ApplicationFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +module.exports = ApplicationFlagsBitField; diff --git a/node_modules/discord.js/src/util/AttachmentFlagsBitField.js b/node_modules/discord.js/src/util/AttachmentFlagsBitField.js new file mode 100644 index 0000000..f7f2bd2 --- /dev/null +++ b/node_modules/discord.js/src/util/AttachmentFlagsBitField.js @@ -0,0 +1,26 @@ +'use strict'; + +const { AttachmentFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with an {@link Attachment#flags} bitfield. + * @extends {BitField} + */ +class AttachmentFlagsBitField extends BitField { + /** + * Numeric attachment flags. + * @type {AttachmentFlags} + * @memberof AttachmentFlagsBitField + */ + static Flags = AttachmentFlags; +} + +/** + * @name AttachmentFlagsBitField + * @kind constructor + * @memberof AttachmentFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +module.exports = AttachmentFlagsBitField; diff --git a/node_modules/discord.js/src/util/BitField.js b/node_modules/discord.js/src/util/BitField.js new file mode 100644 index 0000000..f0778f6 --- /dev/null +++ b/node_modules/discord.js/src/util/BitField.js @@ -0,0 +1,176 @@ +'use strict'; + +const { DiscordjsRangeError, ErrorCodes } = require('../errors'); + +/** + * Data structure that makes it easy to interact with a bitfield. + */ +class BitField { + /** + * Numeric bitfield flags. + * <info>Defined in extension classes</info> + * @type {Object} + * @memberof BitField + * @abstract + */ + static Flags = {}; + + /** + * @type {number|bigint} + * @memberof BitField + * @private + */ + static DefaultBit = 0; + + /** + * @param {BitFieldResolvable} [bits=this.constructor.DefaultBit] Bit(s) to read from + */ + constructor(bits = this.constructor.DefaultBit) { + /** + * Bitfield of the packed bits + * @type {number|bigint} + */ + this.bitfield = this.constructor.resolve(bits); + } + + /** + * Checks whether the bitfield has a bit, or any of multiple bits. + * @param {BitFieldResolvable} bit Bit(s) to check for + * @returns {boolean} + */ + any(bit) { + return (this.bitfield & this.constructor.resolve(bit)) !== this.constructor.DefaultBit; + } + + /** + * Checks if this bitfield equals another + * @param {BitFieldResolvable} bit Bit(s) to check for + * @returns {boolean} + */ + equals(bit) { + return this.bitfield === this.constructor.resolve(bit); + } + + /** + * Checks whether the bitfield has a bit, or multiple bits. + * @param {BitFieldResolvable} bit Bit(s) to check for + * @returns {boolean} + */ + has(bit) { + bit = this.constructor.resolve(bit); + return (this.bitfield & bit) === bit; + } + + /** + * Gets all given bits that are missing from the bitfield. + * @param {BitFieldResolvable} bits Bit(s) to check for + * @param {...*} hasParams Additional parameters for the has method, if any + * @returns {string[]} + */ + missing(bits, ...hasParams) { + return new this.constructor(bits).remove(this).toArray(...hasParams); + } + + /** + * Freezes these bits, making them immutable. + * @returns {Readonly<BitField>} + */ + freeze() { + return Object.freeze(this); + } + + /** + * Adds bits to these ones. + * @param {...BitFieldResolvable} [bits] Bits to add + * @returns {BitField} These bits or new BitField if the instance is frozen. + */ + add(...bits) { + let total = this.constructor.DefaultBit; + for (const bit of bits) { + total |= this.constructor.resolve(bit); + } + if (Object.isFrozen(this)) return new this.constructor(this.bitfield | total); + this.bitfield |= total; + return this; + } + + /** + * Removes bits from these. + * @param {...BitFieldResolvable} [bits] Bits to remove + * @returns {BitField} These bits or new BitField if the instance is frozen. + */ + remove(...bits) { + let total = this.constructor.DefaultBit; + for (const bit of bits) { + total |= this.constructor.resolve(bit); + } + if (Object.isFrozen(this)) return new this.constructor(this.bitfield & ~total); + this.bitfield &= ~total; + return this; + } + + /** + * Gets an object mapping field names to a {@link boolean} indicating whether the + * bit is available. + * @param {...*} hasParams Additional parameters for the has method, if any + * @returns {Object} + */ + serialize(...hasParams) { + const serialized = {}; + for (const [flag, bit] of Object.entries(this.constructor.Flags)) { + if (isNaN(flag)) serialized[flag] = this.has(bit, ...hasParams); + } + return serialized; + } + + /** + * Gets an {@link Array} of bitfield names based on the bits available. + * @param {...*} hasParams Additional parameters for the has method, if any + * @returns {string[]} + */ + toArray(...hasParams) { + return [...this[Symbol.iterator](...hasParams)]; + } + + toJSON() { + return typeof this.bitfield === 'number' ? this.bitfield : this.bitfield.toString(); + } + + valueOf() { + return this.bitfield; + } + + *[Symbol.iterator](...hasParams) { + for (const bitName of Object.keys(this.constructor.Flags)) { + if (isNaN(bitName) && this.has(bitName, ...hasParams)) yield bitName; + } + } + + /** + * Data that can be resolved to give a bitfield. This can be: + * * A bit number (this can be a number literal or a value taken from {@link BitField.Flags}) + * * A string bit number + * * An instance of BitField + * * An Array of BitFieldResolvable + * @typedef {number|string|bigint|BitField|BitFieldResolvable[]} BitFieldResolvable + */ + + /** + * Resolves bitfields to their numeric form. + * @param {BitFieldResolvable} [bit] bit(s) to resolve + * @returns {number|bigint} + */ + static resolve(bit) { + const { DefaultBit } = this; + if (typeof DefaultBit === typeof bit && bit >= DefaultBit) return bit; + if (bit instanceof BitField) return bit.bitfield; + if (Array.isArray(bit)) return bit.map(p => this.resolve(p)).reduce((prev, p) => prev | p, DefaultBit); + if (typeof bit === 'string') { + if (!isNaN(bit)) return typeof DefaultBit === 'bigint' ? BigInt(bit) : Number(bit); + if (this.Flags[bit] !== undefined) return this.Flags[bit]; + } + throw new DiscordjsRangeError(ErrorCodes.BitFieldInvalid, bit); + } +} + +module.exports = BitField; diff --git a/node_modules/discord.js/src/util/ChannelFlagsBitField.js b/node_modules/discord.js/src/util/ChannelFlagsBitField.js new file mode 100644 index 0000000..ad987e1 --- /dev/null +++ b/node_modules/discord.js/src/util/ChannelFlagsBitField.js @@ -0,0 +1,41 @@ +'use strict'; + +const { ChannelFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link BaseChannel#flags} bitfield. + * @extends {BitField} + */ +class ChannelFlagsBitField extends BitField { + /** + * Numeric guild channel flags. + * @type {ChannelFlags} + * @memberof ChannelFlagsBitField + */ + static Flags = ChannelFlags; +} + +/** + * @name ChannelFlagsBitField + * @kind constructor + * @memberof ChannelFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name ChannelFlagsBitField#bitfield + */ + +/** + * Data that can be resolved to give a channel flag bitfield. This can be: + * * A string (see {@link ChannelFlagsBitField.Flags}) + * * A channel flag + * * An instance of ChannelFlagsBitField + * * An Array of ChannelFlagsResolvable + * @typedef {string|number|ChannelFlagsBitField|ChannelFlagsResolvable[]} ChannelFlagsResolvable + */ + +module.exports = ChannelFlagsBitField; diff --git a/node_modules/discord.js/src/util/Channels.js b/node_modules/discord.js/src/util/Channels.js new file mode 100644 index 0000000..8d070bd --- /dev/null +++ b/node_modules/discord.js/src/util/Channels.js @@ -0,0 +1,150 @@ +'use strict'; + +const { lazy } = require('@discordjs/util'); +const { ChannelType } = require('discord-api-types/v10'); + +const getCategoryChannel = lazy(() => require('../structures/CategoryChannel')); +const getDMChannel = lazy(() => require('../structures/DMChannel')); +const getNewsChannel = lazy(() => require('../structures/NewsChannel')); +const getStageChannel = lazy(() => require('../structures/StageChannel')); +const getTextChannel = lazy(() => require('../structures/TextChannel')); +const getThreadChannel = lazy(() => require('../structures/ThreadChannel')); +const getVoiceChannel = lazy(() => require('../structures/VoiceChannel')); +const getDirectoryChannel = lazy(() => require('../structures/DirectoryChannel')); +const getPartialGroupDMChannel = lazy(() => require('../structures/PartialGroupDMChannel')); +const getForumChannel = lazy(() => require('../structures/ForumChannel')); + +/** + * Creates a discord.js channel from data received from the API. + * @param {Client} client The client + * @param {APIChannel} data The data of the channel to create + * @param {Guild} [guild] The guild where this channel belongs + * @param {Object} [extras] Extra information to supply for creating this channel + * @returns {BaseChannel} Any kind of channel. + * @ignore + */ +function createChannel(client, data, guild, { allowUnknownGuild } = {}) { + let channel; + if (!data.guild_id && !guild) { + if ((data.recipients && data.type !== ChannelType.GroupDM) || data.type === ChannelType.DM) { + channel = new (getDMChannel())(client, data); + } else if (data.type === ChannelType.GroupDM) { + channel = new (getPartialGroupDMChannel())(client, data); + } + } else { + guild ??= client.guilds.cache.get(data.guild_id); + + if (guild || allowUnknownGuild) { + switch (data.type) { + case ChannelType.GuildText: { + channel = new (getTextChannel())(guild, data, client); + break; + } + case ChannelType.GuildVoice: { + channel = new (getVoiceChannel())(guild, data, client); + break; + } + case ChannelType.GuildCategory: { + channel = new (getCategoryChannel())(guild, data, client); + break; + } + case ChannelType.GuildAnnouncement: { + channel = new (getNewsChannel())(guild, data, client); + break; + } + case ChannelType.GuildStageVoice: { + channel = new (getStageChannel())(guild, data, client); + break; + } + case ChannelType.AnnouncementThread: + case ChannelType.PublicThread: + case ChannelType.PrivateThread: { + channel = new (getThreadChannel())(guild, data, client); + if (!allowUnknownGuild) channel.parent?.threads.cache.set(channel.id, channel); + break; + } + case ChannelType.GuildDirectory: + channel = new (getDirectoryChannel())(guild, data, client); + break; + case ChannelType.GuildForum: + channel = new (getForumChannel())(guild, data, client); + break; + } + if (channel && !allowUnknownGuild) guild.channels?.cache.set(channel.id, channel); + } + } + return channel; +} + +/** + * Transforms an API guild forum tag to camel-cased guild forum tag. + * @param {APIGuildForumTag} tag The tag to transform + * @returns {GuildForumTag} + * @ignore + */ +function transformAPIGuildForumTag(tag) { + return { + id: tag.id, + name: tag.name, + moderated: tag.moderated, + emoji: + tag.emoji_id ?? tag.emoji_name + ? { + id: tag.emoji_id, + name: tag.emoji_name, + } + : null, + }; +} + +/** + * Transforms a camel-cased guild forum tag to an API guild forum tag. + * @param {GuildForumTag} tag The tag to transform + * @returns {APIGuildForumTag} + * @ignore + */ +function transformGuildForumTag(tag) { + return { + id: tag.id, + name: tag.name, + moderated: tag.moderated, + emoji_id: tag.emoji?.id ?? null, + emoji_name: tag.emoji?.name ?? null, + }; +} + +/** + * Transforms an API guild forum default reaction object to a + * camel-cased guild forum default reaction object. + * @param {APIGuildForumDefaultReactionEmoji} defaultReaction The default reaction to transform + * @returns {DefaultReactionEmoji} + * @ignore + */ +function transformAPIGuildDefaultReaction(defaultReaction) { + return { + id: defaultReaction.emoji_id, + name: defaultReaction.emoji_name, + }; +} + +/** + * Transforms a camel-cased guild forum default reaction object to an + * API guild forum default reaction object. + * @param {DefaultReactionEmoji} defaultReaction The default reaction to transform + * @returns {APIGuildForumDefaultReactionEmoji} + * @ignore + */ +function transformGuildDefaultReaction(defaultReaction) { + return { + emoji_id: defaultReaction.id, + emoji_name: defaultReaction.name, + }; +} + +module.exports = { + createChannel, + transformAPIGuildForumTag, + transformGuildForumTag, + transformAPIGuildDefaultReaction, + transformGuildDefaultReaction, +}; diff --git a/node_modules/discord.js/src/util/Colors.js b/node_modules/discord.js/src/util/Colors.js new file mode 100644 index 0000000..a2d35e5 --- /dev/null +++ b/node_modules/discord.js/src/util/Colors.js @@ -0,0 +1,73 @@ +'use strict'; + +/** + * @typedef {Object} Colors + * @property {number} Default 0x000000 | rgb(0,0,0) + * @property {number} White 0xFFFFFF | rgb(255,255,255) + * @property {number} Aqua 0x1ABC9C | rgb(26,188,156) + * @property {number} Green 0x57F287 | rgb(87,242,135) + * @property {number} Blue 0x3498DB | rgb(52,152,219) + * @property {number} Yellow 0xFEE75C | rgb(254,231,92) + * @property {number} Purple 0x9B59B6 | rgb(155,89,182) + * @property {number} LuminousVividPink 0xE91E63 | rgb(233,30,99) + * @property {number} Fuchsia 0xEB459E | rgb(235,69,158) + * @property {number} Gold 0xF1C40F | rgb(241,196,15) + * @property {number} Orange 0xE67E22 | rgb(230,126,34) + * @property {number} Red 0xED4245 | rgb(237,66,69) + * @property {number} Grey 0x95A5A6 | rgb(149,165,166) + * @property {number} Navy 0x34495E | rgb(52,73,94) + * @property {number} DarkAqua 0x11806A | rgb(17,128,106) + * @property {number} DarkGreen 0x1F8B4C | rgb(31,139,76) + * @property {number} DarkBlue 0x206694 | rgb(32,102,148) + * @property {number} DarkPurple 0x71368A | rgb(113,54,138) + * @property {number} DarkVividPink 0xAD1457 | rgb(173,20,87) + * @property {number} DarkGold 0xC27C0E | rgb(194,124,14) + * @property {number} DarkOrange 0xA84300 | rgb(168,67,0) + * @property {number} DarkRed 0x992D22 | rgb(153,45,34) + * @property {number} DarkGrey 0x979C9F | rgb(151,156,159) + * @property {number} DarkerGrey 0x7F8C8D | rgb(127,140,141) + * @property {number} LightGrey 0xBCC0C0 | rgb(188,192,192) + * @property {number} DarkNavy 0x2C3E50 | rgb(44,62,80) + * @property {number} Blurple 0x5865F2 | rgb(88,101,242) + * @property {number} Greyple 0x99AAb5 | rgb(153,170,181) + * @property {number} DarkButNotBlack 0x2C2F33 | rgb(44,47,51) + * @property {number} NotQuiteBlack 0x23272A | rgb(35,39,42) + */ + +// JSDoc for IntelliSense purposes +/** + * @type {Colors} + * @ignore + */ +module.exports = { + Default: 0x000000, + White: 0xffffff, + Aqua: 0x1abc9c, + Green: 0x57f287, + Blue: 0x3498db, + Yellow: 0xfee75c, + Purple: 0x9b59b6, + LuminousVividPink: 0xe91e63, + Fuchsia: 0xeb459e, + Gold: 0xf1c40f, + Orange: 0xe67e22, + Red: 0xed4245, + Grey: 0x95a5a6, + Navy: 0x34495e, + DarkAqua: 0x11806a, + DarkGreen: 0x1f8b4c, + DarkBlue: 0x206694, + DarkPurple: 0x71368a, + DarkVividPink: 0xad1457, + DarkGold: 0xc27c0e, + DarkOrange: 0xa84300, + DarkRed: 0x992d22, + DarkGrey: 0x979c9f, + DarkerGrey: 0x7f8c8d, + LightGrey: 0xbcc0c0, + DarkNavy: 0x2c3e50, + Blurple: 0x5865f2, + Greyple: 0x99aab5, + DarkButNotBlack: 0x2c2f33, + NotQuiteBlack: 0x23272a, +}; diff --git a/node_modules/discord.js/src/util/Components.js b/node_modules/discord.js/src/util/Components.js new file mode 100644 index 0000000..1a2ccbc --- /dev/null +++ b/node_modules/discord.js/src/util/Components.js @@ -0,0 +1,152 @@ +'use strict'; + +// This file contains the typedefs for camel-cased JSON data +const { ComponentBuilder } = require('@discordjs/builders'); +const { ComponentType } = require('discord-api-types/v10'); +/** + * @typedef {Object} BaseComponentData + * @property {ComponentType} type The type of component + */ + +/** + * @typedef {BaseComponentData} ActionRowData + * @property {ComponentData[]} components The components in this action row + */ + +/** + * @typedef {BaseComponentData} ButtonComponentData + * @property {ButtonStyle} style The style of the button + * @property {?boolean} disabled Whether this button is disabled + * @property {string} label The label of this button + * @property {?APIMessageComponentEmoji} emoji The emoji on this button + * @property {?string} customId The custom id of the button + * @property {?string} url The URL of the button + */ + +/** + * @typedef {object} SelectMenuComponentOptionData + * @property {string} label The label of the option + * @property {string} value The value of the option + * @property {?string} description The description of the option + * @property {?APIMessageComponentEmoji} emoji The emoji on the option + * @property {?boolean} default Whether this option is selected by default + */ + +/** + * @typedef {BaseComponentData} SelectMenuComponentData + * @property {string} customId The custom id of the select menu + * @property {?boolean} disabled Whether the select menu is disabled or not + * @property {?number} maxValues The maximum amount of options that can be selected + * @property {?number} minValues The minimum amount of options that can be selected + * @property {?SelectMenuComponentOptionData[]} options The options in this select menu + * @property {?string} placeholder The placeholder of the select menu + */ + +/** + * @typedef {ActionRowData|ButtonComponentData|SelectMenuComponentData} MessageComponentData + */ + +/** + * @typedef {BaseComponentData} TextInputComponentData + * @property {string} customId The custom id of the text input + * @property {TextInputStyle} style The style of the text input + * @property {string} label The text that appears on top of the text input field + * @property {?number} minLength The minimum number of characters that can be entered in the text input + * @property {?number} maxLength The maximum number of characters that can be entered in the text input + * @property {?boolean} required Whether or not the text input is required or not + * @property {?string} value The pre-filled text in the text input + * @property {?string} placeholder Placeholder for the text input + */ + +/** + * @typedef {ActionRowData|ButtonComponentData|SelectMenuComponentData|TextInputComponentData} ComponentData + */ + +/** + * Any emoji data that can be used within a button + * @typedef {APIMessageComponentEmoji|string} ComponentEmojiResolvable + */ + +/** + * Transforms API data into a component + * @param {APIMessageComponent|Component} data The data to create the component from + * @returns {Component} + */ +function createComponent(data) { + if (data instanceof Component) { + return data; + } + + switch (data.type) { + case ComponentType.ActionRow: + return new ActionRow(data); + case ComponentType.Button: + return new ButtonComponent(data); + case ComponentType.StringSelect: + return new StringSelectMenuComponent(data); + case ComponentType.TextInput: + return new TextInputComponent(data); + case ComponentType.UserSelect: + return new UserSelectMenuComponent(data); + case ComponentType.RoleSelect: + return new RoleSelectMenuComponent(data); + case ComponentType.MentionableSelect: + return new MentionableSelectMenuComponent(data); + case ComponentType.ChannelSelect: + return new ChannelSelectMenuComponent(data); + default: + return new Component(data); + } +} + +/** + * Transforms API data into a component builder + * @param {APIMessageComponent|ComponentBuilder} data The data to create the component from + * @returns {ComponentBuilder} + */ +function createComponentBuilder(data) { + if (data instanceof ComponentBuilder) { + return data; + } + + switch (data.type) { + case ComponentType.ActionRow: + return new ActionRowBuilder(data); + case ComponentType.Button: + return new ButtonBuilder(data); + case ComponentType.StringSelect: + return new StringSelectMenuBuilder(data); + case ComponentType.TextInput: + return new TextInputBuilder(data); + case ComponentType.UserSelect: + return new UserSelectMenuBuilder(data); + case ComponentType.RoleSelect: + return new RoleSelectMenuBuilder(data); + case ComponentType.MentionableSelect: + return new MentionableSelectMenuBuilder(data); + case ComponentType.ChannelSelect: + return new ChannelSelectMenuBuilder(data); + default: + return new ComponentBuilder(data); + } +} + +module.exports = { createComponent, createComponentBuilder }; + +const ActionRow = require('../structures/ActionRow'); +const ActionRowBuilder = require('../structures/ActionRowBuilder'); +const ButtonBuilder = require('../structures/ButtonBuilder'); +const ButtonComponent = require('../structures/ButtonComponent'); +const ChannelSelectMenuBuilder = require('../structures/ChannelSelectMenuBuilder'); +const ChannelSelectMenuComponent = require('../structures/ChannelSelectMenuComponent'); +const Component = require('../structures/Component'); +const MentionableSelectMenuBuilder = require('../structures/MentionableSelectMenuBuilder'); +const MentionableSelectMenuComponent = require('../structures/MentionableSelectMenuComponent'); +const RoleSelectMenuBuilder = require('../structures/RoleSelectMenuBuilder'); +const RoleSelectMenuComponent = require('../structures/RoleSelectMenuComponent'); +const StringSelectMenuBuilder = require('../structures/StringSelectMenuBuilder'); +const StringSelectMenuComponent = require('../structures/StringSelectMenuComponent'); +const TextInputBuilder = require('../structures/TextInputBuilder'); +const TextInputComponent = require('../structures/TextInputComponent'); +const UserSelectMenuBuilder = require('../structures/UserSelectMenuBuilder'); +const UserSelectMenuComponent = require('../structures/UserSelectMenuComponent'); diff --git a/node_modules/discord.js/src/util/Constants.js b/node_modules/discord.js/src/util/Constants.js new file mode 100644 index 0000000..c2d3da9 --- /dev/null +++ b/node_modules/discord.js/src/util/Constants.js @@ -0,0 +1,230 @@ +'use strict'; + +const { ChannelType, MessageType, ComponentType, ImageFormat, StickerFormatType } = require('discord-api-types/v10'); + +/** + * Max bulk deletable message age + * @typedef {number} MaxBulkDeletableMessageAge + */ +exports.MaxBulkDeletableMessageAge = 1_209_600_000; + +/** + * The name of an item to be swept in Sweepers + * * `autoModerationRules` + * * `applicationCommands` - both global and guild commands + * * `bans` + * * `emojis` + * * `invites` - accepts the `lifetime` property, using it will sweep based on expires timestamp + * * `guildMembers` + * * `messages` - accepts the `lifetime` property, using it will sweep based on edited or created timestamp + * * `presences` + * * `reactions` + * * `stageInstances` + * * `stickers` + * * `threadMembers` + * * `threads` - accepts the `lifetime` property, using it will sweep archived threads based on archived timestamp + * * `users` + * * `voiceStates` + * @typedef {string} SweeperKey + */ +exports.SweeperKeys = [ + 'autoModerationRules', + 'applicationCommands', + 'bans', + 'emojis', + 'invites', + 'guildMembers', + 'messages', + 'presences', + 'reactions', + 'stageInstances', + 'stickers', + 'threadMembers', + 'threads', + 'users', + 'voiceStates', +]; + +/** + * The types of messages that are not `System`. The available types are: + * * {@link MessageType.Default} + * * {@link MessageType.Reply} + * * {@link MessageType.ChatInputCommand} + * * {@link MessageType.ContextMenuCommand} + * @typedef {MessageType[]} NonSystemMessageTypes + */ +exports.NonSystemMessageTypes = [ + MessageType.Default, + MessageType.Reply, + MessageType.ChatInputCommand, + MessageType.ContextMenuCommand, +]; + +/** + * The guild channels that are text-based. + * * TextChannel + * * NewsChannel + * * ThreadChannel + * * VoiceChannel + * * StageChannel + * @typedef {TextChannel|NewsChannel|ThreadChannel|VoiceChannel|StageChannel} GuildTextBasedChannel + */ + +/** + * The types of guild channels that are text-based. The available types are: + * * {@link ChannelType.GuildText} + * * {@link ChannelType.GuildAnnouncement} + * * {@link ChannelType.AnnouncementThread} + * * {@link ChannelType.PublicThread} + * * {@link ChannelType.PrivateThread} + * * {@link ChannelType.GuildVoice} + * * {@link ChannelType.GuildStageVoice} + * @typedef {ChannelType[]} GuildTextBasedChannelTypes + */ +exports.GuildTextBasedChannelTypes = [ + ChannelType.GuildText, + ChannelType.GuildAnnouncement, + ChannelType.AnnouncementThread, + ChannelType.PublicThread, + ChannelType.PrivateThread, + ChannelType.GuildVoice, + ChannelType.GuildStageVoice, +]; + +/** + * The channels that are text-based. + * * DMChannel + * * GuildTextBasedChannel + * @typedef {DMChannel|GuildTextBasedChannel} TextBasedChannels + */ + +/** + * Data that resolves to give a text-based channel. This can be: + * * A text-based channel + * * A snowflake + * @typedef {TextBasedChannels|Snowflake} TextBasedChannelsResolvable + */ + +/** + * The types of channels that are text-based. The available types are: + * * {@link ChannelType.DM} + * * {@link ChannelType.GuildText} + * * {@link ChannelType.GuildAnnouncement} + * * {@link ChannelType.AnnouncementThread} + * * {@link ChannelType.PublicThread} + * * {@link ChannelType.PrivateThread} + * * {@link ChannelType.GuildVoice} + * * {@link ChannelType.GuildStageVoice} + * @typedef {ChannelType[]} TextBasedChannelTypes + */ +exports.TextBasedChannelTypes = [...exports.GuildTextBasedChannelTypes, ChannelType.DM]; + +/** + * The types of channels that are threads. The available types are: + * * {@link ChannelType.AnnouncementThread} + * * {@link ChannelType.PublicThread} + * * {@link ChannelType.PrivateThread} + * @typedef {ChannelType[]} ThreadChannelTypes + */ +exports.ThreadChannelTypes = [ChannelType.AnnouncementThread, ChannelType.PublicThread, ChannelType.PrivateThread]; + +/** + * The types of channels that are voice-based. The available types are: + * * {@link ChannelType.GuildVoice} + * * {@link ChannelType.GuildStageVoice} + * @typedef {ChannelType[]} VoiceBasedChannelTypes + */ +exports.VoiceBasedChannelTypes = [ChannelType.GuildVoice, ChannelType.GuildStageVoice]; + +/** + * The types of select menus. The available types are: + * * {@link ComponentType.StringSelect} + * * {@link ComponentType.UserSelect} + * * {@link ComponentType.RoleSelect} + * * {@link ComponentType.MentionableSelect} + * * {@link ComponentType.ChannelSelect} + * @typedef {ComponentType[]} SelectMenuTypes + */ +exports.SelectMenuTypes = [ + ComponentType.StringSelect, + ComponentType.UserSelect, + ComponentType.RoleSelect, + ComponentType.MentionableSelect, + ComponentType.ChannelSelect, +]; + +/** + * The types of messages that can be deleted. The available types are: + * * {@link MessageType.AutoModerationAction} + * * {@link MessageType.ChannelFollowAdd} + * * {@link MessageType.ChannelPinnedMessage} + * * {@link MessageType.ChatInputCommand} + * * {@link MessageType.ContextMenuCommand} + * * {@link MessageType.Default} + * * {@link MessageType.GuildBoost} + * * {@link MessageType.GuildBoostTier1} + * * {@link MessageType.GuildBoostTier2} + * * {@link MessageType.GuildBoostTier3} + * * {@link MessageType.GuildInviteReminder} + * * {@link MessageType.InteractionPremiumUpsell} + * * {@link MessageType.Reply} + * * {@link MessageType.RoleSubscriptionPurchase} + * * {@link MessageType.StageEnd} + * * {@link MessageType.StageRaiseHand} + * * {@link MessageType.StageSpeaker} + * * {@link MessageType.StageStart} + * * {@link MessageType.StageTopic} + * * {@link MessageType.ThreadCreated} + * * {@link MessageType.UserJoin} + * @typedef {MessageType[]} DeletableMessageTypes + */ +exports.DeletableMessageTypes = [ + MessageType.AutoModerationAction, + MessageType.ChannelFollowAdd, + MessageType.ChannelPinnedMessage, + MessageType.ChatInputCommand, + MessageType.ContextMenuCommand, + MessageType.Default, + MessageType.GuildBoost, + MessageType.GuildBoostTier1, + MessageType.GuildBoostTier2, + MessageType.GuildBoostTier3, + MessageType.GuildInviteReminder, + MessageType.InteractionPremiumUpsell, + MessageType.Reply, + MessageType.RoleSubscriptionPurchase, + MessageType.StageEnd, + MessageType.StageRaiseHand, + MessageType.StageSpeaker, + MessageType.StageStart, + MessageType.StageTopic, + MessageType.ThreadCreated, + MessageType.UserJoin, +]; + +/** + * A mapping between sticker formats and their respective image formats. + * * {@link StickerFormatType.PNG} -> {@link ImageFormat.PNG} + * * {@link StickerFormatType.APNG} -> {@link ImageFormat.PNG} + * * {@link StickerFormatType.Lottie} -> {@link ImageFormat.Lottie} + * * {@link StickerFormatType.GIF} -> {@link ImageFormat.GIF} + * @typedef {Object} StickerFormatExtensionMap + */ +exports.StickerFormatExtensionMap = { + [StickerFormatType.PNG]: ImageFormat.PNG, + [StickerFormatType.APNG]: ImageFormat.PNG, + [StickerFormatType.Lottie]: ImageFormat.Lottie, + [StickerFormatType.GIF]: ImageFormat.GIF, +}; + +/** + * @typedef {Object} Constants Constants that can be used in an enum or object-like way. + * @property {number} MaxBulkDeletableMessageAge Max bulk deletable message age + * @property {SweeperKey[]} SweeperKeys The possible names of items that can be swept in sweepers + * @property {NonSystemMessageTypes} NonSystemMessageTypes The types of messages that are not deemed a system type + * @property {TextBasedChannelTypes} TextBasedChannelTypes The types of channels that are text-based + * @property {ThreadChannelTypes} ThreadChannelTypes The types of channels that are threads + * @property {VoiceBasedChannelTypes} VoiceBasedChannelTypes The types of channels that are voice-based + * @property {SelectMenuTypes} SelectMenuTypes The types of components that are select menus. + * @property {Object} StickerFormatExtensionMap A mapping between sticker formats and their respective image formats. + */ diff --git a/node_modules/discord.js/src/util/DataResolver.js b/node_modules/discord.js/src/util/DataResolver.js new file mode 100644 index 0000000..6b8a64c --- /dev/null +++ b/node_modules/discord.js/src/util/DataResolver.js @@ -0,0 +1,140 @@ +'use strict'; + +const { Buffer } = require('node:buffer'); +const fs = require('node:fs/promises'); +const path = require('node:path'); +const { fetch } = require('undici'); +const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors'); +const Invite = require('../structures/Invite'); + +/** + * The DataResolver identifies different objects and tries to resolve a specific piece of information from them. + * @private + */ +class DataResolver extends null { + /** + * Data that can be resolved to give an invite code. This can be: + * * An invite code + * * An invite URL + * @typedef {string} InviteResolvable + */ + + /** + * Data that can be resolved to give a template code. This can be: + * * A template code + * * A template URL + * @typedef {string} GuildTemplateResolvable + */ + + /** + * Resolves the string to a code based on the passed regex. + * @param {string} data The string to resolve + * @param {RegExp} regex The RegExp used to extract the code + * @returns {string} + */ + static resolveCode(data, regex) { + return regex.exec(data)?.[1] ?? data; + } + + /** + * Resolves InviteResolvable to an invite code. + * @param {InviteResolvable} data The invite resolvable to resolve + * @returns {string} + */ + static resolveInviteCode(data) { + return this.resolveCode(data, Invite.InvitesPattern); + } + + /** + * Resolves GuildTemplateResolvable to a template code. + * @param {GuildTemplateResolvable} data The template resolvable to resolve + * @returns {string} + */ + static resolveGuildTemplateCode(data) { + const GuildTemplate = require('../structures/GuildTemplate'); + return this.resolveCode(data, GuildTemplate.GuildTemplatesPattern); + } + + /** + * Resolves a Base64Resolvable, a string, or a BufferResolvable to a Base 64 image. + * @param {BufferResolvable|Base64Resolvable} image The image to be resolved + * @returns {Promise<?string>} + */ + static async resolveImage(image) { + if (!image) return null; + if (typeof image === 'string' && image.startsWith('data:')) { + return image; + } + const file = await this.resolveFile(image); + return this.resolveBase64(file.data); + } + + /** + * Data that resolves to give a Base64 string, typically for image uploading. This can be: + * * A Buffer + * * A base64 string + * @typedef {Buffer|string} Base64Resolvable + */ + + /** + * Resolves a Base64Resolvable to a Base 64 image. + * @param {Base64Resolvable} data The base 64 resolvable you want to resolve + * @returns {?string} + */ + static resolveBase64(data) { + if (Buffer.isBuffer(data)) return `data:image/jpg;base64,${data.toString('base64')}`; + return data; + } + + /** + * Data that can be resolved to give a Buffer. This can be: + * * A Buffer + * * The path to a local file + * * A URL <warn>When provided a URL, discord.js will fetch the URL internally in order to create a Buffer. + * This can pose a security risk when the URL has not been sanitized</warn> + * @typedef {string|Buffer} BufferResolvable + */ + + /** + * @external Stream + * @see {@link https://nodejs.org/api/stream.html} + */ + + /** + * @typedef {Object} ResolvedFile + * @property {Buffer} data Buffer containing the file data + * @property {string} [contentType] Content type of the file + */ + + /** + * Resolves a BufferResolvable to a Buffer. + * @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve + * @returns {Promise<ResolvedFile>} + */ + static async resolveFile(resource) { + if (Buffer.isBuffer(resource)) return { data: resource }; + + if (typeof resource[Symbol.asyncIterator] === 'function') { + const buffers = []; + for await (const data of resource) buffers.push(Buffer.from(data)); + return { data: Buffer.concat(buffers) }; + } + + if (typeof resource === 'string') { + if (/^https?:\/\//.test(resource)) { + const res = await fetch(resource); + return { data: Buffer.from(await res.arrayBuffer()), contentType: res.headers.get('content-type') }; + } + + const file = path.resolve(resource); + + const stats = await fs.stat(file); + if (!stats.isFile()) throw new DiscordjsError(ErrorCodes.FileNotFound, file); + return { data: await fs.readFile(file) }; + } + + throw new DiscordjsTypeError(ErrorCodes.ReqResourceType); + } +} + +module.exports = DataResolver; diff --git a/node_modules/discord.js/src/util/Enums.js b/node_modules/discord.js/src/util/Enums.js new file mode 100644 index 0000000..e3e5cac --- /dev/null +++ b/node_modules/discord.js/src/util/Enums.js @@ -0,0 +1,13 @@ +'use strict'; + +function createEnum(keys) { + const obj = {}; + for (const [index, key] of keys.entries()) { + if (key === null) continue; + obj[key] = index; + obj[index] = key; + } + return obj; +} + +module.exports = { createEnum }; diff --git a/node_modules/discord.js/src/util/Events.js b/node_modules/discord.js/src/util/Events.js new file mode 100644 index 0000000..1a83ec8 --- /dev/null +++ b/node_modules/discord.js/src/util/Events.js @@ -0,0 +1,162 @@ +'use strict'; + +/** + * @typedef {Object} Events + * @property {string} ApplicationCommandPermissionsUpdate applicationCommandPermissionsUpdate + * @property {string} AutoModerationActionExecution autoModerationActionExecution + * @property {string} AutoModerationRuleCreate autoModerationRuleCreate + * @property {string} AutoModerationRuleDelete autoModerationRuleDelete + * @property {string} AutoModerationRuleUpdate autoModerationRuleUpdate + * @property {string} CacheSweep cacheSweep + * @property {string} ChannelCreate channelCreate + * @property {string} ChannelDelete channelDelete + * @property {string} ChannelPinsUpdate channelPinsUpdate + * @property {string} ChannelUpdate channelUpdate + * @property {string} ClientReady ready + * @property {string} Debug debug + * @property {string} Error error + * @property {string} GuildAuditLogEntryCreate guildAuditLogEntryCreate + * @property {string} GuildAvailable guildAvailable + * @property {string} GuildBanAdd guildBanAdd + * @property {string} GuildBanRemove guildBanRemove + * @property {string} GuildCreate guildCreate + * @property {string} GuildDelete guildDelete + * @property {string} GuildEmojiCreate emojiCreate + * @property {string} GuildEmojiDelete emojiDelete + * @property {string} GuildEmojiUpdate emojiUpdate + * @property {string} GuildIntegrationsUpdate guildIntegrationsUpdate + * @property {string} GuildMemberAdd guildMemberAdd + * @property {string} GuildMemberAvailable guildMemberAvailable + * @property {string} GuildMemberRemove guildMemberRemove + * @property {string} GuildMembersChunk guildMembersChunk + * @property {string} GuildMemberUpdate guildMemberUpdate + * @property {string} GuildRoleCreate roleCreate + * @property {string} GuildRoleDelete roleDelete + * @property {string} GuildRoleUpdate roleUpdate + * @property {string} GuildScheduledEventCreate guildScheduledEventCreate + * @property {string} GuildScheduledEventDelete guildScheduledEventDelete + * @property {string} GuildScheduledEventUpdate guildScheduledEventUpdate + * @property {string} GuildScheduledEventUserAdd guildScheduledEventUserAdd + * @property {string} GuildScheduledEventUserRemove guildScheduledEventUserRemove + * @property {string} GuildStickerCreate stickerCreate + * @property {string} GuildStickerDelete stickerDelete + * @property {string} GuildStickerUpdate stickerUpdate + * @property {string} GuildUnavailable guildUnavailable + * @property {string} GuildUpdate guildUpdate + * @property {string} InteractionCreate interactionCreate + * @property {string} Invalidated invalidated + * @property {string} InviteCreate inviteCreate + * @property {string} InviteDelete inviteDelete + * @property {string} MessageBulkDelete messageDeleteBulk + * @property {string} MessageCreate messageCreate + * @property {string} MessageDelete messageDelete + * @property {string} MessageReactionAdd messageReactionAdd + * @property {string} MessageReactionRemove messageReactionRemove + * @property {string} MessageReactionRemoveAll messageReactionRemoveAll + * @property {string} MessageReactionRemoveEmoji messageReactionRemoveEmoji + * @property {string} MessageUpdate messageUpdate + * @property {string} PresenceUpdate presenceUpdate + * @property {string} ShardDisconnect shardDisconnect + * @property {string} ShardError shardError + * @property {string} ShardReady shardReady + * @property {string} ShardReconnecting shardReconnecting + * @property {string} ShardResume shardResume + * @property {string} StageInstanceCreate stageInstanceCreate + * @property {string} StageInstanceDelete stageInstanceDelete + * @property {string} StageInstanceUpdate stageInstanceUpdate + * @property {string} ThreadCreate threadCreate + * @property {string} ThreadDelete threadDelete + * @property {string} ThreadListSync threadListSync + * @property {string} ThreadMembersUpdate threadMembersUpdate + * @property {string} ThreadMemberUpdate threadMemberUpdate + * @property {string} ThreadUpdate threadUpdate + * @property {string} TypingStart typingStart + * @property {string} UserUpdate userUpdate + * @property {string} VoiceServerUpdate voiceServerUpdate + * @property {string} VoiceStateUpdate voiceStateUpdate + * @property {string} Warn warn + * @property {string} WebhooksUpdate webhookUpdate + */ + +// JSDoc for IntelliSense purposes +/** + * @type {Events} + * @ignore + */ +module.exports = { + ApplicationCommandPermissionsUpdate: 'applicationCommandPermissionsUpdate', + AutoModerationActionExecution: 'autoModerationActionExecution', + AutoModerationRuleCreate: 'autoModerationRuleCreate', + AutoModerationRuleDelete: 'autoModerationRuleDelete', + AutoModerationRuleUpdate: 'autoModerationRuleUpdate', + CacheSweep: 'cacheSweep', + ChannelCreate: 'channelCreate', + ChannelDelete: 'channelDelete', + ChannelPinsUpdate: 'channelPinsUpdate', + ChannelUpdate: 'channelUpdate', + ClientReady: 'ready', + Debug: 'debug', + Error: 'error', + GuildAuditLogEntryCreate: 'guildAuditLogEntryCreate', + GuildAvailable: 'guildAvailable', + GuildBanAdd: 'guildBanAdd', + GuildBanRemove: 'guildBanRemove', + GuildCreate: 'guildCreate', + GuildDelete: 'guildDelete', + GuildEmojiCreate: 'emojiCreate', + GuildEmojiDelete: 'emojiDelete', + GuildEmojiUpdate: 'emojiUpdate', + GuildIntegrationsUpdate: 'guildIntegrationsUpdate', + GuildMemberAdd: 'guildMemberAdd', + GuildMemberAvailable: 'guildMemberAvailable', + GuildMemberRemove: 'guildMemberRemove', + GuildMembersChunk: 'guildMembersChunk', + GuildMemberUpdate: 'guildMemberUpdate', + GuildRoleCreate: 'roleCreate', + GuildRoleDelete: 'roleDelete', + GuildRoleUpdate: 'roleUpdate', + GuildScheduledEventCreate: 'guildScheduledEventCreate', + GuildScheduledEventDelete: 'guildScheduledEventDelete', + GuildScheduledEventUpdate: 'guildScheduledEventUpdate', + GuildScheduledEventUserAdd: 'guildScheduledEventUserAdd', + GuildScheduledEventUserRemove: 'guildScheduledEventUserRemove', + GuildStickerCreate: 'stickerCreate', + GuildStickerDelete: 'stickerDelete', + GuildStickerUpdate: 'stickerUpdate', + GuildUnavailable: 'guildUnavailable', + GuildUpdate: 'guildUpdate', + InteractionCreate: 'interactionCreate', + Invalidated: 'invalidated', + InviteCreate: 'inviteCreate', + InviteDelete: 'inviteDelete', + MessageBulkDelete: 'messageDeleteBulk', + MessageCreate: 'messageCreate', + MessageDelete: 'messageDelete', + MessageReactionAdd: 'messageReactionAdd', + MessageReactionRemove: 'messageReactionRemove', + MessageReactionRemoveAll: 'messageReactionRemoveAll', + MessageReactionRemoveEmoji: 'messageReactionRemoveEmoji', + MessageUpdate: 'messageUpdate', + PresenceUpdate: 'presenceUpdate', + Raw: 'raw', + ShardDisconnect: 'shardDisconnect', + ShardError: 'shardError', + ShardReady: 'shardReady', + ShardReconnecting: 'shardReconnecting', + ShardResume: 'shardResume', + StageInstanceCreate: 'stageInstanceCreate', + StageInstanceDelete: 'stageInstanceDelete', + StageInstanceUpdate: 'stageInstanceUpdate', + ThreadCreate: 'threadCreate', + ThreadDelete: 'threadDelete', + ThreadListSync: 'threadListSync', + ThreadMembersUpdate: 'threadMembersUpdate', + ThreadMemberUpdate: 'threadMemberUpdate', + ThreadUpdate: 'threadUpdate', + TypingStart: 'typingStart', + UserUpdate: 'userUpdate', + VoiceServerUpdate: 'voiceServerUpdate', + VoiceStateUpdate: 'voiceStateUpdate', + Warn: 'warn', + WebhooksUpdate: 'webhookUpdate', +}; diff --git a/node_modules/discord.js/src/util/Formatters.js b/node_modules/discord.js/src/util/Formatters.js new file mode 100644 index 0000000..bd93a36 --- /dev/null +++ b/node_modules/discord.js/src/util/Formatters.js @@ -0,0 +1,413 @@ +'use strict'; + +const { deprecate } = require('node:util'); +const { + blockQuote, + bold, + channelMention, + codeBlock, + formatEmoji, + hideLinkEmbed, + hyperlink, + inlineCode, + italic, + quote, + roleMention, + spoiler, + strikethrough, + time, + TimestampStyles, + underscore, + userMention, +} = require('@discordjs/builders'); + +/** + * Formats an application command name and id into an application command mention. + * @method chatInputApplicationCommandMention + * @param {string} commandName The name of the application command + * @param {string|Snowflake} subcommandGroupOrSubOrId + * The subcommand group name, subcommand name, or application command id + * @param {string|Snowflake} [subcommandNameOrId] The subcommand name or application command id + * @param {string} [commandId] The id of the application command + * @returns {string} + */ + +/** + * Wraps the content inside a code block with an optional language. + * @method codeBlock + * @param {string} contentOrLanguage The language to use or content if a second parameter isn't provided + * @param {string} [content] The content to wrap + * @returns {string} + */ + +/** + * Wraps the content inside \`backticks\`, which formats it as inline code. + * @method inlineCode + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into italic text. + * @method italic + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into bold text. + * @method bold + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into underscored text. + * @method underscore + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into strike-through text. + * @method strikethrough + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into a quote. + * <info>This needs to be at the start of the line for Discord to format it.</info> + * @method quote + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content into a block quote. + * <info>This needs to be at the start of the line for Discord to format it.</info> + * @method blockQuote + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Wraps the URL into `<>`, which stops it from embedding. + * @method hideLinkEmbed + * @param {string} content The content to wrap + * @returns {string} + */ + +/** + * Formats the content and the URL into a masked URL with an optional title. + * @method hyperlink + * @param {string} content The content to display + * @param {string} url The URL the content links to + * @param {string} [title] The title shown when hovering on the masked link + * @returns {string} + */ + +/** + * Formats the content into spoiler text. + * @method spoiler + * @param {string} content The content to spoiler + * @returns {string} + */ + +/** + * Formats a user id into a user mention. + * @method userMention + * @param {Snowflake} userId The user id to format + * @returns {string} + */ + +/** + * Formats a channel id into a channel mention. + * @method channelMention + * @param {Snowflake} channelId The channel id to format + * @returns {string} + */ + +/** + * Formats a role id into a role mention. + * @method roleMention + * @param {Snowflake} roleId The role id to format + * @returns {string} + */ + +/** + * Formats an emoji id into a fully qualified emoji identifier. + * @method formatEmoji + * @param {Snowflake} emojiId The emoji id to format + * @param {boolean} [animated=false] Whether the emoji is animated + * @returns {string} + */ + +/** + * Formats a channel link for a channel. + * @method channelLink + * @param {Snowflake} channelId The id of the channel + * @param {Snowflake} [guildId] The id of the guild + * @returns {string} + */ + +/** + * Formats a message link for a channel. + * @method messageLink + * @param {Snowflake} channelId The id of the channel + * @param {Snowflake} messageId The id of the message + * @param {Snowflake} [guildId] The id of the guild + * @returns {string} + */ + +/** + * A message formatting timestamp style, as defined in + * [here](https://discord.com/developers/docs/reference#message-formatting-timestamp-styles). + * * `t` Short time format, consisting of hours and minutes, e.g. 16:20. + * * `T` Long time format, consisting of hours, minutes, and seconds, e.g. 16:20:30. + * * `d` Short date format, consisting of day, month, and year, e.g. 20/04/2021. + * * `D` Long date format, consisting of day, month, and year, e.g. 20 April 2021. + * * `f` Short date-time format, consisting of short date and short time formats, e.g. 20 April 2021 16:20. + * * `F` Long date-time format, consisting of long date and short time formats, e.g. Tuesday, 20 April 2021 16:20. + * * `R` Relative time format, consisting of a relative duration format, e.g. 2 months ago. + * @typedef {string} TimestampStylesString + */ + +/** + * Formats a date into a short date-time string. + * @method time + * @param {number|Date} [date] The date to format + * @param {TimestampStylesString} [style] The style to use + * @returns {string} + */ + +/** + * Contains various Discord-specific functions for formatting messages. + * @deprecated This class is redundant as all methods of the class can be imported from discord.js directly. + */ +class Formatters extends null { + /** + * Formats the content into a block quote. + * <info>This needs to be at the start of the line for Discord to format it.</info> + * @method blockQuote + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static blockQuote = deprecate( + blockQuote, + 'Formatters.blockQuote() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content into bold text. + * @method bold + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static bold = deprecate( + bold, + 'Formatters.bold() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats a channel id into a channel mention. + * @method channelMention + * @memberof Formatters + * @param {Snowflake} channelId The channel id to format + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static channelMention = deprecate( + channelMention, + 'Formatters.channelMention() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Wraps the content inside a code block with an optional language. + * @method codeBlock + * @memberof Formatters + * @param {string} contentOrLanguage The language to use or content if a second parameter isn't provided + * @param {string} [content] The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static codeBlock = deprecate( + codeBlock, + 'Formatters.codeBlock() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats an emoji id into a fully qualified emoji identifier. + * @method formatEmoji + * @memberof Formatters + * @param {string} emojiId The emoji id to format + * @param {boolean} [animated=false] Whether the emoji is animated + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static formatEmoji = deprecate( + formatEmoji, + 'Formatters.formatEmoji() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Wraps the URL into `<>`, which stops it from embedding. + * @method hideLinkEmbed + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static hideLinkEmbed = deprecate( + hideLinkEmbed, + 'Formatters.hideLinkEmbed() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content and the URL into a masked URL with an optional title. + * @method hyperlink + * @memberof Formatters + * @param {string} content The content to display + * @param {string} url The URL the content links to + * @param {string} [title] The title shown when hovering on the masked link + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static hyperlink = deprecate( + hyperlink, + 'Formatters.hyperlink() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Wraps the content inside \`backticks\`, which formats it as inline code. + * @method inlineCode + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static inlineCode = deprecate( + inlineCode, + 'Formatters.inlineCode() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content into italic text. + * @method italic + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static italic = deprecate( + italic, + 'Formatters.italic() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content into a quote. This needs to be at the start of the line for Discord to format it. + * @method quote + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static quote = deprecate( + quote, + 'Formatters.quote() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats a role id into a role mention. + * @method roleMention + * @memberof Formatters + * @param {Snowflake} roleId The role id to format + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static roleMention = deprecate( + roleMention, + 'Formatters.roleMention() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content into spoiler text. + * @method spoiler + * @memberof Formatters + * @param {string} content The content to spoiler + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static spoiler = deprecate( + spoiler, + 'Formatters.spoiler() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats the content into strike-through text. + * @method strikethrough + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static strikethrough = deprecate( + strikethrough, + 'Formatters.strikethrough() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats a date into a short date-time string. + * @method time + * @memberof Formatters + * @param {number|Date} [date] The date to format + * @param {TimestampStylesString} [style] The style to use + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static time = deprecate( + time, + 'Formatters.time() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * The message formatting timestamp + * [styles](https://discord.com/developers/docs/reference#message-formatting-timestamp-styles) supported by Discord. + * @type {Object<string, TimestampStylesString>} + * @memberof Formatters + * @deprecated Import this property directly from discord.js instead. + */ + static TimestampStyles = TimestampStyles; + + /** + * Formats the content into underscored text. + * @method underscore + * @memberof Formatters + * @param {string} content The content to wrap + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static underscore = deprecate( + underscore, + 'Formatters.underscore() is deprecated. Import this method directly from discord.js instead.', + ); + + /** + * Formats a user id into a user mention. + * @method userMention + * @memberof Formatters + * @param {Snowflake} userId The user id to format + * @returns {string} + * @deprecated Import this method directly from discord.js instead. + */ + static userMention = deprecate( + userMention, + 'Formatters.userMention() is deprecated. Import this method directly from discord.js instead.', + ); +} + +module.exports = Formatters; diff --git a/node_modules/discord.js/src/util/GuildMemberFlagsBitField.js b/node_modules/discord.js/src/util/GuildMemberFlagsBitField.js new file mode 100644 index 0000000..84ce6b9 --- /dev/null +++ b/node_modules/discord.js/src/util/GuildMemberFlagsBitField.js @@ -0,0 +1,41 @@ +'use strict'; + +const { GuildMemberFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link GuildMember#flags} bitfield. + * @extends {BitField} + */ +class GuildMemberFlagsBitField extends BitField { + /** + * Numeric guild guild member flags. + * @type {GuildMemberFlags} + * @memberof GuildMemberFlagsBitField + */ + static Flags = GuildMemberFlags; +} + +/** + * @name GuildMemberFlagsBitField + * @kind constructor + * @memberof GuildMemberFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name GuildMemberFlagsBitField#bitfield + */ + +/** + * Data that can be resolved to give a guild member flag bitfield. This can be: + * * A string (see {@link GuildMemberFlagsBitField.Flags}) + * * A guild member flag + * * An instance of GuildMemberFlagsBitField + * * An Array of GuildMemberFlagsResolvable + * @typedef {string|number|GuildMemberFlagsBitField|GuildMemberFlagsResolvable[]} GuildMemberFlagsResolvable + */ + +exports.GuildMemberFlagsBitField = GuildMemberFlagsBitField; diff --git a/node_modules/discord.js/src/util/IntentsBitField.js b/node_modules/discord.js/src/util/IntentsBitField.js new file mode 100644 index 0000000..ea908b6 --- /dev/null +++ b/node_modules/discord.js/src/util/IntentsBitField.js @@ -0,0 +1,34 @@ +'use strict'; +const { GatewayIntentBits } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to calculate intents. + * @extends {BitField} + */ +class IntentsBitField extends BitField { + /** + * Numeric WebSocket intents + * @type {GatewayIntentBits} + * @memberof IntentsBitField + */ + static Flags = GatewayIntentBits; +} + +/** + * @name IntentsBitField + * @kind constructor + * @memberof IntentsBitField + * @param {IntentsResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Data that can be resolved to give a permission number. This can be: + * * A string (see {@link IntentsBitField.Flags}) + * * An intents flag + * * An instance of {@link IntentsBitField} + * * An array of IntentsResolvable + * @typedef {string|number|IntentsBitField|IntentsResolvable[]} IntentsResolvable + */ + +module.exports = IntentsBitField; diff --git a/node_modules/discord.js/src/util/LimitedCollection.js b/node_modules/discord.js/src/util/LimitedCollection.js new file mode 100644 index 0000000..12a8360 --- /dev/null +++ b/node_modules/discord.js/src/util/LimitedCollection.js @@ -0,0 +1,68 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * Options for defining the behavior of a LimitedCollection + * @typedef {Object} LimitedCollectionOptions + * @property {?number} [maxSize=Infinity] The maximum size of the Collection + * @property {?Function} [keepOverLimit=null] A function, which is passed the value and key of an entry, ran to decide + * to keep an entry past the maximum size + */ + +/** + * A Collection which holds a max amount of entries. + * @extends {Collection} + * @param {LimitedCollectionOptions} [options={}] Options for constructing the Collection. + * @param {Iterable} [iterable=null] Optional entries passed to the Map constructor. + */ +class LimitedCollection extends Collection { + constructor(options = {}, iterable) { + if (typeof options !== 'object' || options === null) { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true); + } + const { maxSize = Infinity, keepOverLimit = null } = options; + + if (typeof maxSize !== 'number') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'maxSize', 'number'); + } + if (keepOverLimit !== null && typeof keepOverLimit !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'keepOverLimit', 'function'); + } + + super(iterable); + + /** + * The max size of the Collection. + * @type {number} + */ + this.maxSize = maxSize; + + /** + * A function called to check if an entry should be kept when the Collection is at max size. + * @type {?Function} + */ + this.keepOverLimit = keepOverLimit; + } + + set(key, value) { + if (this.maxSize === 0 && !this.keepOverLimit?.(value, key, this)) return this; + if (this.size >= this.maxSize && !this.has(key)) { + for (const [k, v] of this.entries()) { + const keep = this.keepOverLimit?.(v, k, this) ?? false; + if (!keep) { + this.delete(k); + break; + } + } + } + return super.set(key, value); + } + + static get [Symbol.species]() { + return Collection; + } +} + +module.exports = LimitedCollection; diff --git a/node_modules/discord.js/src/util/MessageFlagsBitField.js b/node_modules/discord.js/src/util/MessageFlagsBitField.js new file mode 100644 index 0000000..71f1fd6 --- /dev/null +++ b/node_modules/discord.js/src/util/MessageFlagsBitField.js @@ -0,0 +1,32 @@ +'use strict'; + +const { MessageFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link Message#flags} bitfield. + * @extends {BitField} + */ +class MessageFlagsBitField extends BitField { + /** + * Numeric message flags. + * @type {MessageFlags} + * @memberof MessageFlagsBitField + */ + static Flags = MessageFlags; +} + +/** + * @name MessageFlagsBitField + * @kind constructor + * @memberof MessageFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name MessageFlagsBitField#bitfield + */ + +module.exports = MessageFlagsBitField; diff --git a/node_modules/discord.js/src/util/Options.js b/node_modules/discord.js/src/util/Options.js new file mode 100644 index 0000000..9d1ce50 --- /dev/null +++ b/node_modules/discord.js/src/util/Options.js @@ -0,0 +1,237 @@ +'use strict'; + +const { DefaultRestOptions, DefaultUserAgentAppendix } = require('@discordjs/rest'); +const { toSnakeCase } = require('./Transformers'); +const { version } = require('../../package.json'); + +// TODO(ckohen): switch order of params so full manager is first and "type" is optional +/** + * @typedef {Function} CacheFactory + * @param {Function} managerType The base manager class the cache is being requested from. + * @param {Function} holds The class that the cache will hold. + * @param {Function} manager The fully extended manager class the cache is being requested from. + * @returns {Collection} A Collection used to store the cache of the manager. + */ + +/** + * Options for a client. + * @typedef {Object} ClientOptions + * @property {number|number[]|string} [shards] The shard's id to run, or an array of shard ids. If not specified, + * the client will spawn {@link ClientOptions#shardCount} shards. If set to `auto`, it will fetch the + * recommended amount of shards from Discord and spawn that amount + * @property {number} [closeTimeout=5_000] The amount of time in milliseconds to wait for the close frame to be received + * from the WebSocket. Don't have this too high/low. Its best to have it between 2_000-6_000 ms. + * @property {number} [shardCount=1] The total amount of shards used by all processes of this bot + * (e.g. recommended shard count, shard count of the ShardingManager) + * @property {CacheFactory} [makeCache] Function to create a cache. + * You can use your own function, or the {@link Options} class to customize the Collection used for the cache. + * <warn>Overriding the cache used in `GuildManager`, `ChannelManager`, `GuildChannelManager`, `RoleManager`, + * and `PermissionOverwriteManager` is unsupported and **will** break functionality</warn> + * @property {MessageMentionOptions} [allowedMentions] The default value for {@link BaseMessageOptions#allowedMentions} + * @property {Partials[]} [partials] Structures allowed to be partial. This means events can be emitted even when + * they're missing all the data for a particular structure. See the "Partial Structures" topic on the + * [guide](https://discordjs.guide/popular-topics/partials.html) for some + * important usage information, as partials require you to put checks in place when handling data. + * @property {boolean} [failIfNotExists=true] The default value for {@link MessageReplyOptions#failIfNotExists} + * @property {PresenceData} [presence={}] Presence data to use upon login + * @property {IntentsResolvable} intents Intents to enable for this connection + * @property {number} [waitGuildTimeout=15_000] Time in milliseconds that clients with the + * {@link GatewayIntentBits.Guilds} gateway intent should wait for missing guilds to be received before being ready. + * @property {SweeperOptions} [sweepers=this.DefaultSweeperSettings] Options for cache sweeping + * @property {WebsocketOptions} [ws] Options for the WebSocket + * @property {RESTOptions} [rest] Options for the REST manager + * @property {Function} [jsonTransformer] A function used to transform outgoing json data + */ + +/** + * Options for {@link Sweepers} defining the behavior of cache sweeping + * @typedef {Object<SweeperKey, SweepOptions>} SweeperOptions + */ + +/** + * Options for sweeping a single type of item from cache + * @typedef {Object} SweepOptions + * @property {number} interval The interval (in seconds) at which to perform sweeping of the item + * @property {number} [lifetime] How long an item should stay in cache until it is considered sweepable. + * <warn>This property is only valid for the `invites`, `messages`, and `threads` keys. The `filter` property + * is mutually exclusive to this property and takes priority</warn> + * @property {GlobalSweepFilter} filter The function used to determine the function passed to the sweep method + * <info>This property is optional when the key is `invites`, `messages`, or `threads` and `lifetime` is set</info> + */ + +/** + * A function to determine what strategy to use for sharding internally. + * ```js + * (manager) => new WorkerShardingStrategy(manager, { shardsPerWorker: 2 }) + * ``` + * @typedef {Function} BuildStrategyFunction + * @param {WSWebSocketManager} manager The WebSocketManager that is going to initiate the sharding + * @returns {IShardingStrategy} The strategy to use for sharding + */ + +/** + * A function to change the concurrency handling for shard identifies of this manager + * ```js + * async (manager) => { + * const gateway = await manager.fetchGatewayInformation(); + * return new SimpleIdentifyThrottler(gateway.session_start_limit.max_concurrency); + * } + * ``` + * @typedef {Function} IdentifyThrottlerFunction + * @param {WSWebSocketManager} manager The WebSocketManager that is going to initiate the sharding + * @returns {Awaitable<IIdentifyThrottler>} The identify throttler that this ws manager will use + */ + +/** + * WebSocket options (these are left as snake_case to match the API) + * @typedef {Object} WebsocketOptions + * @property {number} [large_threshold=50] Number of members in a guild after which offline users will no longer be + * sent in the initial guild member list, must be between 50 and 250 + * @property {number} [version=10] The Discord gateway version to use <warn>Changing this can break the library; + * only set this if you know what you are doing</warn> + * @property {BuildStrategyFunction} [buildStrategy] Builds the strategy to use for sharding + * @property {IdentifyThrottlerFunction} [buildIdentifyThrottler] Builds the identify throttler to use for sharding + */ + +/** + * Contains various utilities for client options. + */ +class Options extends null { + /** + * The default user agent appendix. + * @type {string} + * @memberof Options + * @private + */ + static userAgentAppendix = `discord.js/${version} ${DefaultUserAgentAppendix}`.trimEnd(); + + /** + * The default client options. + * @returns {ClientOptions} + */ + static createDefault() { + return { + closeTimeout: 5_000, + waitGuildTimeout: 15_000, + shardCount: 1, + makeCache: this.cacheWithLimits(this.DefaultMakeCacheSettings), + partials: [], + failIfNotExists: true, + presence: {}, + sweepers: this.DefaultSweeperSettings, + ws: { + large_threshold: 50, + version: 10, + }, + rest: { + ...DefaultRestOptions, + userAgentAppendix: this.userAgentAppendix, + }, + jsonTransformer: toSnakeCase, + }; + } + + /** + * Create a cache factory using predefined settings to sweep or limit. + * @param {Object<string, LimitedCollectionOptions|number>} [settings={}] Settings passed to the relevant constructor. + * If no setting is provided for a manager, it uses Collection. + * If a number is provided for a manager, it uses that number as the max size for a LimitedCollection. + * If LimitedCollectionOptions are provided for a manager, it uses those settings to form a LimitedCollection. + * @returns {CacheFactory} + * @example + * // Store up to 200 messages per channel and 200 members per guild, always keeping the client member. + * Options.cacheWithLimits({ + * MessageManager: 200, + * GuildMemberManager: { + * maxSize: 200, + * keepOverLimit: (member) => member.id === client.user.id, + * }, + * }); + */ + static cacheWithLimits(settings = {}) { + const { Collection } = require('@discordjs/collection'); + const LimitedCollection = require('./LimitedCollection'); + + return (managerType, _, manager) => { + const setting = settings[manager.name] ?? settings[managerType.name]; + /* eslint-disable-next-line eqeqeq */ + if (setting == null) { + return new Collection(); + } + if (typeof setting === 'number') { + if (setting === Infinity) { + return new Collection(); + } + return new LimitedCollection({ maxSize: setting }); + } + /* eslint-disable-next-line eqeqeq */ + const noLimit = setting.maxSize == null || setting.maxSize === Infinity; + if (noLimit) { + return new Collection(); + } + return new LimitedCollection(setting); + }; + } + + /** + * Create a cache factory that always caches everything. + * @returns {CacheFactory} + */ + static cacheEverything() { + const { Collection } = require('@discordjs/collection'); + return () => new Collection(); + } + + /** + * The default settings passed to {@link ClientOptions.makeCache}. + * The caches that this changes are: + * * `MessageManager` - Limit to 200 messages + * <info>If you want to keep default behavior and add on top of it you can use this object and add on to it, e.g. + * `makeCache: Options.cacheWithLimits({ ...Options.DefaultMakeCacheSettings, ReactionManager: 0 })`</info> + * @type {Object<string, LimitedCollectionOptions|number>} + */ + static get DefaultMakeCacheSettings() { + return { + MessageManager: 200, + }; + } + + /** + * The default settings passed to {@link ClientOptions.sweepers}. + * The sweepers that this changes are: + * * `threads` - Sweep archived threads every hour, removing those archived more than 4 hours ago + * <info>If you want to keep default behavior and add on top of it you can use this object and add on to it, e.g. + * `sweepers: { ...Options.DefaultSweeperSettings, messages: { interval: 300, lifetime: 600 } }`</info> + * @type {SweeperOptions} + */ + static get DefaultSweeperSettings() { + return { + threads: { + interval: 3600, + lifetime: 14400, + }, + }; + } +} + +module.exports = Options; + +/** + * @external RESTOptions + * @see {@link https://discord.js.org/docs/packages/rest/stable/RESTOptions:Interface} + */ + +/** + * @external WSWebSocketManager + * @see {@link https://discord.js.org/docs/packages/ws/stable/WebSocketManager:Class} + */ + +/** + * @external IShardingStrategy + * @see {@link https://discord.js.org/docs/packages/ws/stable/IShardingStrategy:Interface} + */ + +/** + * @external IIdentifyThrottler + * @see {@link https://discord.js.org/docs/packages/ws/stable/IIdentifyThrottler:Interface} + */ diff --git a/node_modules/discord.js/src/util/Partials.js b/node_modules/discord.js/src/util/Partials.js new file mode 100644 index 0000000..31d9223 --- /dev/null +++ b/node_modules/discord.js/src/util/Partials.js @@ -0,0 +1,44 @@ +'use strict'; + +const { createEnum } = require('./Enums'); + +/** + * The enumeration for partials. + * ```js + * import { Client, Partials } from 'discord.js'; + * + * const client = new Client({ + * intents: [ + * // Intents... + * ], + * partials: [ + * Partials.User, // We want to receive uncached users! + * Partials.Message // We want to receive uncached messages! + * ] + * }); + * ``` + * @typedef {Object} Partials + * @property {number} User The partial to receive uncached users. + * @property {number} Channel The partial to receive uncached channels. + * <info>This is required to receive direct messages!</info> + * @property {number} GuildMember The partial to receive uncached guild members. + * @property {number} Message The partial to receive uncached messages. + * @property {number} Reaction The partial to receive uncached reactions. + * @property {number} GuildScheduledEvent The partial to receive uncached guild scheduled events. + * @property {number} ThreadMember The partial to receive uncached thread members. + */ + +// JSDoc for IntelliSense purposes +/** + * @type {Partials} + * @ignore + */ +module.exports = createEnum([ + 'User', + 'Channel', + 'GuildMember', + 'Message', + 'Reaction', + 'GuildScheduledEvent', + 'ThreadMember', +]); diff --git a/node_modules/discord.js/src/util/PermissionsBitField.js b/node_modules/discord.js/src/util/PermissionsBitField.js new file mode 100644 index 0000000..c1ec72d --- /dev/null +++ b/node_modules/discord.js/src/util/PermissionsBitField.js @@ -0,0 +1,104 @@ +'use strict'; + +const { PermissionFlagsBits } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a permission bitfield. All {@link GuildMember}s have a set of + * permissions in their guild, and each channel in the guild may also have {@link PermissionOverwrites} for the member + * that override their default permissions. + * @extends {BitField} + */ +class PermissionsBitField extends BitField { + /** + * Numeric permission flags. + * @type {PermissionFlagsBits} + * @memberof PermissionsBitField + * @see {@link https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags} + */ + static Flags = PermissionFlagsBits; + + /** + * Bitfield representing every permission combined + * @type {bigint} + * @memberof PermissionsBitField + */ + static All = Object.values(PermissionFlagsBits).reduce((all, p) => all | p, 0n); + + /** + * Bitfield representing the default permissions for users + * @type {bigint} + * @memberof PermissionsBitField + */ + static Default = BigInt(104324673); + + /** + * Bitfield representing the permissions required for moderators of stage channels + * @type {bigint} + * @memberof PermissionsBitField + */ + static StageModerator = + PermissionFlagsBits.ManageChannels | PermissionFlagsBits.MuteMembers | PermissionFlagsBits.MoveMembers; + + /** + * @type {bigint} + * @memberof PermissionsBitField + * @private + */ + static DefaultBit = BigInt(0); + + /** + * Bitfield of the packed bits + * @type {bigint} + * @name PermissionsBitField#bitfield + */ + + /** + * Data that can be resolved to give a permission number. This can be: + * * A string (see {@link PermissionsBitField.Flags}) + * * A permission number + * * An instance of {@link PermissionsBitField} + * * An Array of PermissionResolvable + * @typedef {string|bigint|PermissionsBitField|PermissionResolvable[]} PermissionResolvable + */ + + /** + * Gets all given bits that are missing from the bitfield. + * @param {BitFieldResolvable} bits Bit(s) to check for + * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override + * @returns {string[]} + */ + missing(bits, checkAdmin = true) { + return checkAdmin && this.has(PermissionFlagsBits.Administrator) ? [] : super.missing(bits); + } + + /** + * Checks whether the bitfield has a permission, or any of multiple permissions. + * @param {PermissionResolvable} permission Permission(s) to check for + * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override + * @returns {boolean} + */ + any(permission, checkAdmin = true) { + return (checkAdmin && super.has(PermissionFlagsBits.Administrator)) || super.any(permission); + } + + /** + * Checks whether the bitfield has a permission, or multiple permissions. + * @param {PermissionResolvable} permission Permission(s) to check for + * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override + * @returns {boolean} + */ + has(permission, checkAdmin = true) { + return (checkAdmin && super.has(PermissionFlagsBits.Administrator)) || super.has(permission); + } + + /** + * Gets an {@link Array} of bitfield names based on the permissions available. + * @returns {string[]} + */ + toArray() { + return super.toArray(false); + } +} + +module.exports = PermissionsBitField; diff --git a/node_modules/discord.js/src/util/RoleFlagsBitField.js b/node_modules/discord.js/src/util/RoleFlagsBitField.js new file mode 100644 index 0000000..1e0f895 --- /dev/null +++ b/node_modules/discord.js/src/util/RoleFlagsBitField.js @@ -0,0 +1,26 @@ +'use strict'; + +const { RoleFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link Role#flags} bitfield. + * @extends {BitField} + */ +class RoleFlagsBitField extends BitField { + /** + * Numeric role flags. + * @type {RoleFlags} + * @memberof RoleFlagsBitField + */ + static Flags = RoleFlags; +} + +/** + * @name RoleFlagsBitField + * @kind constructor + * @memberof RoleFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +module.exports = RoleFlagsBitField; diff --git a/node_modules/discord.js/src/util/ShardEvents.js b/node_modules/discord.js/src/util/ShardEvents.js new file mode 100644 index 0000000..f5ba961 --- /dev/null +++ b/node_modules/discord.js/src/util/ShardEvents.js @@ -0,0 +1,29 @@ +'use strict'; + +/** + * @typedef {Object} ShardEvents + * @property {string} Death death + * @property {string} Disconnect disconnect + * @property {string} Error error + * @property {string} Message message + * @property {string} Ready ready + * @property {string} Reconnecting reconnecting + * @property {string} Resume resume + * @property {string} Spawn spawn + */ + +// JSDoc for IntelliSense purposes +/** + * @type {ShardEvents} + * @ignore + */ +module.exports = { + Death: 'death', + Disconnect: 'disconnect', + Error: 'error', + Message: 'message', + Ready: 'ready', + Reconnecting: 'reconnecting', + Resume: 'resume', + Spawn: 'spawn', +}; diff --git a/node_modules/discord.js/src/util/Status.js b/node_modules/discord.js/src/util/Status.js new file mode 100644 index 0000000..e524197 --- /dev/null +++ b/node_modules/discord.js/src/util/Status.js @@ -0,0 +1,33 @@ +'use strict'; + +const { createEnum } = require('./Enums'); + +/** + * @typedef {Object} Status + * @property {number} Ready + * @property {number} Connecting + * @property {number} Reconnecting + * @property {number} Idle + * @property {number} Nearly + * @property {number} Disconnected + * @property {number} WaitingForGuilds + * @property {number} Identifying + * @property {number} Resuming + */ + +// JSDoc for IntelliSense purposes +/** + * @type {Status} + * @ignore + */ +module.exports = createEnum([ + 'Ready', + 'Connecting', + 'Reconnecting', + 'Idle', + 'Nearly', + 'Disconnected', + 'WaitingForGuilds', + 'Identifying', + 'Resuming', +]); diff --git a/node_modules/discord.js/src/util/Sweepers.js b/node_modules/discord.js/src/util/Sweepers.js new file mode 100644 index 0000000..6eb2dc6 --- /dev/null +++ b/node_modules/discord.js/src/util/Sweepers.js @@ -0,0 +1,467 @@ +'use strict'; + +const { setInterval, clearInterval } = require('node:timers'); +const { ThreadChannelTypes, SweeperKeys } = require('./Constants'); +const Events = require('./Events'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * @typedef {Function} GlobalSweepFilter + * @returns {Function|null} Return `null` to skip sweeping, otherwise a function passed to `sweep()`, + * See {@link [Collection#sweep](https://discord.js.org/docs/packages/collection/stable/Collection:Class#sweep)} + * for the definition of this function. + */ + +/** + * A container for all cache sweeping intervals and their associated sweep methods. + */ +class Sweepers { + constructor(client, options) { + /** + * The client that instantiated this + * @type {Client} + * @readonly + */ + Object.defineProperty(this, 'client', { value: client }); + + /** + * The options the sweepers were instantiated with + * @type {SweeperOptions} + */ + this.options = options; + + /** + * A record of interval timeout that is used to sweep the indicated items, or null if not being swept + * @type {Object<SweeperKey, ?Timeout>} + */ + this.intervals = Object.fromEntries(SweeperKeys.map(key => [key, null])); + + for (const key of SweeperKeys) { + if (!(key in options)) continue; + + this._validateProperties(key); + + const clonedOptions = { ...this.options[key] }; + + // Handle cases that have a "lifetime" + if (!('filter' in clonedOptions)) { + switch (key) { + case 'invites': + clonedOptions.filter = this.constructor.expiredInviteSweepFilter(clonedOptions.lifetime); + break; + case 'messages': + clonedOptions.filter = this.constructor.outdatedMessageSweepFilter(clonedOptions.lifetime); + break; + case 'threads': + clonedOptions.filter = this.constructor.archivedThreadSweepFilter(clonedOptions.lifetime); + } + } + + this._initInterval(key, `sweep${key[0].toUpperCase()}${key.slice(1)}`, clonedOptions); + } + } + + /** + * Sweeps all guild and global application commands and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which commands will be removed from the caches. + * @returns {number} Amount of commands that were removed from the caches + */ + sweepApplicationCommands(filter) { + const { guilds, items: guildCommands } = this._sweepGuildDirectProp('commands', filter, { emit: false }); + + const globalCommands = this.client.application?.commands.cache.sweep(filter) ?? 0; + + this.client.emit( + Events.CacheSweep, + `Swept ${globalCommands} global application commands and ${guildCommands} guild commands in ${guilds} guilds.`, + ); + return guildCommands + globalCommands; + } + + /** + * Sweeps all auto moderation rules and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine + * which auto moderation rules will be removed from the caches + * @returns {number} Amount of auto moderation rules that were removed from the caches + */ + sweepAutoModerationRules(filter) { + return this._sweepGuildDirectProp('autoModerationRules', filter).items; + } + + /** + * Sweeps all guild bans and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which bans will be removed from the caches. + * @returns {number} Amount of bans that were removed from the caches + */ + sweepBans(filter) { + return this._sweepGuildDirectProp('bans', filter).items; + } + + /** + * Sweeps all guild emojis and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which emojis will be removed from the caches. + * @returns {number} Amount of emojis that were removed from the caches + */ + sweepEmojis(filter) { + return this._sweepGuildDirectProp('emojis', filter).items; + } + + /** + * Sweeps all guild invites and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which invites will be removed from the caches. + * @returns {number} Amount of invites that were removed from the caches + */ + sweepInvites(filter) { + return this._sweepGuildDirectProp('invites', filter).items; + } + + /** + * Sweeps all guild members and removes the ones which are indicated by the filter. + * <info>It is highly recommended to keep the client guild member cached</info> + * @param {Function} filter The function used to determine which guild members will be removed from the caches. + * @returns {number} Amount of guild members that were removed from the caches + */ + sweepGuildMembers(filter) { + return this._sweepGuildDirectProp('members', filter, { outputName: 'guild members' }).items; + } + + /** + * Sweeps all text-based channels' messages and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which messages will be removed from the caches. + * @returns {number} Amount of messages that were removed from the caches + * @example + * // Remove all messages older than 1800 seconds from the messages cache + * const amount = sweepers.sweepMessages( + * Sweepers.filterByLifetime({ + * lifetime: 1800, + * getComparisonTimestamp: m => m.editedTimestamp ?? m.createdTimestamp, + * })(), + * ); + * console.log(`Successfully removed ${amount} messages from the cache.`); + */ + sweepMessages(filter) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + let channels = 0; + let messages = 0; + + for (const channel of this.client.channels.cache.values()) { + if (!channel.isTextBased()) continue; + + channels++; + messages += channel.messages.cache.sweep(filter); + } + this.client.emit(Events.CacheSweep, `Swept ${messages} messages in ${channels} text-based channels.`); + return messages; + } + + /** + * Sweeps all presences and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which presences will be removed from the caches. + * @returns {number} Amount of presences that were removed from the caches + */ + sweepPresences(filter) { + return this._sweepGuildDirectProp('presences', filter).items; + } + + /** + * Sweeps all message reactions and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which reactions will be removed from the caches. + * @returns {number} Amount of reactions that were removed from the caches + */ + sweepReactions(filter) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + let channels = 0; + let messages = 0; + let reactions = 0; + + for (const channel of this.client.channels.cache.values()) { + if (!channel.isTextBased()) continue; + channels++; + + for (const message of channel.messages.cache.values()) { + messages++; + reactions += message.reactions.cache.sweep(filter); + } + } + this.client.emit( + Events.CacheSweep, + `Swept ${reactions} reactions on ${messages} messages in ${channels} text-based channels.`, + ); + return reactions; + } + + /** + * Sweeps all guild stage instances and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which stage instances will be removed from the caches. + * @returns {number} Amount of stage instances that were removed from the caches + */ + sweepStageInstances(filter) { + return this._sweepGuildDirectProp('stageInstances', filter, { outputName: 'stage instances' }).items; + } + + /** + * Sweeps all guild stickers and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which stickers will be removed from the caches. + * @returns {number} Amount of stickers that were removed from the caches + */ + sweepStickers(filter) { + return this._sweepGuildDirectProp('stickers', filter).items; + } + + /** + * Sweeps all thread members and removes the ones which are indicated by the filter. + * <info>It is highly recommended to keep the client thread member cached</info> + * @param {Function} filter The function used to determine which thread members will be removed from the caches. + * @returns {number} Amount of thread members that were removed from the caches + */ + sweepThreadMembers(filter) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + + let threads = 0; + let members = 0; + for (const channel of this.client.channels.cache.values()) { + if (!ThreadChannelTypes.includes(channel.type)) continue; + threads++; + members += channel.members.cache.sweep(filter); + } + this.client.emit(Events.CacheSweep, `Swept ${members} thread members in ${threads} threads.`); + return members; + } + + /** + * Sweeps all threads and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which threads will be removed from the caches. + * @returns {number} filter Amount of threads that were removed from the caches + * @example + * // Remove all threads archived greater than 1 day ago from all the channel caches + * const amount = sweepers.sweepThreads( + * Sweepers.filterByLifetime({ + * getComparisonTimestamp: t => t.archivedTimestamp, + * excludeFromSweep: t => !t.archived, + * })(), + * ); + * console.log(`Successfully removed ${amount} threads from the cache.`); + */ + sweepThreads(filter) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + + let threads = 0; + for (const [key, val] of this.client.channels.cache.entries()) { + if (!ThreadChannelTypes.includes(val.type)) continue; + if (filter(val, key, this.client.channels.cache)) { + threads++; + this.client.channels._remove(key); + } + } + this.client.emit(Events.CacheSweep, `Swept ${threads} threads.`); + return threads; + } + + /** + * Sweeps all users and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which users will be removed from the caches. + * @returns {number} Amount of users that were removed from the caches + */ + sweepUsers(filter) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + + const users = this.client.users.cache.sweep(filter); + + this.client.emit(Events.CacheSweep, `Swept ${users} users.`); + + return users; + } + + /** + * Sweeps all guild voice states and removes the ones which are indicated by the filter. + * @param {Function} filter The function used to determine which voice states will be removed from the caches. + * @returns {number} Amount of voice states that were removed from the caches + */ + sweepVoiceStates(filter) { + return this._sweepGuildDirectProp('voiceStates', filter, { outputName: 'voice states' }).items; + } + + /** + * Cancels all sweeping intervals + * @returns {void} + */ + destroy() { + for (const key of SweeperKeys) { + if (this.intervals[key]) clearInterval(this.intervals[key]); + } + } + + /** + * Options for generating a filter function based on lifetime + * @typedef {Object} LifetimeFilterOptions + * @property {number} [lifetime=14400] How long, in seconds, an entry should stay in the collection + * before it is considered sweepable. + * @property {Function} [getComparisonTimestamp=e => e?.createdTimestamp] A function that takes an entry, key, + * and the collection and returns a timestamp to compare against in order to determine the lifetime of the entry. + * @property {Function} [excludeFromSweep=() => false] A function that takes an entry, key, and the collection + * and returns a boolean, `true` when the entry should not be checked for sweepability. + */ + + /** + * Create a sweepFilter function that uses a lifetime to determine sweepability. + * @param {LifetimeFilterOptions} [options={}] The options used to generate the filter function + * @returns {GlobalSweepFilter} + */ + static filterByLifetime({ + lifetime = 14400, + getComparisonTimestamp = e => e?.createdTimestamp, + excludeFromSweep = () => false, + } = {}) { + if (typeof lifetime !== 'number') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'lifetime', 'number'); + } + if (typeof getComparisonTimestamp !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'getComparisonTimestamp', 'function'); + } + if (typeof excludeFromSweep !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'excludeFromSweep', 'function'); + } + return () => { + if (lifetime <= 0) return null; + const lifetimeMs = lifetime * 1_000; + const now = Date.now(); + return (entry, key, coll) => { + if (excludeFromSweep(entry, key, coll)) { + return false; + } + const comparisonTimestamp = getComparisonTimestamp(entry, key, coll); + if (!comparisonTimestamp || typeof comparisonTimestamp !== 'number') return false; + return now - comparisonTimestamp > lifetimeMs; + }; + }; + } + + /** + * Creates a sweep filter that sweeps archived threads + * @param {number} [lifetime=14400] How long a thread has to be archived to be valid for sweeping + * @returns {GlobalSweepFilter} + */ + static archivedThreadSweepFilter(lifetime = 14400) { + return this.filterByLifetime({ + lifetime, + getComparisonTimestamp: e => e.archiveTimestamp, + excludeFromSweep: e => !e.archived, + }); + } + + /** + * Creates a sweep filter that sweeps expired invites + * @param {number} [lifetime=14400] How long ago an invite has to have expired to be valid for sweeping + * @returns {GlobalSweepFilter} + */ + static expiredInviteSweepFilter(lifetime = 14400) { + return this.filterByLifetime({ + lifetime, + getComparisonTimestamp: i => i.expiresTimestamp, + }); + } + + /** + * Creates a sweep filter that sweeps outdated messages (edits taken into account) + * @param {number} [lifetime=3600] How long ago a message has to have been sent or edited to be valid for sweeping + * @returns {GlobalSweepFilter} + */ + static outdatedMessageSweepFilter(lifetime = 3600) { + return this.filterByLifetime({ + lifetime, + getComparisonTimestamp: m => m.editedTimestamp ?? m.createdTimestamp, + }); + } + + /** + * Configuration options for emitting the cache sweep client event + * @typedef {Object} SweepEventOptions + * @property {boolean} [emit=true] Whether to emit the client event in this method + * @property {string} [outputName] A name to output in the client event if it should differ from the key + * @private + */ + + /** + * Sweep a direct sub property of all guilds + * @param {string} key The name of the property + * @param {Function} filter Filter function passed to sweep + * @param {SweepEventOptions} [eventOptions={}] Options for the Client event emitted here + * @returns {Object} Object containing the number of guilds swept and the number of items swept + * @private + */ + _sweepGuildDirectProp(key, filter, { emit = true, outputName } = {}) { + if (typeof filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function'); + } + + let guilds = 0; + let items = 0; + + for (const guild of this.client.guilds.cache.values()) { + const { cache } = guild[key]; + + guilds++; + items += cache.sweep(filter); + } + + if (emit) { + this.client.emit(Events.CacheSweep, `Swept ${items} ${outputName ?? key} in ${guilds} guilds.`); + } + + return { guilds, items }; + } + + /** + * Validates a set of properties + * @param {string} key Key of the options object to check + * @private + */ + _validateProperties(key) { + const props = this.options[key]; + if (typeof props !== 'object') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}`, 'object', true); + } + if (typeof props.interval !== 'number') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}.interval`, 'number'); + } + // Invites, Messages, and Threads can be provided a lifetime parameter, which we use to generate the filter + if (['invites', 'messages', 'threads'].includes(key) && !('filter' in props)) { + if (typeof props.lifetime !== 'number') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}.lifetime`, 'number'); + } + return; + } + if (typeof props.filter !== 'function') { + throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}.filter`, 'function'); + } + } + + /** + * Initialize an interval for sweeping + * @param {string} intervalKey The name of the property that stores the interval for this sweeper + * @param {string} sweepKey The name of the function that sweeps the desired caches + * @param {Object} opts Validated options for a sweep + * @private + */ + _initInterval(intervalKey, sweepKey, opts) { + if (opts.interval <= 0 || opts.interval === Infinity) return; + this.intervals[intervalKey] = setInterval(() => { + const sweepFn = opts.filter(); + if (sweepFn === null) return; + if (typeof sweepFn !== 'function') throw new DiscordjsTypeError(ErrorCodes.SweepFilterReturn); + this[sweepKey](sweepFn); + }, opts.interval * 1_000).unref(); + } +} + +module.exports = Sweepers; diff --git a/node_modules/discord.js/src/util/Symbols.js b/node_modules/discord.js/src/util/Symbols.js new file mode 100644 index 0000000..36d4ed8 --- /dev/null +++ b/node_modules/discord.js/src/util/Symbols.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.MakeCacheOverrideSymbol = Symbol('djs.managers.makeCacheOverride'); diff --git a/node_modules/discord.js/src/util/SystemChannelFlagsBitField.js b/node_modules/discord.js/src/util/SystemChannelFlagsBitField.js new file mode 100644 index 0000000..cbca48f --- /dev/null +++ b/node_modules/discord.js/src/util/SystemChannelFlagsBitField.js @@ -0,0 +1,43 @@ +'use strict'; + +const { GuildSystemChannelFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link Guild#systemChannelFlags} bitfield. + * <info>Note that all event message types are enabled by default, + * and by setting their corresponding flags you are disabling them</info> + * @extends {BitField} + */ +class SystemChannelFlagsBitField extends BitField { + /** + * Numeric system channel flags. + * @type {GuildSystemChannelFlags} + * @memberof SystemChannelFlagsBitField + */ + static Flags = GuildSystemChannelFlags; +} + +/** + * @name SystemChannelFlagsBitField + * @kind constructor + * @memberof SystemChannelFlagsBitField + * @param {SystemChannelFlagsResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name SystemChannelFlagsBitField#bitfield + */ + +/** + * Data that can be resolved to give a system channel flag bitfield. This can be: + * * A string (see {@link SystemChannelFlagsBitField.Flags}) + * * A system channel flag + * * An instance of SystemChannelFlagsBitField + * * An Array of SystemChannelFlagsResolvable + * @typedef {string|number|SystemChannelFlagsBitField|SystemChannelFlagsResolvable[]} SystemChannelFlagsResolvable + */ + +module.exports = SystemChannelFlagsBitField; diff --git a/node_modules/discord.js/src/util/ThreadMemberFlagsBitField.js b/node_modules/discord.js/src/util/ThreadMemberFlagsBitField.js new file mode 100644 index 0000000..c5073a8 --- /dev/null +++ b/node_modules/discord.js/src/util/ThreadMemberFlagsBitField.js @@ -0,0 +1,31 @@ +'use strict'; + +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link ThreadMember#flags} bitfield. + * @extends {BitField} + */ +class ThreadMemberFlagsBitField extends BitField { + /** + * Numeric thread member flags. There are currently no bitflags relevant to bots for this. + * @type {Object<string, number>} + * @memberof ThreadMemberFlagsBitField + */ + static Flags = {}; +} + +/** + * @name ThreadMemberFlagsBitField + * @kind constructor + * @memberof ThreadMemberFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name ThreadMemberFlagsBitField#bitfield + */ + +module.exports = ThreadMemberFlagsBitField; diff --git a/node_modules/discord.js/src/util/Transformers.js b/node_modules/discord.js/src/util/Transformers.js new file mode 100644 index 0000000..f4d7af0 --- /dev/null +++ b/node_modules/discord.js/src/util/Transformers.js @@ -0,0 +1,36 @@ +'use strict'; + +const { isJSONEncodable } = require('@discordjs/util'); +const snakeCase = require('lodash.snakecase'); + +/** + * Transforms camel-cased keys into snake cased keys + * @param {*} obj The object to transform + * @returns {*} + */ +function toSnakeCase(obj) { + if (typeof obj !== 'object' || !obj) return obj; + if (obj instanceof Date) return obj; + if (isJSONEncodable(obj)) return toSnakeCase(obj.toJSON()); + if (Array.isArray(obj)) return obj.map(toSnakeCase); + return Object.fromEntries(Object.entries(obj).map(([key, value]) => [snakeCase(key), toSnakeCase(value)])); +} + +/** + * Transforms an API auto moderation action object to a camel-cased variant. + * @param {APIAutoModerationAction} autoModerationAction The action to transform + * @returns {AutoModerationAction} + * @ignore + */ +function _transformAPIAutoModerationAction(autoModerationAction) { + return { + type: autoModerationAction.type, + metadata: { + durationSeconds: autoModerationAction.metadata.duration_seconds ?? null, + channelId: autoModerationAction.metadata.channel_id ?? null, + customMessage: autoModerationAction.metadata.custom_message ?? null, + }, + }; +} + +module.exports = { toSnakeCase, _transformAPIAutoModerationAction }; diff --git a/node_modules/discord.js/src/util/UserFlagsBitField.js b/node_modules/discord.js/src/util/UserFlagsBitField.js new file mode 100644 index 0000000..ea9f835 --- /dev/null +++ b/node_modules/discord.js/src/util/UserFlagsBitField.js @@ -0,0 +1,32 @@ +'use strict'; + +const { UserFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link User#flags} bitfield. + * @extends {BitField} + */ +class UserFlagsBitField extends BitField { + /** + * Numeric user flags. + * @type {UserFlags} + * @memberof UserFlagsBitField + */ + static Flags = UserFlags; +} + +/** + * @name UserFlagsBitField + * @kind constructor + * @memberof UserFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name UserFlagsBitField#bitfield + */ + +module.exports = UserFlagsBitField; diff --git a/node_modules/discord.js/src/util/Util.js b/node_modules/discord.js/src/util/Util.js new file mode 100644 index 0000000..e42bc5a --- /dev/null +++ b/node_modules/discord.js/src/util/Util.js @@ -0,0 +1,424 @@ +'use strict'; + +const { parse } = require('node:path'); +const { Collection } = require('@discordjs/collection'); +const { ChannelType, RouteBases, Routes } = require('discord-api-types/v10'); +const { fetch } = require('undici'); +const Colors = require('./Colors'); +const { DiscordjsError, DiscordjsRangeError, DiscordjsTypeError, ErrorCodes } = require('../errors'); +const isObject = d => typeof d === 'object' && d !== null; + +/** + * Flatten an object. Any properties that are collections will get converted to an array of keys. + * @param {Object} obj The object to flatten. + * @param {...Object<string, boolean|string>} [props] Specific properties to include/exclude. + * @returns {Object} + */ +function flatten(obj, ...props) { + if (!isObject(obj)) return obj; + + const objProps = Object.keys(obj) + .filter(k => !k.startsWith('_')) + .map(k => ({ [k]: true })); + + props = objProps.length ? Object.assign(...objProps, ...props) : Object.assign({}, ...props); + + const out = {}; + + for (let [prop, newProp] of Object.entries(props)) { + if (!newProp) continue; + newProp = newProp === true ? prop : newProp; + + const element = obj[prop]; + const elemIsObj = isObject(element); + const valueOf = elemIsObj && typeof element.valueOf === 'function' ? element.valueOf() : null; + const hasToJSON = elemIsObj && typeof element.toJSON === 'function'; + + // If it's a Collection, make the array of keys + if (element instanceof Collection) out[newProp] = Array.from(element.keys()); + // If the valueOf is a Collection, use its array of keys + else if (valueOf instanceof Collection) out[newProp] = Array.from(valueOf.keys()); + // If it's an array, call toJSON function on each element if present, otherwise flatten each element + else if (Array.isArray(element)) out[newProp] = element.map(e => e.toJSON?.() ?? flatten(e)); + // If it's an object with a primitive `valueOf`, use that value + else if (typeof valueOf !== 'object') out[newProp] = valueOf; + // If it's an object with a toJSON function, use the return value of it + else if (hasToJSON) out[newProp] = element.toJSON(); + // If element is an object, use the flattened version of it + else if (typeof element === 'object') out[newProp] = flatten(element); + // If it's a primitive + else if (!elemIsObj) out[newProp] = element; + } + + return out; +} + +/** + * @typedef {Object} FetchRecommendedShardCountOptions + * @property {number} [guildsPerShard=1000] Number of guilds assigned per shard + * @property {number} [multipleOf=1] The multiple the shard count should round up to. (16 for large bot sharding) + */ + +/** + * Gets the recommended shard count from Discord. + * @param {string} token Discord auth token + * @param {FetchRecommendedShardCountOptions} [options] Options for fetching the recommended shard count + * @returns {Promise<number>} The recommended number of shards + */ +async function fetchRecommendedShardCount(token, { guildsPerShard = 1_000, multipleOf = 1 } = {}) { + if (!token) throw new DiscordjsError(ErrorCodes.TokenMissing); + const response = await fetch(RouteBases.api + Routes.gatewayBot(), { + method: 'GET', + headers: { Authorization: `Bot ${token.replace(/^Bot\s*/i, '')}` }, + }); + if (!response.ok) { + if (response.status === 401) throw new DiscordjsError(ErrorCodes.TokenInvalid); + throw response; + } + const { shards } = await response.json(); + return Math.ceil((shards * (1_000 / guildsPerShard)) / multipleOf) * multipleOf; +} + +/** + * Parses emoji info out of a string. The string must be one of: + * * A UTF-8 emoji (no id) + * * A URL-encoded UTF-8 emoji (no id) + * * A Discord custom emoji (`<:name:id>` or `<a:name:id>`) + * @param {string} text Emoji string to parse + * @returns {APIEmoji} Object with `animated`, `name`, and `id` properties + */ +function parseEmoji(text) { + if (text.includes('%')) text = decodeURIComponent(text); + if (!text.includes(':')) return { animated: false, name: text, id: undefined }; + const match = text.match(/<?(?:(a):)?(\w{2,32}):(\d{17,19})?>?/); + return match && { animated: Boolean(match[1]), name: match[2], id: match[3] }; +} + +/** + * Resolves a partial emoji object from an {@link EmojiIdentifierResolvable}, without checking a Client. + * @param {EmojiIdentifierResolvable} emoji Emoji identifier to resolve + * @returns {?RawEmoji} + * @private + */ +function resolvePartialEmoji(emoji) { + if (!emoji) return null; + if (typeof emoji === 'string') return /^\d{17,19}$/.test(emoji) ? { id: emoji } : parseEmoji(emoji); + const { id, name, animated } = emoji; + if (!id && !name) return null; + return { id, name, animated: Boolean(animated) }; +} + +/** + * Sets default properties on an object that aren't already specified. + * @param {Object} def Default properties + * @param {Object} given Object to assign defaults to + * @returns {Object} + * @private + */ +function mergeDefault(def, given) { + if (!given) return def; + for (const key in def) { + if (!Object.hasOwn(given, key) || given[key] === undefined) { + given[key] = def[key]; + } else if (given[key] === Object(given[key])) { + given[key] = mergeDefault(def[key], given[key]); + } + } + + return given; +} + +/** + * Options used to make an error object. + * @typedef {Object} MakeErrorOptions + * @property {string} name Error type + * @property {string} message Message for the error + * @property {string} stack Stack for the error + */ + +/** + * Makes an Error from a plain info object. + * @param {MakeErrorOptions} obj Error info + * @returns {Error} + * @private + */ +function makeError(obj) { + const err = new Error(obj.message); + err.name = obj.name; + err.stack = obj.stack; + return err; +} + +/** + * Makes a plain error info object from an Error. + * @param {Error} err Error to get info from + * @returns {MakeErrorOptions} + * @private + */ +function makePlainError(err) { + return { + name: err.name, + message: err.message, + stack: err.stack, + }; +} + +const TextSortableGroupTypes = [ChannelType.GuildText, ChannelType.GuildAnnouncement, ChannelType.GuildForum]; +const VoiceSortableGroupTypes = [ChannelType.GuildVoice, ChannelType.GuildStageVoice]; +const CategorySortableGroupTypes = [ChannelType.GuildCategory]; + +/** + * Gets an array of the channel types that can be moved in the channel group. For example, a GuildText channel would + * return an array containing the types that can be ordered within the text channels (always at the top), and a voice + * channel would return an array containing the types that can be ordered within the voice channels (always at the + * bottom). + * @param {ChannelType} type The type of the channel + * @returns {ChannelType[]} + * @private + */ +function getSortableGroupTypes(type) { + switch (type) { + case ChannelType.GuildText: + case ChannelType.GuildAnnouncement: + case ChannelType.GuildForum: + return TextSortableGroupTypes; + case ChannelType.GuildVoice: + case ChannelType.GuildStageVoice: + return VoiceSortableGroupTypes; + case ChannelType.GuildCategory: + return CategorySortableGroupTypes; + default: + return [type]; + } +} + +/** + * Moves an element in an array *in place*. + * @param {Array<*>} array Array to modify + * @param {*} element Element to move + * @param {number} newIndex Index or offset to move the element to + * @param {boolean} [offset=false] Move the element by an offset amount rather than to a set index + * @returns {number} + * @private + */ +function moveElementInArray(array, element, newIndex, offset = false) { + const index = array.indexOf(element); + newIndex = (offset ? index : 0) + newIndex; + if (newIndex > -1 && newIndex < array.length) { + const removedElement = array.splice(index, 1)[0]; + array.splice(newIndex, 0, removedElement); + } + return array.indexOf(element); +} + +/** + * Verifies the provided data is a string, otherwise throws provided error. + * @param {string} data The string resolvable to resolve + * @param {Function} [error] The Error constructor to instantiate. Defaults to Error + * @param {string} [errorMessage] The error message to throw with. Defaults to "Expected string, got <data> instead." + * @param {boolean} [allowEmpty=true] Whether an empty string should be allowed + * @returns {string} + */ +function verifyString( + data, + error = Error, + errorMessage = `Expected a string, got ${data} instead.`, + allowEmpty = true, +) { + if (typeof data !== 'string') throw new error(errorMessage); + if (!allowEmpty && data.length === 0) throw new error(errorMessage); + return data; +} + +/** + * Can be a number, hex string, an RGB array like: + * ```js + * [255, 0, 255] // purple + * ``` + * or one of the following strings: + * - `Default` + * - `White` + * - `Aqua` + * - `Green` + * - `Blue` + * - `Yellow` + * - `Purple` + * - `LuminousVividPink` + * - `Fuchsia` + * - `Gold` + * - `Orange` + * - `Red` + * - `Grey` + * - `Navy` + * - `DarkAqua` + * - `DarkGreen` + * - `DarkBlue` + * - `DarkPurple` + * - `DarkVividPink` + * - `DarkGold` + * - `DarkOrange` + * - `DarkRed` + * - `DarkGrey` + * - `DarkerGrey` + * - `LightGrey` + * - `DarkNavy` + * - `Blurple` + * - `Greyple` + * - `DarkButNotBlack` + * - `NotQuiteBlack` + * - `Random` + * @typedef {string|number|number[]} ColorResolvable + */ + +/** + * Resolves a ColorResolvable into a color number. + * @param {ColorResolvable} color Color to resolve + * @returns {number} A color + */ +function resolveColor(color) { + if (typeof color === 'string') { + if (color === 'Random') return Math.floor(Math.random() * (0xffffff + 1)); + if (color === 'Default') return 0; + if (/^#?[\da-f]{6}$/i.test(color)) return parseInt(color.replace('#', ''), 16); + color = Colors[color]; + } else if (Array.isArray(color)) { + color = (color[0] << 16) + (color[1] << 8) + color[2]; + } + + if (color < 0 || color > 0xffffff) throw new DiscordjsRangeError(ErrorCodes.ColorRange); + if (typeof color !== 'number' || Number.isNaN(color)) throw new DiscordjsTypeError(ErrorCodes.ColorConvert); + + return color; +} + +/** + * Sorts by Discord's position and id. + * @param {Collection} collection Collection of objects to sort + * @returns {Collection} + */ +function discordSort(collection) { + const isGuildChannel = collection.first() instanceof GuildChannel; + return collection.sorted( + isGuildChannel + ? (a, b) => a.rawPosition - b.rawPosition || Number(BigInt(a.id) - BigInt(b.id)) + : (a, b) => a.rawPosition - b.rawPosition || Number(BigInt(b.id) - BigInt(a.id)), + ); +} + +/** + * Sets the position of a Channel or Role. + * @param {BaseChannel|Role} item Object to set the position of + * @param {number} position New position for the object + * @param {boolean} relative Whether `position` is relative to its current position + * @param {Collection<string, BaseChannel|Role>} sorted A collection of the objects sorted properly + * @param {Client} client The client to use to patch the data + * @param {string} route Route to call PATCH on + * @param {string} [reason] Reason for the change + * @returns {Promise<BaseChannel[]|Role[]>} Updated item list, with `id` and `position` properties + * @private + */ +async function setPosition(item, position, relative, sorted, client, route, reason) { + let updatedItems = [...sorted.values()]; + moveElementInArray(updatedItems, item, position, relative); + updatedItems = updatedItems.map((r, i) => ({ id: r.id, position: i })); + await client.rest.patch(route, { body: updatedItems, reason }); + return updatedItems; +} + +/** + * Alternative to Node's `path.basename`, removing query string after the extension if it exists. + * @param {string} path Path to get the basename of + * @param {string} [ext] File extension to remove + * @returns {string} Basename of the path + * @private + */ +function basename(path, ext) { + const res = parse(path); + return ext && res.ext.startsWith(ext) ? res.name : res.base.split('?')[0]; +} + +/** + * The content to have all mentions replaced by the equivalent text. + * @param {string} str The string to be converted + * @param {TextBasedChannels} channel The channel the string was sent in + * @returns {string} + */ +function cleanContent(str, channel) { + return str.replaceAll(/<(@[!&]?|#)(\d{17,19})>/g, (match, type, id) => { + switch (type) { + case '@': + case '@!': { + const member = channel.guild?.members.cache.get(id); + if (member) { + return `@${member.displayName}`; + } + + const user = channel.client.users.cache.get(id); + return user ? `@${user.username}` : match; + } + case '@&': { + if (channel.type === ChannelType.DM) return match; + const role = channel.guild.roles.cache.get(id); + return role ? `@${role.name}` : match; + } + case '#': { + const mentionedChannel = channel.client.channels.cache.get(id); + return mentionedChannel ? `#${mentionedChannel.name}` : match; + } + default: { + return match; + } + } + }); +} + +/** + * The content to put in a code block with all code block fences replaced by the equivalent backticks. + * @param {string} text The string to be converted + * @returns {string} + */ +function cleanCodeBlockContent(text) { + return text.replaceAll('```', '`\u200b``'); +} + +/** + * Parses a webhook URL for the id and token. + * @param {string} url The URL to parse + * @returns {?WebhookClientDataIdWithToken} `null` if the URL is invalid, otherwise the id and the token + */ +function parseWebhookURL(url) { + const matches = url.match( + /https?:\/\/(?:ptb\.|canary\.)?discord\.com\/api(?:\/v\d{1,2})?\/webhooks\/(\d{17,19})\/([\w-]{68})/i, + ); + + if (!matches || matches.length <= 2) return null; + + const [, id, token] = matches; + return { + id, + token, + }; +} + +module.exports = { + flatten, + fetchRecommendedShardCount, + parseEmoji, + resolvePartialEmoji, + mergeDefault, + makeError, + makePlainError, + getSortableGroupTypes, + moveElementInArray, + verifyString, + resolveColor, + discordSort, + setPosition, + basename, + cleanContent, + cleanCodeBlockContent, + parseWebhookURL, +}; + +// Fixes Circular +const GuildChannel = require('../structures/GuildChannel'); diff --git a/node_modules/discord.js/src/util/WebSocketShardEvents.js b/node_modules/discord.js/src/util/WebSocketShardEvents.js new file mode 100644 index 0000000..81e05f2 --- /dev/null +++ b/node_modules/discord.js/src/util/WebSocketShardEvents.js @@ -0,0 +1,25 @@ +'use strict'; + +/** + * @typedef {Object} WebSocketShardEvents + * @property {string} Close close + * @property {string} Destroyed destroyed + * @property {string} InvalidSession invalidSession + * @property {string} Ready ready + * @property {string} Resumed resumed + * @property {string} AllReady allReady + */ + +// JSDoc for IntelliSense purposes +/** + * @type {WebSocketShardEvents} + * @ignore + */ +module.exports = { + Close: 'close', + Destroyed: 'destroyed', + InvalidSession: 'invalidSession', + Ready: 'ready', + Resumed: 'resumed', + AllReady: 'allReady', +}; diff --git a/node_modules/discord.js/typings/index.d.ts b/node_modules/discord.js/typings/index.d.ts new file mode 100644 index 0000000..fda9b4c --- /dev/null +++ b/node_modules/discord.js/typings/index.d.ts @@ -0,0 +1,6520 @@ +// DOM types required for undici +/// <reference lib="dom" /> + +import { + ActionRowBuilder as BuilderActionRow, + MessageActionRowComponentBuilder, + blockQuote, + bold, + ButtonBuilder as BuilderButtonComponent, + channelMention, + codeBlock, + EmbedBuilder as BuildersEmbed, + formatEmoji, + hideLinkEmbed, + hyperlink, + inlineCode, + italic, + quote, + roleMention, + ChannelSelectMenuBuilder as BuilderChannelSelectMenuComponent, + MentionableSelectMenuBuilder as BuilderMentionableSelectMenuComponent, + RoleSelectMenuBuilder as BuilderRoleSelectMenuComponent, + StringSelectMenuBuilder as BuilderStringSelectMenuComponent, + UserSelectMenuBuilder as BuilderUserSelectMenuComponent, + TextInputBuilder as BuilderTextInputComponent, + SelectMenuOptionBuilder as BuildersSelectMenuOption, + spoiler, + strikethrough, + time, + TimestampStyles, + underscore, + userMention, + ModalActionRowComponentBuilder, + ModalBuilder as BuildersModal, + AnyComponentBuilder, + ComponentBuilder, + type RestOrArray, + ApplicationCommandOptionAllowedChannelTypes, +} from '@discordjs/builders'; +import { Awaitable, JSONEncodable } from '@discordjs/util'; +import { Collection } from '@discordjs/collection'; +import { BaseImageURLOptions, ImageURLOptions, RawFile, REST, RESTOptions } from '@discordjs/rest'; +import { + WebSocketManager as WSWebSocketManager, + IShardingStrategy, + IIdentifyThrottler, + SessionInfo, +} from '@discordjs/ws'; +import { + APIActionRowComponent, + APIApplicationCommandInteractionData, + APIApplicationCommandOption, + APIAuditLogChange, + APIButtonComponent, + APIEmbed, + APIEmoji, + APIInteractionDataResolvedChannel, + APIInteractionDataResolvedGuildMember, + APIInteractionGuildMember, + APIMessage, + APIMessageComponent, + APIOverwrite, + APIPartialChannel, + APIPartialEmoji, + APIPartialGuild, + APIRole, + APISelectMenuComponent, + APITemplateSerializedSourceGuild, + APIUser, + ButtonStyle, + ChannelType, + ComponentType, + GatewayDispatchEvents, + GatewayVoiceServerUpdateDispatchData, + GatewayVoiceStateUpdateDispatchData, + GuildFeature, + GuildMFALevel, + GuildNSFWLevel, + GuildPremiumTier, + GuildVerificationLevel, + Locale, + InteractionType, + InviteTargetType, + MessageType, + OAuth2Scopes, + RESTPostAPIApplicationCommandsJSONBody, + Snowflake, + StageInstancePrivacyLevel, + StickerFormatType, + StickerType, + TeamMemberMembershipState, + WebhookType, + OverwriteType, + GuildExplicitContentFilter, + GuildDefaultMessageNotifications, + ApplicationCommandPermissionType, + ApplicationCommandOptionType, + ApplicationCommandType, + ActivityType, + GuildScheduledEventEntityType, + GuildScheduledEventPrivacyLevel, + GuildScheduledEventStatus, + IntegrationExpireBehavior, + ApplicationFlags, + PermissionFlagsBits, + ThreadMemberFlags, + UserFlags, + MessageFlags, + GuildSystemChannelFlags, + GatewayIntentBits, + ActivityFlags, + AuditLogEvent, + APIMessageComponentEmoji, + EmbedType, + APIActionRowComponentTypes, + APIModalInteractionResponseCallbackData, + APIModalSubmitInteraction, + APIMessageActionRowComponent, + TextInputStyle, + APITextInputComponent, + APIModalActionRowComponent, + APIModalComponent, + APISelectMenuOption, + APIEmbedField, + APIEmbedAuthor, + APIEmbedFooter, + APIEmbedImage, + VideoQualityMode, + LocalizationMap, + LocaleString, + MessageActivityType, + APIAttachment, + APIChannel, + ThreadAutoArchiveDuration, + FormattingPatterns, + APIEmbedProvider, + AuditLogOptionsType, + TextChannelType, + ChannelFlags, + SortOrderType, + APIMessageStringSelectInteractionData, + APIMessageUserSelectInteractionData, + APIStringSelectComponent, + APIUserSelectComponent, + APIRoleSelectComponent, + APIMentionableSelectComponent, + APIChannelSelectComponent, + APIGuildMember, + APIMessageRoleSelectInteractionData, + APIMessageMentionableSelectInteractionData, + APIMessageChannelSelectInteractionData, + AutoModerationRuleKeywordPresetType, + AutoModerationActionType, + AutoModerationRuleEventType, + AutoModerationRuleTriggerType, + AuditLogRuleTriggerType, + GatewayAutoModerationActionExecutionDispatchData, + APIAutoModerationRule, + ForumLayoutType, + ApplicationRoleConnectionMetadataType, + APIApplicationRoleConnectionMetadata, + ImageFormat, + GuildMemberFlags, + RESTGetAPIGuildThreadsResult, + RESTGetAPIGuildOnboardingResult, + APIGuildOnboardingPrompt, + APIGuildOnboardingPromptOption, + GuildOnboardingPromptType, + AttachmentFlags, + RoleFlags, +} from 'discord-api-types/v10'; +import { ChildProcess } from 'node:child_process'; +import { EventEmitter } from 'node:events'; +import { Stream } from 'node:stream'; +import { MessagePort, Worker } from 'node:worker_threads'; +import * as WebSocket from 'ws'; +import { + RawActivityData, + RawAnonymousGuildData, + RawApplicationCommandData, + RawApplicationData, + RawBaseGuildData, + RawChannelData, + RawClientApplicationData, + RawDMChannelData, + RawEmojiData, + RawGuildAuditLogData, + RawGuildAuditLogEntryData, + RawGuildBanData, + RawGuildChannelData, + RawGuildData, + RawGuildEmojiData, + RawGuildMemberData, + RawGuildPreviewData, + RawGuildScheduledEventData, + RawGuildTemplateData, + RawIntegrationApplicationData, + RawIntegrationData, + RawInteractionData, + RawInviteData, + RawInviteGuildData, + RawInviteStageInstance, + RawMessageButtonInteractionData, + RawMessageComponentInteractionData, + RawMessageData, + RawMessagePayloadData, + RawMessageReactionData, + RawOAuth2GuildData, + RawPartialGroupDMChannelData, + RawPartialMessageData, + RawPermissionOverwriteData, + RawPresenceData, + RawReactionEmojiData, + RawRichPresenceAssets, + RawRoleData, + RawStageInstanceData, + RawStickerData, + RawStickerPackData, + RawTeamData, + RawTeamMemberData, + RawThreadChannelData, + RawThreadMemberData, + RawTypingData, + RawUserData, + RawVoiceRegionData, + RawVoiceStateData, + RawWebhookData, + RawWelcomeChannelData, + RawWelcomeScreenData, + RawWidgetData, + RawWidgetMemberData, +} from './rawDataTypes'; + +declare module 'node:events' { + class EventEmitter { + // Add type overloads for client events. + public static once<E extends EventEmitter, K extends keyof ClientEvents>( + eventEmitter: E, + eventName: E extends Client ? K : string, + ): Promise<E extends Client ? ClientEvents[K] : any[]>; + public static on<E extends EventEmitter, K extends keyof ClientEvents>( + eventEmitter: E, + eventName: E extends Client ? K : string, + ): AsyncIterableIterator<E extends Client ? ClientEvents[K] : any>; + } +} + +//#region Classes + +export class Activity { + private constructor(presence: Presence, data?: RawActivityData); + public readonly presence: Presence; + public applicationId: Snowflake | null; + public assets: RichPresenceAssets | null; + public buttons: string[]; + public get createdAt(): Date; + public createdTimestamp: number; + public details: string | null; + public emoji: Emoji | null; + public flags: Readonly<ActivityFlagsBitField>; + public name: string; + public party: { + id: string | null; + size: [number, number]; + } | null; + public state: string | null; + public timestamps: { + start: Date | null; + end: Date | null; + } | null; + public type: ActivityType; + public url: string | null; + public equals(activity: Activity): boolean; + public toString(): string; +} + +export type ActivityFlagsString = keyof typeof ActivityFlags; + +export interface BaseComponentData { + type: ComponentType; +} + +export type MessageActionRowComponentData = + | JSONEncodable<APIMessageActionRowComponent> + | ButtonComponentData + | StringSelectMenuComponentData + | UserSelectMenuComponentData + | RoleSelectMenuComponentData + | MentionableSelectMenuComponentData + | ChannelSelectMenuComponentData; + +export type ModalActionRowComponentData = JSONEncodable<APIModalActionRowComponent> | TextInputComponentData; + +export type ActionRowComponentData = MessageActionRowComponentData | ModalActionRowComponentData; + +export type ActionRowComponent = MessageActionRowComponent | ModalActionRowComponent; + +export interface ActionRowData<T extends JSONEncodable<APIActionRowComponentTypes> | ActionRowComponentData> + extends BaseComponentData { + components: T[]; +} + +export class ActionRowBuilder<T extends AnyComponentBuilder = AnyComponentBuilder> extends BuilderActionRow<T> { + constructor( + data?: Partial< + | ActionRowData<ActionRowComponentData | JSONEncodable<APIActionRowComponentTypes>> + | APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent> + >, + ); + public static from<T extends AnyComponentBuilder = AnyComponentBuilder>( + other: + | JSONEncodable<APIActionRowComponent<ReturnType<T['toJSON']>>> + | APIActionRowComponent<ReturnType<T['toJSON']>>, + ): ActionRowBuilder<T>; +} + +export type MessageActionRowComponent = + | ButtonComponent + | StringSelectMenuComponent + | UserSelectMenuComponent + | RoleSelectMenuComponent + | MentionableSelectMenuComponent + | ChannelSelectMenuComponent; +export type ModalActionRowComponent = TextInputComponent; + +export class ActionRow<T extends MessageActionRowComponent | ModalActionRowComponent> extends Component< + APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent> +> { + private constructor(data: APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent>); + public readonly components: T[]; + public toJSON(): APIActionRowComponent<ReturnType<T['toJSON']>>; +} + +export class ActivityFlagsBitField extends BitField<ActivityFlagsString> { + public static Flags: typeof ActivityFlags; + public static resolve(bit?: BitFieldResolvable<ActivityFlagsString, number>): number; +} + +export abstract class AnonymousGuild extends BaseGuild { + protected constructor(client: Client<true>, data: RawAnonymousGuildData, immediatePatch?: boolean); + public banner: string | null; + public description: string | null; + public nsfwLevel: GuildNSFWLevel; + public premiumSubscriptionCount: number | null; + public splash: string | null; + public vanityURLCode: string | null; + public verificationLevel: GuildVerificationLevel; + public bannerURL(options?: ImageURLOptions): string | null; + public splashURL(options?: ImageURLOptions): string | null; +} + +export class AutoModerationActionExecution { + private constructor(data: GatewayAutoModerationActionExecutionDispatchData, guild: Guild); + public guild: Guild; + public action: AutoModerationAction; + public ruleId: Snowflake; + public ruleTriggerType: AutoModerationRuleTriggerType; + public get user(): User | null; + public userId: Snowflake; + public get channel(): GuildTextBasedChannel | ForumChannel | null; + public channelId: Snowflake | null; + public get member(): GuildMember | null; + public messageId: Snowflake | null; + public alertSystemMessageId: Snowflake | null; + public content: string; + public matchedKeyword: string | null; + public matchedContent: string | null; + public get autoModerationRule(): AutoModerationRule | null; +} + +export class AutoModerationRule extends Base { + private constructor(client: Client<true>, data: APIAutoModerationRule, guild: Guild); + public id: Snowflake; + public guild: Guild; + public name: string; + public creatorId: Snowflake; + public eventType: AutoModerationRuleEventType; + public triggerType: AutoModerationRuleTriggerType; + public triggerMetadata: AutoModerationTriggerMetadata; + public actions: AutoModerationAction[]; + public enabled: boolean; + public exemptRoles: Collection<Snowflake, Role>; + public exemptChannels: Collection<Snowflake, GuildBasedChannel>; + public edit(options: AutoModerationRuleEditOptions): Promise<AutoModerationRule>; + public delete(reason?: string): Promise<void>; + public setName(name: string, reason?: string): Promise<AutoModerationRule>; + public setEventType(eventType: AutoModerationRuleEventType, reason?: string): Promise<AutoModerationRule>; + public setKeywordFilter(keywordFilter: string[], reason?: string): Promise<AutoModerationRule>; + public setRegexPatterns(regexPatterns: string[], reason?: string): Promise<AutoModerationRule>; + public setPresets(presets: AutoModerationRuleKeywordPresetType[], reason?: string): Promise<AutoModerationRule>; + public setAllowList(allowList: string[], reason?: string): Promise<AutoModerationRule>; + public setMentionTotalLimit(mentionTotalLimit: number, reason?: string): Promise<AutoModerationRule>; + public setMentionRaidProtectionEnabled( + mentionRaidProtectionEnabled: boolean, + reason?: string, + ): Promise<AutoModerationRule>; + public setActions(actions: AutoModerationActionOptions[], reason?: string): Promise<AutoModerationRule>; + public setEnabled(enabled?: boolean, reason?: string): Promise<AutoModerationRule>; + public setExemptRoles( + roles: Collection<Snowflake, Role> | RoleResolvable[], + reason?: string, + ): Promise<AutoModerationRule>; + public setExemptChannels( + channels: Collection<Snowflake, GuildBasedChannel> | GuildChannelResolvable[], + reason?: string, + ): Promise<AutoModerationRule>; +} + +export abstract class Application extends Base { + protected constructor(client: Client<true>, data: RawApplicationData); + public get createdAt(): Date; + public get createdTimestamp(): number; + public description: string | null; + public icon: string | null; + public id: Snowflake; + public name: string | null; + public coverURL(options?: ImageURLOptions): string | null; + public iconURL(options?: ImageURLOptions): string | null; + public toJSON(): unknown; + public toString(): string | null; +} + +export class ApplicationCommand<PermissionsFetchType = {}> extends Base { + private constructor(client: Client<true>, data: RawApplicationCommandData, guild?: Guild, guildId?: Snowflake); + public applicationId: Snowflake; + public get createdAt(): Date; + public get createdTimestamp(): number; + public defaultMemberPermissions: Readonly<PermissionsBitField> | null; + public description: string; + public descriptionLocalizations: LocalizationMap | null; + public descriptionLocalized: string | null; + public dmPermission: boolean | null; + public guild: Guild | null; + public guildId: Snowflake | null; + public get manager(): ApplicationCommandManager; + public id: Snowflake; + public name: string; + public nameLocalizations: LocalizationMap | null; + public nameLocalized: string | null; + public options: (ApplicationCommandOption & { nameLocalized?: string; descriptionLocalized?: string })[]; + public permissions: ApplicationCommandPermissionsManager< + PermissionsFetchType, + PermissionsFetchType, + Guild | null, + Snowflake + >; + public type: ApplicationCommandType; + public version: Snowflake; + public nsfw: boolean; + public delete(): Promise<ApplicationCommand<PermissionsFetchType>>; + public edit(data: Partial<ApplicationCommandData>): Promise<ApplicationCommand<PermissionsFetchType>>; + public setName(name: string): Promise<ApplicationCommand<PermissionsFetchType>>; + public setNameLocalizations(nameLocalizations: LocalizationMap): Promise<ApplicationCommand<PermissionsFetchType>>; + public setDescription(description: string): Promise<ApplicationCommand<PermissionsFetchType>>; + public setDescriptionLocalizations( + descriptionLocalizations: LocalizationMap, + ): Promise<ApplicationCommand<PermissionsFetchType>>; + public setDefaultMemberPermissions( + defaultMemberPermissions: PermissionResolvable | null, + ): Promise<ApplicationCommand<PermissionsFetchType>>; + public setDMPermission(dmPermission?: boolean): Promise<ApplicationCommand<PermissionsFetchType>>; + public setOptions(options: ApplicationCommandOptionData[]): Promise<ApplicationCommand<PermissionsFetchType>>; + public equals( + command: ApplicationCommand | ApplicationCommandData | RawApplicationCommandData, + enforceOptionOrder?: boolean, + ): boolean; + public static optionsEqual( + existing: ApplicationCommandOption[], + options: ApplicationCommandOption[] | ApplicationCommandOptionData[] | APIApplicationCommandOption[], + enforceOptionOrder?: boolean, + ): boolean; + private static _optionEquals( + existing: ApplicationCommandOption, + options: ApplicationCommandOption | ApplicationCommandOptionData | APIApplicationCommandOption, + enforceOptionOrder?: boolean, + ): boolean; + private static transformOption(option: ApplicationCommandOptionData, received?: boolean): unknown; + private static transformCommand(command: ApplicationCommandData): RESTPostAPIApplicationCommandsJSONBody; + private static isAPICommandData(command: object): command is RESTPostAPIApplicationCommandsJSONBody; +} + +export class ApplicationRoleConnectionMetadata { + private constructor(data: APIApplicationRoleConnectionMetadata); + public name: string; + public nameLocalizations: LocalizationMap | null; + public description: string; + public descriptionLocalizations: LocalizationMap | null; + public key: string; + public type: ApplicationRoleConnectionMetadataType; +} + +export type ApplicationResolvable = Application | Activity | Snowflake; + +export class ApplicationFlagsBitField extends BitField<ApplicationFlagsString> { + public static Flags: typeof ApplicationFlags; + public static resolve(bit?: BitFieldResolvable<ApplicationFlagsString, number>): number; +} + +export type AutoModerationRuleResolvable = AutoModerationRule | Snowflake; + +export abstract class Base { + public constructor(client: Client<true>); + public readonly client: Client<true>; + public toJSON(...props: Record<string, boolean | string>[]): unknown; + public valueOf(): string; +} + +export class BaseClient extends EventEmitter { + public constructor(options?: ClientOptions | WebhookClientOptions); + private decrementMaxListeners(): void; + private incrementMaxListeners(): void; + + public options: ClientOptions | WebhookClientOptions; + public rest: REST; + public destroy(): void; + public toJSON(...props: Record<string, boolean | string>[]): unknown; +} + +export type GuildCacheMessage<Cached extends CacheType> = CacheTypeReducer< + Cached, + Message<true>, + APIMessage, + Message | APIMessage, + Message | APIMessage +>; + +export type BooleanCache<T extends CacheType> = T extends 'cached' ? true : false; + +export abstract class CommandInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> { + public type: InteractionType.ApplicationCommand; + public get command(): ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null; + public options: Omit< + CommandInteractionOptionResolver<Cached>, + | 'getMessage' + | 'getFocused' + | 'getMentionable' + | 'getRole' + | 'getAttachment' + | 'getNumber' + | 'getInteger' + | 'getString' + | 'getChannel' + | 'getBoolean' + | 'getSubcommandGroup' + | 'getSubcommand' + >; + public channelId: Snowflake; + public commandId: Snowflake; + public commandName: string; + public commandType: ApplicationCommandType; + public commandGuildId: Snowflake | null; + public deferred: boolean; + public ephemeral: boolean | null; + public replied: boolean; + public webhook: InteractionWebhook; + public inGuild(): this is CommandInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is CommandInteraction<'cached'>; + public inRawGuild(): this is CommandInteraction<'raw'>; + public deferReply( + options: InteractionDeferReplyOptions & { fetchReply: true }, + ): Promise<Message<BooleanCache<Cached>>>; + public deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse<BooleanCache<Cached>>>; + public deleteReply(message?: MessageResolvable | '@original'): Promise<void>; + public editReply( + options: string | MessagePayload | InteractionEditReplyOptions, + ): Promise<Message<BooleanCache<Cached>>>; + public fetchReply(message?: Snowflake | '@original'): Promise<Message<BooleanCache<Cached>>>; + public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<Message<BooleanCache<Cached>>>; + public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<Message<BooleanCache<Cached>>>; + public reply( + options: string | MessagePayload | InteractionReplyOptions, + ): Promise<InteractionResponse<BooleanCache<Cached>>>; + public showModal( + modal: + | JSONEncodable<APIModalInteractionResponseCallbackData> + | ModalComponentData + | APIModalInteractionResponseCallbackData, + ): Promise<void>; + public awaitModalSubmit( + options: AwaitModalSubmitOptions<ModalSubmitInteraction>, + ): Promise<ModalSubmitInteraction<Cached>>; + private transformOption( + option: APIApplicationCommandOption, + resolved: APIApplicationCommandInteractionData['resolved'], + ): CommandInteractionOption<Cached>; + private transformResolved( + resolved: APIApplicationCommandInteractionData['resolved'], + ): CommandInteractionResolvedData<Cached>; +} + +export class InteractionResponse<Cached extends boolean = boolean> { + private constructor(interaction: Interaction, id?: Snowflake); + public interaction: Interaction<WrapBooleanCache<Cached>>; + public client: Client; + public id: Snowflake; + public get createdAt(): Date; + public get createdTimestamp(): number; + public awaitMessageComponent<T extends MessageComponentType>( + options?: AwaitMessageCollectorOptionsParams<T, Cached>, + ): Promise<MappedInteractionTypes<Cached>[T]>; + public createMessageComponentCollector<T extends MessageComponentType>( + options?: MessageCollectorOptionsParams<T, Cached>, + ): InteractionCollector<MappedInteractionTypes<Cached>[T]>; + public delete(): Promise<void>; + public edit(options: string | MessagePayload | WebhookMessageEditOptions): Promise<Message>; + public fetch(): Promise<Message>; +} + +export abstract class BaseGuild extends Base { + protected constructor(client: Client<true>, data: RawBaseGuildData); + public get createdAt(): Date; + public get createdTimestamp(): number; + public features: `${GuildFeature}`[]; + public icon: string | null; + public id: Snowflake; + public name: string; + public get nameAcronym(): string; + public get partnered(): boolean; + public get verified(): boolean; + public fetch(): Promise<Guild>; + public iconURL(options?: ImageURLOptions): string | null; + public toString(): string; +} + +export class BaseGuildEmoji extends Emoji { + protected constructor(client: Client<true>, data: RawGuildEmojiData, guild: Guild | GuildPreview); + public available: boolean | null; + public get createdAt(): Date; + public get createdTimestamp(): number; + public guild: Guild | GuildPreview; + public id: Snowflake; + public managed: boolean | null; + public requiresColons: boolean | null; +} + +export class BaseGuildTextChannel extends TextBasedChannelMixin(GuildChannel, true) { + protected constructor(guild: Guild, data?: RawGuildChannelData, client?: Client<true>, immediatePatch?: boolean); + public defaultAutoArchiveDuration?: ThreadAutoArchiveDuration; + public rateLimitPerUser: number | null; + public nsfw: boolean; + public threads: GuildTextThreadManager<AllowedThreadTypeForTextChannel | AllowedThreadTypeForNewsChannel>; + public topic: string | null; + public createInvite(options?: InviteCreateOptions): Promise<Invite>; + public fetchInvites(cache?: boolean): Promise<Collection<string, Invite>>; + public setDefaultAutoArchiveDuration( + defaultAutoArchiveDuration: ThreadAutoArchiveDuration, + reason?: string, + ): Promise<this>; + public setTopic(topic: string | null, reason?: string): Promise<this>; + public setType(type: ChannelType.GuildText, reason?: string): Promise<TextChannel>; + public setType(type: ChannelType.GuildAnnouncement, reason?: string): Promise<NewsChannel>; +} + +export class BaseGuildVoiceChannel extends TextBasedChannelMixin(GuildChannel, true, [ + 'lastPinTimestamp', + 'lastPinAt', +]) { + public constructor(guild: Guild, data?: RawGuildChannelData); + public bitrate: number; + public get full(): boolean; + public get joinable(): boolean; + public get members(): Collection<Snowflake, GuildMember>; + public nsfw: boolean; + public rateLimitPerUser: number | null; + public rtcRegion: string | null; + public userLimit: number; + public videoQualityMode: VideoQualityMode | null; + public createInvite(options?: InviteCreateOptions): Promise<Invite>; + public fetchInvites(cache?: boolean): Promise<Collection<string, Invite>>; + public setBitrate(bitrate: number, reason?: string): Promise<this>; + public setRTCRegion(rtcRegion: string | null, reason?: string): Promise<this>; + public setUserLimit(userLimit: number, reason?: string): Promise<this>; + public setVideoQualityMode(videoQualityMode: VideoQualityMode, reason?: string): Promise<this>; +} + +export type EnumLike<E, V> = Record<keyof E, V>; + +export class BitField<S extends string, N extends number | bigint = number> { + public constructor(bits?: BitFieldResolvable<S, N>); + public bitfield: N; + public add(...bits: BitFieldResolvable<S, N>[]): BitField<S, N>; + public any(bit: BitFieldResolvable<S, N>): boolean; + public equals(bit: BitFieldResolvable<S, N>): boolean; + public freeze(): Readonly<BitField<S, N>>; + public has(bit: BitFieldResolvable<S, N>): boolean; + public missing(bits: BitFieldResolvable<S, N>, ...hasParams: readonly unknown[]): S[]; + public remove(...bits: BitFieldResolvable<S, N>[]): BitField<S, N>; + public serialize(...hasParams: readonly unknown[]): Record<S, boolean>; + public toArray(...hasParams: readonly unknown[]): S[]; + public toJSON(): N extends number ? number : string; + public valueOf(): N; + public [Symbol.iterator](): IterableIterator<S>; + public static Flags: EnumLike<unknown, number | bigint>; + public static resolve(bit?: BitFieldResolvable<string, number | bigint>): number | bigint; +} + +export class ButtonInteraction<Cached extends CacheType = CacheType> extends MessageComponentInteraction<Cached> { + private constructor(client: Client<true>, data: RawMessageButtonInteractionData); + public componentType: ComponentType.Button; + public get component(): CacheTypeReducer< + Cached, + ButtonComponent, + APIButtonComponent, + ButtonComponent | APIButtonComponent, + ButtonComponent | APIButtonComponent + >; + public inGuild(): this is ButtonInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is ButtonInteraction<'cached'>; + public inRawGuild(): this is ButtonInteraction<'raw'>; +} + +export type AnyComponent = + | APIMessageComponent + | APIModalComponent + | APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent>; + +export class Component<T extends AnyComponent = AnyComponent> { + public readonly data: Readonly<T>; + public get type(): T['type']; + public toJSON(): T; + public equals(other: this | T): boolean; +} + +export class ButtonComponent extends Component<APIButtonComponent> { + private constructor(data: APIButtonComponent); + public get style(): ButtonStyle; + public get label(): string | null; + public get emoji(): APIMessageComponentEmoji | null; + public get disabled(): boolean; + public get customId(): string | null; + public get url(): string | null; +} + +export type ComponentEmojiResolvable = APIMessageComponentEmoji | string; + +export class ButtonBuilder extends BuilderButtonComponent { + public constructor(data?: Partial<ButtonComponentData> | Partial<APIButtonComponent>); + public static from(other: JSONEncodable<APIButtonComponent> | APIButtonComponent): ButtonBuilder; + public override setEmoji(emoji: ComponentEmojiResolvable): this; +} + +export class StringSelectMenuBuilder extends BuilderStringSelectMenuComponent { + public constructor(data?: Partial<StringSelectMenuComponentData | APIStringSelectComponent>); + private static normalizeEmoji( + selectMenuOption: JSONEncodable<APISelectMenuOption> | SelectMenuComponentOptionData, + ): (APISelectMenuOption | StringSelectMenuOptionBuilder)[]; + public override addOptions( + ...options: RestOrArray<BuildersSelectMenuOption | SelectMenuComponentOptionData | APISelectMenuOption> + ): this; + public override setOptions( + ...options: RestOrArray<BuildersSelectMenuOption | SelectMenuComponentOptionData | APISelectMenuOption> + ): this; + public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): StringSelectMenuBuilder; +} + +export { + /** @deprecated Use {@link StringSelectMenuBuilder} instead */ + StringSelectMenuBuilder as SelectMenuBuilder, + /** @deprecated Use {@link StringSelectMenuOptionBuilder} instead */ + StringSelectMenuOptionBuilder as SelectMenuOptionBuilder, +}; + +export class UserSelectMenuBuilder extends BuilderUserSelectMenuComponent { + public constructor(data?: Partial<UserSelectMenuComponentData | APIUserSelectComponent>); + public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): UserSelectMenuBuilder; +} + +export class RoleSelectMenuBuilder extends BuilderRoleSelectMenuComponent { + public constructor(data?: Partial<RoleSelectMenuComponentData | APIRoleSelectComponent>); + public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): RoleSelectMenuBuilder; +} + +export class MentionableSelectMenuBuilder extends BuilderMentionableSelectMenuComponent { + public constructor(data?: Partial<MentionableSelectMenuComponentData | APIMentionableSelectComponent>); + public static from( + other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent, + ): MentionableSelectMenuBuilder; +} + +export class ChannelSelectMenuBuilder extends BuilderChannelSelectMenuComponent { + public constructor(data?: Partial<ChannelSelectMenuComponentData | APIChannelSelectComponent>); + public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): ChannelSelectMenuBuilder; +} + +export class StringSelectMenuOptionBuilder extends BuildersSelectMenuOption { + public constructor(data?: SelectMenuComponentOptionData | APISelectMenuOption); + public override setEmoji(emoji: ComponentEmojiResolvable): this; + public static from(other: JSONEncodable<APISelectMenuOption> | APISelectMenuOption): StringSelectMenuOptionBuilder; +} + +export class ModalBuilder extends BuildersModal { + public constructor(data?: Partial<ModalComponentData> | Partial<APIModalInteractionResponseCallbackData>); + public static from(other: JSONEncodable<APIModalComponent> | APIModalComponent): ModalBuilder; +} + +export class TextInputBuilder extends BuilderTextInputComponent { + public constructor(data?: Partial<TextInputComponentData | APITextInputComponent>); + public static from(other: JSONEncodable<APITextInputComponent> | APITextInputComponent): TextInputBuilder; +} + +export class TextInputComponent extends Component<APITextInputComponent> { + public get customId(): string; + public get value(): string; +} + +export class BaseSelectMenuComponent<Data extends APISelectMenuComponent> extends Component<Data> { + protected constructor(data: Data); + public get placeholder(): string | null; + public get maxValues(): number | null; + public get minValues(): number | null; + public get customId(): string; + public get disabled(): boolean; +} + +export class StringSelectMenuComponent extends BaseSelectMenuComponent<APIStringSelectComponent> { + public get options(): APISelectMenuOption[]; +} + +export { + /** @deprecated Use {@link StringSelectMenuComponent} instead */ + StringSelectMenuComponent as SelectMenuComponent, +}; + +export class UserSelectMenuComponent extends BaseSelectMenuComponent<APIUserSelectComponent> {} + +export class RoleSelectMenuComponent extends BaseSelectMenuComponent<APIRoleSelectComponent> {} + +export class MentionableSelectMenuComponent extends BaseSelectMenuComponent<APIMentionableSelectComponent> {} + +export class ChannelSelectMenuComponent extends BaseSelectMenuComponent<APIChannelSelectComponent> { + public getChannelTypes(): ChannelType[] | null; +} + +export interface EmbedData { + title?: string; + type?: EmbedType; + description?: string; + url?: string; + timestamp?: string | number | Date; + color?: number; + footer?: EmbedFooterData; + image?: EmbedAssetData; + thumbnail?: EmbedAssetData; + provider?: APIEmbedProvider; + author?: EmbedAuthorData; + fields?: APIEmbedField[]; + video?: EmbedAssetData; +} + +export interface IconData { + iconURL?: string; + proxyIconURL?: string; +} + +export type EmbedAuthorData = Omit<APIEmbedAuthor, 'icon_url' | 'proxy_icon_url'> & IconData; + +export type EmbedFooterData = Omit<APIEmbedFooter, 'icon_url' | 'proxy_icon_url'> & IconData; + +export interface EmbedAssetData extends Omit<APIEmbedImage, 'proxy_url'> { + proxyURL?: string; +} + +export class EmbedBuilder extends BuildersEmbed { + public constructor(data?: EmbedData | APIEmbed); + public override setColor(color: ColorResolvable | null): this; + public static from(other: JSONEncodable<APIEmbed> | APIEmbed): EmbedBuilder; + public get length(): number; +} + +export class Embed { + private constructor(data: APIEmbed); + public readonly data: Readonly<APIEmbed>; + public get fields(): APIEmbedField[]; + public get footer(): EmbedFooterData | null; + public get title(): string | null; + public get description(): string | null; + public get url(): string | null; + public get color(): number | null; + public get hexColor(): string | null; + public get timestamp(): string | null; + public get thumbnail(): EmbedAssetData | null; + public get image(): EmbedAssetData | null; + public get author(): EmbedAuthorData | null; + public get provider(): APIEmbedProvider | null; + public get video(): EmbedAssetData | null; + public get length(): number; + public equals(other: Embed | APIEmbed): boolean; + public toJSON(): APIEmbed; +} + +export interface MappedChannelCategoryTypes { + [ChannelType.GuildAnnouncement]: NewsChannel; + [ChannelType.GuildVoice]: VoiceChannel; + [ChannelType.GuildText]: TextChannel; + [ChannelType.GuildStageVoice]: StageChannel; + [ChannelType.GuildForum]: ForumChannel; +} + +export type CategoryChannelType = Exclude< + ChannelType, + | ChannelType.DM + | ChannelType.GroupDM + | ChannelType.PublicThread + | ChannelType.AnnouncementThread + | ChannelType.PrivateThread + | ChannelType.GuildCategory + | ChannelType.GuildDirectory +>; + +export class CategoryChannel extends GuildChannel { + public get children(): CategoryChannelChildManager; + public type: ChannelType.GuildCategory; + public get parent(): null; + public parentId: null; +} + +export type CategoryChannelResolvable = Snowflake | CategoryChannel; + +export type ChannelFlagsString = keyof typeof ChannelFlags; + +export type ChannelFlagsResolvable = BitFieldResolvable<ChannelFlagsString, number>; + +export class ChannelFlagsBitField extends BitField<ChannelFlagsString> { + public static Flags: typeof ChannelFlags; + public static resolve(bit?: BitFieldResolvable<ChannelFlagsString, ChannelFlags>): number; +} + +export abstract class BaseChannel extends Base { + public constructor(client: Client<true>, data?: RawChannelData, immediatePatch?: boolean); + public get createdAt(): Date | null; + public get createdTimestamp(): number | null; + public id: Snowflake; + public flags: Readonly<ChannelFlagsBitField> | null; + public get partial(): false; + public type: ChannelType; + public get url(): string; + public delete(): Promise<this>; + public fetch(force?: boolean): Promise<this>; + public isThread(): this is AnyThreadChannel; + public isTextBased(): this is TextBasedChannel; + public isDMBased(): this is PartialGroupDMChannel | DMChannel | PartialDMChannel; + public isVoiceBased(): this is VoiceBasedChannel; + public toString(): ChannelMention | UserMention; +} + +export type If<T extends boolean, A, B = null> = T extends true ? A : T extends false ? B : A | B; + +export class Client<Ready extends boolean = boolean> extends BaseClient { + public constructor(options: ClientOptions); + private actions: unknown; + private presence: ClientPresence; + private _eval(script: string): unknown; + private _validateOptions(options: ClientOptions): void; + private get _censoredToken(): string | null; + + public application: If<Ready, ClientApplication>; + public channels: ChannelManager; + public get emojis(): BaseGuildEmojiManager; + public guilds: GuildManager; + public options: Omit<ClientOptions, 'intents'> & { intents: IntentsBitField }; + public get readyAt(): If<Ready, Date>; + public readyTimestamp: If<Ready, number>; + public sweepers: Sweepers; + public shard: ShardClientUtil | null; + public token: If<Ready, string, string | null>; + public get uptime(): If<Ready, number>; + public user: If<Ready, ClientUser>; + public users: UserManager; + public voice: ClientVoiceManager; + public ws: WebSocketManager; + public destroy(): Promise<void>; + public deleteWebhook(id: Snowflake, options?: WebhookDeleteOptions): Promise<void>; + public fetchGuildPreview(guild: GuildResolvable): Promise<GuildPreview>; + public fetchInvite(invite: InviteResolvable, options?: ClientFetchInviteOptions): Promise<Invite>; + public fetchGuildTemplate(template: GuildTemplateResolvable): Promise<GuildTemplate>; + public fetchVoiceRegions(): Promise<Collection<string, VoiceRegion>>; + public fetchSticker(id: Snowflake): Promise<Sticker>; + public fetchPremiumStickerPacks(): Promise<Collection<Snowflake, StickerPack>>; + public fetchWebhook(id: Snowflake, token?: string): Promise<Webhook>; + public fetchGuildWidget(guild: GuildResolvable): Promise<Widget>; + public generateInvite(options?: InviteGenerationOptions): string; + public login(token?: string): Promise<string>; + public isReady(): this is Client<true>; + public toJSON(): unknown; + + public on<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => Awaitable<void>): this; + public on<S extends string | symbol>( + event: Exclude<S, keyof ClientEvents>, + listener: (...args: any[]) => Awaitable<void>, + ): this; + + public once<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => Awaitable<void>): this; + public once<S extends string | symbol>( + event: Exclude<S, keyof ClientEvents>, + listener: (...args: any[]) => Awaitable<void>, + ): this; + + public emit<K extends keyof ClientEvents>(event: K, ...args: ClientEvents[K]): boolean; + public emit<S extends string | symbol>(event: Exclude<S, keyof ClientEvents>, ...args: unknown[]): boolean; + + public off<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => Awaitable<void>): this; + public off<S extends string | symbol>( + event: Exclude<S, keyof ClientEvents>, + listener: (...args: any[]) => Awaitable<void>, + ): this; + + public removeAllListeners<K extends keyof ClientEvents>(event?: K): this; + public removeAllListeners<S extends string | symbol>(event?: Exclude<S, keyof ClientEvents>): this; +} + +export class ClientApplication extends Application { + private constructor(client: Client<true>, data: RawClientApplicationData); + public botPublic: boolean | null; + public botRequireCodeGrant: boolean | null; + public commands: ApplicationCommandManager; + public guildId: Snowflake | null; + public get guild(): Guild | null; + public cover: string | null; + public flags: Readonly<ApplicationFlagsBitField>; + public approximateGuildCount: number | null; + public tags: string[]; + public installParams: ClientApplicationInstallParams | null; + public customInstallURL: string | null; + public owner: User | Team | null; + public get partial(): boolean; + public roleConnectionsVerificationURL: string | null; + public rpcOrigins: string[]; + public fetch(): Promise<ClientApplication>; + public fetchRoleConnectionMetadataRecords(): Promise<ApplicationRoleConnectionMetadata[]>; + public editRoleConnectionMetadataRecords( + records: ApplicationRoleConnectionMetadataEditOptions[], + ): Promise<ApplicationRoleConnectionMetadata[]>; +} + +export class ClientPresence extends Presence { + private constructor(client: Client<true>, data: RawPresenceData); + private _parse(data: PresenceData): RawPresenceData; + + public set(presence: PresenceData): ClientPresence; +} + +export class ClientUser extends User { + public mfaEnabled: boolean; + public get presence(): ClientPresence; + public verified: boolean; + public edit(options: ClientUserEditOptions): Promise<this>; + public setActivity(options?: ActivityOptions): ClientPresence; + public setActivity(name: string, options?: Omit<ActivityOptions, 'name'>): ClientPresence; + public setAFK(afk?: boolean, shardId?: number | number[]): ClientPresence; + public setAvatar(avatar: BufferResolvable | Base64Resolvable | null): Promise<this>; + public setPresence(data: PresenceData): ClientPresence; + public setStatus(status: PresenceStatusData, shardId?: number | number[]): ClientPresence; + public setUsername(username: string): Promise<this>; +} + +export class Options extends null { + private constructor(); + private static userAgentAppendix: string; + public static get DefaultMakeCacheSettings(): CacheWithLimitsOptions; + public static get DefaultSweeperSettings(): SweeperOptions; + public static createDefault(): ClientOptions; + public static cacheWithLimits(settings?: CacheWithLimitsOptions): CacheFactory; + public static cacheEverything(): CacheFactory; +} + +export class ClientVoiceManager { + private constructor(client: Client); + public readonly client: Client; + public adapters: Map<Snowflake, InternalDiscordGatewayAdapterLibraryMethods>; +} + +export { Collection } from '@discordjs/collection'; + +export interface CollectorEventTypes<K, V, F extends unknown[] = []> { + collect: [V, ...F]; + ignore: [V, ...F]; + dispose: [V, ...F]; + end: [collected: Collection<K, V>, reason: string]; +} + +export abstract class Collector<K, V, F extends unknown[] = []> extends EventEmitter { + protected constructor(client: Client<true>, options?: CollectorOptions<[V, ...F]>); + private _timeout: NodeJS.Timeout | null; + private _idletimeout: NodeJS.Timeout | null; + private _endReason: string | null; + + public readonly client: Client; + public collected: Collection<K, V>; + public lastCollectedTimestamp: number | null; + public get lastCollectedAt(): Date | null; + public ended: boolean; + public get endReason(): string | null; + public filter: CollectorFilter<[V, ...F]>; + public get next(): Promise<V>; + public options: CollectorOptions<[V, ...F]>; + public checkEnd(): boolean; + public handleCollect(...args: unknown[]): Promise<void>; + public handleDispose(...args: unknown[]): Promise<void>; + public stop(reason?: string): void; + public resetTimer(options?: CollectorResetTimerOptions): void; + public [Symbol.asyncIterator](): AsyncIterableIterator<[V, ...F]>; + public toJSON(): unknown; + + protected listener: (...args: any[]) => void; + public abstract collect(...args: unknown[]): K | null | Promise<K | null>; + public abstract dispose(...args: unknown[]): K | null; + + public on<EventKey extends keyof CollectorEventTypes<K, V, F>>( + event: EventKey, + listener: (...args: CollectorEventTypes<K, V, F>[EventKey]) => Awaitable<void>, + ): this; + + public once<EventKey extends keyof CollectorEventTypes<K, V, F>>( + event: EventKey, + listener: (...args: CollectorEventTypes<K, V, F>[EventKey]) => Awaitable<void>, + ): this; +} + +export class ChatInputCommandInteraction<Cached extends CacheType = CacheType> extends CommandInteraction<Cached> { + public commandType: ApplicationCommandType.ChatInput; + public options: Omit<CommandInteractionOptionResolver<Cached>, 'getMessage' | 'getFocused'>; + public inGuild(): this is ChatInputCommandInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is ChatInputCommandInteraction<'cached'>; + public inRawGuild(): this is ChatInputCommandInteraction<'raw'>; + public toString(): string; +} + +export class AutocompleteInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> { + public type: InteractionType.ApplicationCommandAutocomplete; + public get command(): ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null; + public channelId: Snowflake; + public commandId: Snowflake; + public commandName: string; + public commandType: ApplicationCommandType.ChatInput; + public commandGuildId: Snowflake | null; + public responded: boolean; + public options: Omit< + CommandInteractionOptionResolver<Cached>, + 'getMessage' | 'getUser' | 'getAttachment' | 'getChannel' | 'getMember' | 'getMentionable' | 'getRole' + >; + public inGuild(): this is AutocompleteInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is AutocompleteInteraction<'cached'>; + public inRawGuild(): this is AutocompleteInteraction<'raw'>; + public respond(options: ApplicationCommandOptionChoiceData[]): Promise<void>; +} + +export class CommandInteractionOptionResolver<Cached extends CacheType = CacheType> { + private constructor( + client: Client<true>, + options: CommandInteractionOption[], + resolved: CommandInteractionResolvedData, + ); + public readonly client: Client; + public readonly data: readonly CommandInteractionOption<Cached>[]; + public readonly resolved: Readonly<CommandInteractionResolvedData<Cached>> | null; + private _group: string | null; + private _hoistedOptions: CommandInteractionOption<Cached>[]; + private _subcommand: string | null; + private _getTypedOption( + name: string, + allowedTypes: ApplicationCommandOptionType[], + properties: (keyof ApplicationCommandOption)[], + required: true, + ): CommandInteractionOption<Cached>; + private _getTypedOption( + name: string, + allowedTypes: ApplicationCommandOptionType[], + properties: (keyof ApplicationCommandOption)[], + required: boolean, + ): CommandInteractionOption<Cached> | null; + + public get(name: string, required: true): CommandInteractionOption<Cached>; + public get(name: string, required?: boolean): CommandInteractionOption<Cached> | null; + + public getSubcommand(required?: true): string; + public getSubcommand(required: boolean): string | null; + public getSubcommandGroup(required: true): string; + public getSubcommandGroup(required?: boolean): string | null; + public getBoolean(name: string, required: true): boolean; + public getBoolean(name: string, required?: boolean): boolean | null; + public getChannel<const T extends ChannelType = ChannelType>( + name: string, + required: true, + channelTypes?: readonly T[], + ): Extract< + NonNullable<CommandInteractionOption<Cached>['channel']>, + { + // The `type` property of the PublicThreadChannel class is typed as `ChannelType.PublicThread | ChannelType.AnnouncementThread` + // If the user only passed one of those channel types, the Extract<> would have resolved to `never` + // Hence the need for this ternary + type: T extends ChannelType.PublicThread | ChannelType.AnnouncementThread + ? ChannelType.PublicThread | ChannelType.AnnouncementThread + : T; + } + >; + public getChannel<const T extends ChannelType = ChannelType>( + name: string, + required?: boolean, + channelTypes?: readonly T[], + ): Extract< + NonNullable<CommandInteractionOption<Cached>['channel']>, + { + // The `type` property of the PublicThreadChannel class is typed as `ChannelType.PublicThread | ChannelType.AnnouncementThread` + // If the user only passed one of those channel types, the Extract<> would have resolved to `never` + // Hence the need for this ternary + type: T extends ChannelType.PublicThread | ChannelType.AnnouncementThread + ? ChannelType.PublicThread | ChannelType.AnnouncementThread + : T; + } + > | null; + public getString(name: string, required: true): string; + public getString(name: string, required?: boolean): string | null; + public getInteger(name: string, required: true): number; + public getInteger(name: string, required?: boolean): number | null; + public getNumber(name: string, required: true): number; + public getNumber(name: string, required?: boolean): number | null; + public getUser(name: string, required: true): NonNullable<CommandInteractionOption<Cached>['user']>; + public getUser(name: string, required?: boolean): NonNullable<CommandInteractionOption<Cached>['user']> | null; + public getMember(name: string): NonNullable<CommandInteractionOption<Cached>['member']> | null; + public getRole(name: string, required: true): NonNullable<CommandInteractionOption<Cached>['role']>; + public getRole(name: string, required?: boolean): NonNullable<CommandInteractionOption<Cached>['role']> | null; + public getAttachment(name: string, required: true): NonNullable<CommandInteractionOption<Cached>['attachment']>; + public getAttachment( + name: string, + required?: boolean, + ): NonNullable<CommandInteractionOption<Cached>['attachment']> | null; + public getMentionable( + name: string, + required: true, + ): NonNullable<CommandInteractionOption<Cached>['member' | 'role' | 'user']>; + public getMentionable( + name: string, + required?: boolean, + ): NonNullable<CommandInteractionOption<Cached>['member' | 'role' | 'user']> | null; + public getMessage(name: string, required: true): NonNullable<CommandInteractionOption<Cached>['message']>; + public getMessage(name: string, required?: boolean): NonNullable<CommandInteractionOption<Cached>['message']> | null; + public getFocused(getFull: true): AutocompleteFocusedOption; + public getFocused(getFull?: boolean): string; +} + +export class ContextMenuCommandInteraction<Cached extends CacheType = CacheType> extends CommandInteraction<Cached> { + public commandType: ApplicationCommandType.Message | ApplicationCommandType.User; + public options: Omit< + CommandInteractionOptionResolver<Cached>, + | 'getFocused' + | 'getMentionable' + | 'getRole' + | 'getNumber' + | 'getInteger' + | 'getString' + | 'getChannel' + | 'getBoolean' + | 'getSubcommandGroup' + | 'getSubcommand' + >; + public targetId: Snowflake; + public inGuild(): this is ContextMenuCommandInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is ContextMenuCommandInteraction<'cached'>; + public inRawGuild(): this is ContextMenuCommandInteraction<'raw'>; + private resolveContextMenuOptions(data: APIApplicationCommandInteractionData): CommandInteractionOption<Cached>[]; +} + +export interface ResolvedFile { + data: Buffer; + contentType?: string; +} + +export class DataResolver extends null { + private constructor(); + public static resolveBase64(data: Base64Resolvable): string; + public static resolveCode(data: string, regex: RegExp): string; + public static resolveFile(resource: BufferResolvable | Stream): Promise<ResolvedFile>; + public static resolveImage(resource: BufferResolvable | Base64Resolvable): Promise<string | null>; + public static resolveInviteCode(data: InviteResolvable): string; + public static resolveGuildTemplateCode(data: GuildTemplateResolvable): string; +} + +export class DMChannel extends TextBasedChannelMixin(BaseChannel, false, [ + 'bulkDelete', + 'fetchWebhooks', + 'createWebhook', + 'setRateLimitPerUser', + 'setNSFW', +]) { + private constructor(client: Client<true>, data?: RawDMChannelData); + public flags: Readonly<ChannelFlagsBitField>; + public recipientId: Snowflake; + public get recipient(): User | null; + public type: ChannelType.DM; + public fetch(force?: boolean): Promise<this>; + public toString(): UserMention; +} + +export class Emoji extends Base { + protected constructor(client: Client<true>, emoji: RawEmojiData); + public animated: boolean | null; + public get createdAt(): Date | null; + public get createdTimestamp(): number | null; + public id: Snowflake | null; + public name: string | null; + public get identifier(): string; + public get url(): string | null; + public toJSON(): unknown; + public toString(): string; +} + +export class Guild extends AnonymousGuild { + private constructor(client: Client<true>, data: RawGuildData); + private _sortedRoles(): Collection<Snowflake, Role>; + private _sortedChannels(channel: NonThreadGuildBasedChannel): Collection<Snowflake, NonThreadGuildBasedChannel>; + + public get afkChannel(): VoiceChannel | null; + public afkChannelId: Snowflake | null; + public afkTimeout: number; + public applicationId: Snowflake | null; + public maxVideoChannelUsers: number | null; + public approximateMemberCount: number | null; + public approximatePresenceCount: number | null; + public autoModerationRules: AutoModerationRuleManager; + public available: boolean; + public bans: GuildBanManager; + public channels: GuildChannelManager; + public commands: GuildApplicationCommandManager; + public defaultMessageNotifications: GuildDefaultMessageNotifications; + public discoverySplash: string | null; + public emojis: GuildEmojiManager; + public explicitContentFilter: GuildExplicitContentFilter; + public invites: GuildInviteManager; + public get joinedAt(): Date; + public joinedTimestamp: number; + public large: boolean; + public maximumMembers: number | null; + public maximumPresences: number | null; + public maxStageVideoChannelUsers: number | null; + public memberCount: number; + public members: GuildMemberManager; + public mfaLevel: GuildMFALevel; + public ownerId: Snowflake; + public preferredLocale: Locale; + public premiumProgressBarEnabled: boolean; + public premiumTier: GuildPremiumTier; + public presences: PresenceManager; + public get publicUpdatesChannel(): TextChannel | null; + public publicUpdatesChannelId: Snowflake | null; + public roles: RoleManager; + public get rulesChannel(): TextChannel | null; + public rulesChannelId: Snowflake | null; + public get safetyAlertsChannel(): TextChannel | null; + public safetyAlertsChannelId: Snowflake | null; + public scheduledEvents: GuildScheduledEventManager; + public get shard(): WebSocketShard; + public shardId: number; + public stageInstances: StageInstanceManager; + public stickers: GuildStickerManager; + public get systemChannel(): TextChannel | null; + public systemChannelFlags: Readonly<SystemChannelFlagsBitField>; + public systemChannelId: Snowflake | null; + public vanityURLUses: number | null; + public get voiceAdapterCreator(): InternalDiscordGatewayAdapterCreator; + public voiceStates: VoiceStateManager; + public get widgetChannel(): TextChannel | NewsChannel | VoiceBasedChannel | ForumChannel | null; + public widgetChannelId: Snowflake | null; + public widgetEnabled: boolean | null; + public get maximumBitrate(): number; + public createTemplate(name: string, description?: string): Promise<GuildTemplate>; + public delete(): Promise<Guild>; + public discoverySplashURL(options?: ImageURLOptions): string | null; + public edit(options: GuildEditOptions): Promise<Guild>; + public editWelcomeScreen(options: WelcomeScreenEditOptions): Promise<WelcomeScreen>; + public equals(guild: Guild): boolean; + public fetchAuditLogs<T extends GuildAuditLogsResolvable = null>( + options?: GuildAuditLogsFetchOptions<T>, + ): Promise<GuildAuditLogs<T>>; + public fetchIntegrations(): Promise<Collection<Snowflake | string, Integration>>; + public fetchOnboarding(): Promise<GuildOnboarding>; + public fetchOwner(options?: BaseFetchOptions): Promise<GuildMember>; + public fetchPreview(): Promise<GuildPreview>; + public fetchTemplates(): Promise<Collection<GuildTemplate['code'], GuildTemplate>>; + public fetchVanityData(): Promise<Vanity>; + public fetchWebhooks(): Promise<Collection<Snowflake, Webhook>>; + public fetchWelcomeScreen(): Promise<WelcomeScreen>; + public fetchWidget(): Promise<Widget>; + public fetchWidgetSettings(): Promise<GuildWidgetSettings>; + public leave(): Promise<Guild>; + public disableInvites(disabled?: boolean): Promise<Guild>; + public setAFKChannel(afkChannel: VoiceChannelResolvable | null, reason?: string): Promise<Guild>; + public setAFKTimeout(afkTimeout: number, reason?: string): Promise<Guild>; + public setBanner(banner: BufferResolvable | Base64Resolvable | null, reason?: string): Promise<Guild>; + public setDefaultMessageNotifications( + defaultMessageNotifications: GuildDefaultMessageNotifications | null, + reason?: string, + ): Promise<Guild>; + public setDiscoverySplash( + discoverySplash: BufferResolvable | Base64Resolvable | null, + reason?: string, + ): Promise<Guild>; + public setExplicitContentFilter( + explicitContentFilter: GuildExplicitContentFilter | null, + reason?: string, + ): Promise<Guild>; + public setIcon(icon: BufferResolvable | Base64Resolvable | null, reason?: string): Promise<Guild>; + public setName(name: string, reason?: string): Promise<Guild>; + public setOwner(owner: GuildMemberResolvable, reason?: string): Promise<Guild>; + public setPreferredLocale(preferredLocale: Locale | null, reason?: string): Promise<Guild>; + public setPublicUpdatesChannel(publicUpdatesChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>; + public setRulesChannel(rulesChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>; + public setSafetyAlertsChannel(safetyAlertsChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>; + public setSplash(splash: BufferResolvable | Base64Resolvable | null, reason?: string): Promise<Guild>; + public setSystemChannel(systemChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>; + public setSystemChannelFlags(systemChannelFlags: SystemChannelFlagsResolvable, reason?: string): Promise<Guild>; + public setVerificationLevel(verificationLevel: GuildVerificationLevel | null, reason?: string): Promise<Guild>; + public setPremiumProgressBarEnabled(enabled?: boolean, reason?: string): Promise<Guild>; + public setWidgetSettings(settings: GuildWidgetSettingsData, reason?: string): Promise<Guild>; + public setMFALevel(level: GuildMFALevel, reason?: string): Promise<Guild>; + public toJSON(): unknown; +} + +export class GuildAuditLogs<T extends GuildAuditLogsResolvable = AuditLogEvent> { + private constructor(guild: Guild, data: RawGuildAuditLogData); + private applicationCommands: Collection<Snowflake, ApplicationCommand>; + private webhooks: Collection<Snowflake, Webhook>; + private integrations: Collection<Snowflake | string, Integration>; + private guildScheduledEvents: Collection<Snowflake, GuildScheduledEvent>; + private autoModerationRules: Collection<Snowflake, AutoModerationRule>; + public entries: Collection<Snowflake, GuildAuditLogsEntry<T>>; + public toJSON(): unknown; +} + +export class GuildAuditLogsEntry< + TAction extends GuildAuditLogsResolvable = AuditLogEvent, + TActionType extends GuildAuditLogsActionType = TAction extends keyof GuildAuditLogsTypes + ? GuildAuditLogsTypes[TAction][1] + : GuildAuditLogsActionType, + TTargetType extends GuildAuditLogsTargetType = TAction extends keyof GuildAuditLogsTypes + ? GuildAuditLogsTypes[TAction][0] + : GuildAuditLogsTargetType, + TResolvedType = TAction extends null ? AuditLogEvent : TAction, +> { + private constructor(guild: Guild, data: RawGuildAuditLogEntryData, logs?: GuildAuditLogs); + public static Targets: GuildAuditLogsTargets; + public action: TResolvedType; + public actionType: TActionType; + public changes: AuditLogChange[]; + public get createdAt(): Date; + public get createdTimestamp(): number; + public executorId: Snowflake | null; + public executor: User | null; + public extra: TResolvedType extends keyof GuildAuditLogsEntryExtraField + ? GuildAuditLogsEntryExtraField[TResolvedType] + : null; + public id: Snowflake; + public reason: string | null; + public targetId: Snowflake | null; + public target: TTargetType extends keyof GuildAuditLogsEntryTargetField<TActionType> + ? GuildAuditLogsEntryTargetField<TActionType>[TTargetType] + : Role | GuildEmoji | { id: Snowflake } | null; + public targetType: TTargetType; + public static actionType(action: AuditLogEvent): GuildAuditLogsActionType; + public static targetType(target: AuditLogEvent): GuildAuditLogsTargetType; + public toJSON(): unknown; +} + +export class GuildBan extends Base { + private constructor(client: Client<true>, data: RawGuildBanData, guild: Guild); + public guild: Guild; + public user: User; + public get partial(): boolean; + public reason?: string | null; + public fetch(force?: boolean): Promise<GuildBan>; +} + +export abstract class GuildChannel extends BaseChannel { + public constructor(guild: Guild, data?: RawGuildChannelData, client?: Client<true>, immediatePatch?: boolean); + private memberPermissions(member: GuildMember, checkAdmin: boolean): Readonly<PermissionsBitField>; + private rolePermissions(role: Role, checkAdmin: boolean): Readonly<PermissionsBitField>; + public get createdAt(): Date; + public get createdTimestamp(): number; + public get deletable(): boolean; + public flags: Readonly<ChannelFlagsBitField>; + public guild: Guild; + public guildId: Snowflake; + public get manageable(): boolean; + public get members(): Collection<Snowflake, GuildMember>; + public name: string; + public get parent(): CategoryChannel | null; + public parentId: Snowflake | null; + public permissionOverwrites: PermissionOverwriteManager; + public get permissionsLocked(): boolean | null; + public get position(): number; + public rawPosition: number; + public type: Exclude<ChannelType, ChannelType.DM | ChannelType.GroupDM>; + public get viewable(): boolean; + public clone(options?: GuildChannelCloneOptions): Promise<this>; + public delete(reason?: string): Promise<this>; + public edit(options: GuildChannelEditOptions): Promise<this>; + public equals(channel: GuildChannel): boolean; + public lockPermissions(): Promise<this>; + public permissionsFor(memberOrRole: GuildMember | Role, checkAdmin?: boolean): Readonly<PermissionsBitField>; + public permissionsFor( + memberOrRole: GuildMemberResolvable | RoleResolvable, + checkAdmin?: boolean, + ): Readonly<PermissionsBitField> | null; + public setName(name: string, reason?: string): Promise<this>; + public setParent(channel: CategoryChannelResolvable | null, options?: SetParentOptions): Promise<this>; + public setPosition(position: number, options?: SetChannelPositionOptions): Promise<this>; + public isTextBased(): this is GuildBasedChannel & TextBasedChannel; + public toString(): ChannelMention; +} + +export class GuildEmoji extends BaseGuildEmoji { + private constructor(client: Client<true>, data: RawGuildEmojiData, guild: Guild); + private _roles: Snowflake[]; + + public get deletable(): boolean; + public guild: Guild; + public author: User | null; + public get roles(): GuildEmojiRoleManager; + public get url(): string; + public delete(reason?: string): Promise<GuildEmoji>; + public edit(options: GuildEmojiEditOptions): Promise<GuildEmoji>; + public equals(other: GuildEmoji | unknown): boolean; + public fetchAuthor(): Promise<User>; + public setName(name: string, reason?: string): Promise<GuildEmoji>; +} + +export type GuildMemberFlagsString = keyof typeof GuildMemberFlags; + +export type GuildMemberFlagsResolvable = BitFieldResolvable<GuildMemberFlagsString, number>; + +export class GuildMemberFlagsBitField extends BitField<GuildMemberFlagsString> { + public static Flags: GuildMemberFlags; + public static resolve(bit?: BitFieldResolvable<GuildMemberFlagsString, GuildMemberFlags>): number; +} + +export class GuildMember extends PartialTextBasedChannel(Base) { + private constructor(client: Client<true>, data: RawGuildMemberData, guild: Guild); + private _roles: Snowflake[]; + public avatar: string | null; + public get bannable(): boolean; + public get dmChannel(): DMChannel | null; + public get displayColor(): number; + public get displayHexColor(): HexColorString; + public get displayName(): string; + public guild: Guild; + public get id(): Snowflake; + public pending: boolean; + public get communicationDisabledUntil(): Date | null; + public communicationDisabledUntilTimestamp: number | null; + public flags: Readonly<GuildMemberFlagsBitField>; + public get joinedAt(): Date | null; + public joinedTimestamp: number | null; + public get kickable(): boolean; + public get manageable(): boolean; + public get moderatable(): boolean; + public nickname: string | null; + public get partial(): false; + public get permissions(): Readonly<PermissionsBitField>; + public get premiumSince(): Date | null; + public premiumSinceTimestamp: number | null; + public get presence(): Presence | null; + public get roles(): GuildMemberRoleManager; + public user: User; + public get voice(): VoiceState; + public avatarURL(options?: ImageURLOptions): string | null; + public ban(options?: BanOptions): Promise<GuildMember>; + public disableCommunicationUntil(timeout: DateResolvable | null, reason?: string): Promise<GuildMember>; + public timeout(timeout: number | null, reason?: string): Promise<GuildMember>; + public fetch(force?: boolean): Promise<GuildMember>; + public createDM(force?: boolean): Promise<DMChannel>; + public deleteDM(): Promise<DMChannel>; + public displayAvatarURL(options?: ImageURLOptions): string; + public edit(options: GuildMemberEditOptions): Promise<GuildMember>; + public isCommunicationDisabled(): this is GuildMember & { + communicationDisabledUntilTimestamp: number; + readonly communicationDisabledUntil: Date; + }; + public kick(reason?: string): Promise<GuildMember>; + public permissionsIn(channel: GuildChannelResolvable): Readonly<PermissionsBitField>; + public setFlags(flags: GuildMemberFlagsResolvable, reason?: string): Promise<GuildMember>; + public setNickname(nickname: string | null, reason?: string): Promise<GuildMember>; + public toJSON(): unknown; + public toString(): UserMention; + public valueOf(): string; +} + +export class GuildOnboarding extends Base { + private constructor(client: Client, data: RESTGetAPIGuildOnboardingResult); + public get guild(): Guild; + public guildId: Snowflake; + public prompts: Collection<Snowflake, GuildOnboardingPrompt>; + public defaultChannels: Collection<Snowflake, GuildChannel>; + public enabled: boolean; +} + +export class GuildOnboardingPrompt extends Base { + private constructor(client: Client, data: APIGuildOnboardingPrompt, guildId: Snowflake); + public id: Snowflake; + public get guild(): Guild; + public guildId: Snowflake; + public options: Collection<Snowflake, GuildOnboardingPromptOption>; + public title: string; + public singleSelect: boolean; + public required: boolean; + public inOnboarding: boolean; + public type: GuildOnboardingPromptType; +} + +export class GuildOnboardingPromptOption extends Base { + private constructor(client: Client, data: APIGuildOnboardingPromptOption, guildId: Snowflake); + public id: Snowflake; + public get guild(): Guild; + public guildId: Snowflake; + public channels: Collection<Snowflake, GuildChannel>; + public roles: Collection<Snowflake, Role>; + public emoji: GuildOnboardingPromptOptionEmoji | null; + public title: string; + public description: string | null; +} + +export class GuildPreview extends Base { + private constructor(client: Client<true>, data: RawGuildPreviewData); + public approximateMemberCount: number; + public approximatePresenceCount: number; + public get createdAt(): Date; + public get createdTimestamp(): number; + public description: string | null; + public discoverySplash: string | null; + public emojis: Collection<Snowflake, GuildPreviewEmoji>; + public stickers: Collection<Snowflake, Sticker>; + public features: `${GuildFeature}`[]; + public icon: string | null; + public id: Snowflake; + public name: string; + public splash: string | null; + public discoverySplashURL(options?: ImageURLOptions): string | null; + public iconURL(options?: ImageURLOptions): string | null; + public splashURL(options?: ImageURLOptions): string | null; + public fetch(): Promise<GuildPreview>; + public toJSON(): unknown; + public toString(): string; +} + +export class GuildScheduledEvent<S extends GuildScheduledEventStatus = GuildScheduledEventStatus> extends Base { + private constructor(client: Client<true>, data: RawGuildScheduledEventData); + public id: Snowflake; + public guildId: Snowflake; + public channelId: Snowflake | null; + public creatorId: Snowflake | null; + public name: string; + public description: string | null; + public scheduledStartTimestamp: number | null; + public scheduledEndTimestamp: number | null; + public privacyLevel: GuildScheduledEventPrivacyLevel; + public status: S; + public entityType: GuildScheduledEventEntityType; + public entityId: Snowflake | null; + public entityMetadata: GuildScheduledEventEntityMetadata | null; + public userCount: number | null; + public creator: User | null; + public get createdTimestamp(): number; + public get createdAt(): Date; + public get scheduledStartAt(): Date | null; + public get scheduledEndAt(): Date | null; + public get channel(): VoiceChannel | StageChannel | null; + public get guild(): Guild | null; + public get url(): string; + public image: string | null; + public coverImageURL(options?: Readonly<BaseImageURLOptions>): string | null; + public createInviteURL(options?: GuildScheduledEventInviteURLCreateOptions): Promise<string>; + public edit<T extends GuildScheduledEventSetStatusArg<S>>( + options: GuildScheduledEventEditOptions<S, T>, + ): Promise<GuildScheduledEvent<T>>; + public delete(): Promise<GuildScheduledEvent<S>>; + public setName(name: string, reason?: string): Promise<GuildScheduledEvent<S>>; + public setScheduledStartTime(scheduledStartTime: DateResolvable, reason?: string): Promise<GuildScheduledEvent<S>>; + public setScheduledEndTime(scheduledEndTime: DateResolvable, reason?: string): Promise<GuildScheduledEvent<S>>; + public setDescription(description: string, reason?: string): Promise<GuildScheduledEvent<S>>; + public setStatus<T extends GuildScheduledEventSetStatusArg<S>>( + status: T, + reason?: string, + ): Promise<GuildScheduledEvent<T>>; + public setLocation(location: string, reason?: string): Promise<GuildScheduledEvent<S>>; + public fetchSubscribers<T extends FetchGuildScheduledEventSubscribersOptions>( + options?: T, + ): Promise<GuildScheduledEventManagerFetchSubscribersResult<T>>; + public toString(): string; + public isActive(): this is GuildScheduledEvent<GuildScheduledEventStatus.Active>; + public isCanceled(): this is GuildScheduledEvent<GuildScheduledEventStatus.Canceled>; + public isCompleted(): this is GuildScheduledEvent<GuildScheduledEventStatus.Completed>; + public isScheduled(): this is GuildScheduledEvent<GuildScheduledEventStatus.Scheduled>; +} + +export class GuildTemplate extends Base { + private constructor(client: Client<true>, data: RawGuildTemplateData); + public createdTimestamp: number; + public updatedTimestamp: number; + public get url(): string; + public code: string; + public name: string; + public description: string | null; + public usageCount: number; + public creator: User; + public creatorId: Snowflake; + public get createdAt(): Date; + public get updatedAt(): Date; + public get guild(): Guild | null; + public guildId: Snowflake; + public serializedGuild: APITemplateSerializedSourceGuild; + public unSynced: boolean | null; + public createGuild(name: string, icon?: BufferResolvable | Base64Resolvable): Promise<Guild>; + public delete(): Promise<GuildTemplate>; + public edit(options?: GuildTemplateEditOptions): Promise<GuildTemplate>; + public sync(): Promise<GuildTemplate>; + public static GuildTemplatesPattern: RegExp; +} + +export class GuildPreviewEmoji extends BaseGuildEmoji { + private constructor(client: Client<true>, data: RawGuildEmojiData, guild: GuildPreview); + public guild: GuildPreview; + public roles: Snowflake[]; +} + +export class Integration extends Base { + private constructor(client: Client<true>, data: RawIntegrationData, guild: Guild); + public account: IntegrationAccount; + public application: IntegrationApplication | null; + public enabled: boolean | null; + public expireBehavior: IntegrationExpireBehavior | null; + public expireGracePeriod: number | null; + public guild: Guild; + public id: Snowflake | string; + public name: string; + public role: Role | null; + public enableEmoticons: boolean | null; + public get roles(): Collection<Snowflake, Role>; + public scopes: OAuth2Scopes[]; + public get syncedAt(): Date | null; + public syncedTimestamp: number | null; + public syncing: boolean | null; + public type: IntegrationType; + public user: User | null; + public subscriberCount: number | null; + public revoked: boolean | null; + public delete(reason?: string): Promise<Integration>; +} + +export class IntegrationApplication extends Application { + private constructor(client: Client<true>, data: RawIntegrationApplicationData); + public bot: User | null; + public termsOfServiceURL: string | null; + public privacyPolicyURL: string | null; + public rpcOrigins: string[]; + public hook: boolean | null; + public cover: string | null; + public verifyKey: string | null; +} + +export type GatewayIntentsString = keyof typeof GatewayIntentBits; + +export class IntentsBitField extends BitField<GatewayIntentsString> { + public static Flags: typeof GatewayIntentBits; + public static resolve(bit?: BitFieldResolvable<GatewayIntentsString, number>): number; +} + +export type CacheType = 'cached' | 'raw' | undefined; + +export type CacheTypeReducer< + State extends CacheType, + CachedType, + RawType = CachedType, + PresentType = CachedType | RawType, + Fallback = PresentType | null, +> = [State] extends ['cached'] + ? CachedType + : [State] extends ['raw'] + ? RawType + : [State] extends ['raw' | 'cached'] + ? PresentType + : Fallback; + +export type Interaction<Cached extends CacheType = CacheType> = + | ChatInputCommandInteraction<Cached> + | MessageContextMenuCommandInteraction<Cached> + | UserContextMenuCommandInteraction<Cached> + | AnySelectMenuInteraction<Cached> + | ButtonInteraction<Cached> + | AutocompleteInteraction<Cached> + | ModalSubmitInteraction<Cached>; + +export type RepliableInteraction<Cached extends CacheType = CacheType> = Exclude< + Interaction<Cached>, + AutocompleteInteraction<Cached> +>; + +export class BaseInteraction<Cached extends CacheType = CacheType> extends Base { + // This a technique used to brand different cached types. Or else we'll get `never` errors on typeguard checks. + private readonly _cacheType: Cached; + protected constructor(client: Client<true>, data: RawInteractionData); + public applicationId: Snowflake; + public get channel(): CacheTypeReducer< + Cached, + GuildTextBasedChannel | null, + GuildTextBasedChannel | null, + GuildTextBasedChannel | null, + TextBasedChannel | null + >; + public channelId: Snowflake | null; + public get createdAt(): Date; + public get createdTimestamp(): number; + public get guild(): CacheTypeReducer<Cached, Guild, null>; + public guildId: CacheTypeReducer<Cached, Snowflake>; + public id: Snowflake; + public member: CacheTypeReducer<Cached, GuildMember, APIInteractionGuildMember>; + public readonly token: string; + public type: InteractionType; + public user: User; + public version: number; + public appPermissions: CacheTypeReducer<Cached, Readonly<PermissionsBitField>>; + public memberPermissions: CacheTypeReducer<Cached, Readonly<PermissionsBitField>>; + public locale: Locale; + public guildLocale: CacheTypeReducer<Cached, Locale>; + public inGuild(): this is BaseInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is BaseInteraction<'cached'>; + public inRawGuild(): this is BaseInteraction<'raw'>; + public isButton(): this is ButtonInteraction<Cached>; + public isAutocomplete(): this is AutocompleteInteraction<Cached>; + public isChatInputCommand(): this is ChatInputCommandInteraction<Cached>; + public isCommand(): this is CommandInteraction<Cached>; + public isContextMenuCommand(): this is ContextMenuCommandInteraction<Cached>; + public isMessageComponent(): this is MessageComponentInteraction<Cached>; + public isMessageContextMenuCommand(): this is MessageContextMenuCommandInteraction<Cached>; + public isModalSubmit(): this is ModalSubmitInteraction<Cached>; + public isUserContextMenuCommand(): this is UserContextMenuCommandInteraction<Cached>; + /** @deprecated Use {@link isStringSelectMenu} instead. */ + public isSelectMenu(): this is StringSelectMenuInteraction<Cached>; + public isAnySelectMenu(): this is AnySelectMenuInteraction<Cached>; + public isStringSelectMenu(): this is StringSelectMenuInteraction<Cached>; + public isUserSelectMenu(): this is UserSelectMenuInteraction<Cached>; + public isRoleSelectMenu(): this is RoleSelectMenuInteraction<Cached>; + public isMentionableSelectMenu(): this is MentionableSelectMenuInteraction<Cached>; + public isChannelSelectMenu(): this is ChannelSelectMenuInteraction<Cached>; + public isRepliable(): this is RepliableInteraction<Cached>; +} + +export class InteractionCollector<T extends CollectedInteraction> extends Collector< + Snowflake, + T, + [Collection<Snowflake, T>] +> { + public constructor(client: Client<true>, options?: InteractionCollectorOptions<T>); + private _handleMessageDeletion(message: Message): void; + private _handleChannelDeletion(channel: NonThreadGuildBasedChannel): void; + private _handleGuildDeletion(guild: Guild): void; + + public channelId: Snowflake | null; + public messageInteractionId: Snowflake | null; + public componentType: ComponentType | null; + public guildId: Snowflake | null; + public interactionType: InteractionType | null; + public messageId: Snowflake | null; + public options: InteractionCollectorOptions<T>; + public total: number; + public users: Collection<Snowflake, User>; + + public collect(interaction: Interaction): Snowflake; + public empty(): void; + public dispose(interaction: Interaction): Snowflake; + public on(event: 'collect' | 'dispose' | 'ignore', listener: (interaction: T) => Awaitable<void>): this; + public on(event: 'end', listener: (collected: Collection<Snowflake, T>, reason: string) => Awaitable<void>): this; + public on(event: string, listener: (...args: any[]) => Awaitable<void>): this; + + public once(event: 'collect' | 'dispose' | 'ignore', listener: (interaction: T) => Awaitable<void>): this; + public once(event: 'end', listener: (collected: Collection<Snowflake, T>, reason: string) => Awaitable<void>): this; + public once(event: string, listener: (...args: any[]) => Awaitable<void>): this; +} + +export class InteractionWebhook extends PartialWebhookMixin() { + public constructor(client: Client<true>, id: Snowflake, token: string); + public token: string; + public send(options: string | MessagePayload | InteractionReplyOptions): Promise<Message>; + public editMessage( + message: MessageResolvable | '@original', + options: string | MessagePayload | WebhookMessageEditOptions, + ): Promise<Message>; + public fetchMessage(message: Snowflake | '@original'): Promise<Message>; +} + +export class Invite extends Base { + private constructor(client: Client<true>, data: RawInviteData); + public channel: NonThreadGuildBasedChannel | PartialGroupDMChannel | null; + public channelId: Snowflake | null; + public code: string; + public get deletable(): boolean; + public get createdAt(): Date | null; + public createdTimestamp: number | null; + public get expiresAt(): Date | null; + public get expiresTimestamp(): number | null; + public guild: InviteGuild | Guild | null; + public get inviter(): User | null; + public inviterId: Snowflake | null; + public maxAge: number | null; + public maxUses: number | null; + public memberCount: number; + public presenceCount: number; + public targetApplication: IntegrationApplication | null; + public targetUser: User | null; + public targetType: InviteTargetType | null; + public temporary: boolean | null; + public get url(): string; + public uses: number | null; + public delete(reason?: string): Promise<Invite>; + public toJSON(): unknown; + public toString(): string; + public static InvitesPattern: RegExp; + /** @deprecated */ + public stageInstance: InviteStageInstance | null; + public guildScheduledEvent: GuildScheduledEvent | null; +} + +/** @deprecated */ +export class InviteStageInstance extends Base { + private constructor(client: Client<true>, data: RawInviteStageInstance, channelId: Snowflake, guildId: Snowflake); + public channelId: Snowflake; + public guildId: Snowflake; + public members: Collection<Snowflake, GuildMember>; + public topic: string; + public participantCount: number; + public speakerCount: number; + public get channel(): StageChannel | null; + public get guild(): Guild | null; +} + +export class InviteGuild extends AnonymousGuild { + private constructor(client: Client<true>, data: RawInviteGuildData); + public welcomeScreen: WelcomeScreen | null; +} + +export class LimitedCollection<K, V> extends Collection<K, V> { + public constructor(options?: LimitedCollectionOptions<K, V>, iterable?: Iterable<readonly [K, V]>); + public maxSize: number; + public keepOverLimit: ((value: V, key: K, collection: this) => boolean) | null; +} + +export type MessageComponentType = Exclude<ComponentType, ComponentType.TextInput | ComponentType.ActionRow>; + +export type MessageCollectorOptionsParams<T extends MessageComponentType, Cached extends boolean = boolean> = + | { + componentType?: T; + } & MessageComponentCollectorOptions<MappedInteractionTypes<Cached>[T]>; + +export type MessageChannelCollectorOptionsParams<T extends MessageComponentType, Cached extends boolean = boolean> = + | { + componentType?: T; + } & MessageChannelComponentCollectorOptions<MappedInteractionTypes<Cached>[T]>; + +export type AwaitMessageCollectorOptionsParams<T extends MessageComponentType, Cached extends boolean = boolean> = + | { componentType?: T } & Pick< + InteractionCollectorOptions<MappedInteractionTypes<Cached>[T]>, + keyof AwaitMessageComponentOptions<any> + >; + +export interface StringMappedInteractionTypes<Cached extends CacheType = CacheType> { + Button: ButtonInteraction<Cached>; + StringSelectMenu: StringSelectMenuInteraction<Cached>; + UserSelectMenu: UserSelectMenuInteraction<Cached>; + RoleSelectMenu: RoleSelectMenuInteraction<Cached>; + MentionableSelectMenu: MentionableSelectMenuInteraction<Cached>; + ChannelSelectMenu: ChannelSelectMenuInteraction<Cached>; + ActionRow: MessageComponentInteraction<Cached>; +} + +export type WrapBooleanCache<T extends boolean> = If<T, 'cached', CacheType>; + +export interface MappedInteractionTypes<Cached extends boolean = boolean> { + [ComponentType.Button]: ButtonInteraction<WrapBooleanCache<Cached>>; + [ComponentType.StringSelect]: StringSelectMenuInteraction<WrapBooleanCache<Cached>>; + [ComponentType.UserSelect]: UserSelectMenuInteraction<WrapBooleanCache<Cached>>; + [ComponentType.RoleSelect]: RoleSelectMenuInteraction<WrapBooleanCache<Cached>>; + [ComponentType.MentionableSelect]: MentionableSelectMenuInteraction<WrapBooleanCache<Cached>>; + [ComponentType.ChannelSelect]: ChannelSelectMenuInteraction<WrapBooleanCache<Cached>>; +} + +export class Message<InGuild extends boolean = boolean> extends Base { + private readonly _cacheType: InGuild; + private constructor(client: Client<true>, data: RawMessageData); + private _patch(data: RawPartialMessageData | RawMessageData): void; + + public activity: MessageActivity | null; + public applicationId: Snowflake | null; + public attachments: Collection<Snowflake, Attachment>; + public author: User; + public get bulkDeletable(): boolean; + public get channel(): If<InGuild, GuildTextBasedChannel, TextBasedChannel>; + public channelId: Snowflake; + public get cleanContent(): string; + public components: ActionRow<MessageActionRowComponent>[]; + public content: string; + public get createdAt(): Date; + public createdTimestamp: number; + public get crosspostable(): boolean; + public get deletable(): boolean; + public get editable(): boolean; + public get editedAt(): Date | null; + public editedTimestamp: number | null; + public embeds: Embed[]; + public groupActivityApplication: ClientApplication | null; + public guildId: If<InGuild, Snowflake>; + public get guild(): If<InGuild, Guild>; + public get hasThread(): boolean; + public id: Snowflake; + public interaction: MessageInteraction | null; + public get member(): GuildMember | null; + public mentions: MessageMentions<InGuild>; + public nonce: string | number | null; + public get partial(): false; + public get pinnable(): boolean; + public pinned: boolean; + public reactions: ReactionManager; + public stickers: Collection<Snowflake, Sticker>; + public position: number | null; + public roleSubscriptionData: RoleSubscriptionData | null; + public system: boolean; + public get thread(): AnyThreadChannel | null; + public tts: boolean; + public type: MessageType; + public get url(): string; + public webhookId: Snowflake | null; + public flags: Readonly<MessageFlagsBitField>; + public reference: MessageReference | null; + public awaitMessageComponent<T extends MessageComponentType>( + options?: AwaitMessageCollectorOptionsParams<T, InGuild>, + ): Promise<MappedInteractionTypes<InGuild>[T]>; + public awaitReactions(options?: AwaitReactionsOptions): Promise<Collection<Snowflake | string, MessageReaction>>; + public createReactionCollector(options?: ReactionCollectorOptions): ReactionCollector; + public createMessageComponentCollector<T extends MessageComponentType>( + options?: MessageCollectorOptionsParams<T, InGuild>, + ): InteractionCollector<MappedInteractionTypes<InGuild>[T]>; + public delete(): Promise<Message<InGuild>>; + public edit(content: string | MessageEditOptions | MessagePayload): Promise<Message<InGuild>>; + public equals(message: Message, rawData: unknown): boolean; + public fetchReference(): Promise<Message<InGuild>>; + public fetchWebhook(): Promise<Webhook>; + public crosspost(): Promise<Message<InGuild>>; + public fetch(force?: boolean): Promise<Message<InGuild>>; + public pin(reason?: string): Promise<Message<InGuild>>; + public react(emoji: EmojiIdentifierResolvable): Promise<MessageReaction>; + public removeAttachments(): Promise<Message<InGuild>>; + public reply(options: string | MessagePayload | MessageReplyOptions): Promise<Message<InGuild>>; + public resolveComponent(customId: string): MessageActionRowComponent | null; + public startThread(options: StartThreadOptions): Promise<AnyThreadChannel>; + public suppressEmbeds(suppress?: boolean): Promise<Message<InGuild>>; + public toJSON(): unknown; + public toString(): string; + public unpin(reason?: string): Promise<Message<InGuild>>; + public inGuild(): this is Message<true>; +} + +export class AttachmentBuilder { + public constructor(attachment: BufferResolvable | Stream, data?: AttachmentData); + public attachment: BufferResolvable | Stream; + public description: string | null; + public name: string | null; + public get spoiler(): boolean; + public setDescription(description: string): this; + public setFile(attachment: BufferResolvable | Stream, name?: string): this; + public setName(name: string): this; + public setSpoiler(spoiler?: boolean): this; + public toJSON(): unknown; + public static from(other: JSONEncodable<AttachmentPayload>): AttachmentBuilder; +} + +export class Attachment { + private constructor(data: APIAttachment); + private attachment: BufferResolvable | Stream; + public contentType: string | null; + public description: string | null; + public duration: number | null; + public ephemeral: boolean; + public flags: AttachmentFlagsBitField; + public height: number | null; + public id: Snowflake; + public name: string; + public proxyURL: string; + public size: number; + public get spoiler(): boolean; + public url: string; + public waveform: string | null; + public width: number | null; + public toJSON(): unknown; +} + +export type AttachmentFlagsString = keyof typeof AttachmentFlags; + +export class AttachmentFlagsBitField extends BitField<AttachmentFlagsString> { + public static Flags: Record<AttachmentFlagsString, number>; + public static resolve(bit?: BitFieldResolvable<AttachmentFlagsString, number>): number; +} + +export class MessageCollector extends Collector<Snowflake, Message, [Collection<Snowflake, Message>]> { + public constructor(channel: TextBasedChannel, options?: MessageCollectorOptions); + private _handleChannelDeletion(channel: NonThreadGuildBasedChannel): void; + private _handleGuildDeletion(guild: Guild): void; + + public channel: TextBasedChannel; + public options: MessageCollectorOptions; + public received: number; + + public collect(message: Message): Snowflake | null; + public dispose(message: Message): Snowflake | null; +} + +export class MessageComponentInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> { + protected constructor(client: Client<true>, data: RawMessageComponentInteractionData); + public type: InteractionType.MessageComponent; + public get component(): CacheTypeReducer< + Cached, + MessageActionRowComponent, + Exclude<APIMessageComponent, APIActionRowComponent<APIMessageActionRowComponent>>, + MessageActionRowComponent | Exclude<APIMessageComponent, APIActionRowComponent<APIMessageActionRowComponent>>, + MessageActionRowComponent | Exclude<APIMessageComponent, APIActionRowComponent<APIMessageActionRowComponent>> + >; + public componentType: Exclude<ComponentType, ComponentType.ActionRow | ComponentType.TextInput>; + public customId: string; + public channelId: Snowflake; + public deferred: boolean; + public ephemeral: boolean | null; + public message: Message<BooleanCache<Cached>>; + public replied: boolean; + public webhook: InteractionWebhook; + public inGuild(): this is MessageComponentInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is MessageComponentInteraction<'cached'>; + public inRawGuild(): this is MessageComponentInteraction<'raw'>; + public deferReply( + options: InteractionDeferReplyOptions & { fetchReply: true }, + ): Promise<Message<BooleanCache<Cached>>>; + public deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse<BooleanCache<Cached>>>; + public deferUpdate( + options: InteractionDeferUpdateOptions & { fetchReply: true }, + ): Promise<Message<BooleanCache<Cached>>>; + public deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse<BooleanCache<Cached>>>; + public deleteReply(message?: MessageResolvable | '@original'): Promise<void>; + public editReply( + options: string | MessagePayload | InteractionEditReplyOptions, + ): Promise<Message<BooleanCache<Cached>>>; + public fetchReply(message?: Snowflake | '@original'): Promise<Message<BooleanCache<Cached>>>; + public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<Message<BooleanCache<Cached>>>; + public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<Message<BooleanCache<Cached>>>; + public reply( + options: string | MessagePayload | InteractionReplyOptions, + ): Promise<InteractionResponse<BooleanCache<Cached>>>; + public update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<Message<BooleanCache<Cached>>>; + public update( + options: string | MessagePayload | InteractionUpdateOptions, + ): Promise<InteractionResponse<BooleanCache<Cached>>>; + public showModal( + modal: + | JSONEncodable<APIModalInteractionResponseCallbackData> + | ModalComponentData + | APIModalInteractionResponseCallbackData, + ): Promise<void>; + public awaitModalSubmit( + options: AwaitModalSubmitOptions<ModalSubmitInteraction>, + ): Promise<ModalSubmitInteraction<Cached>>; +} + +export class MessageContextMenuCommandInteraction< + Cached extends CacheType = CacheType, +> extends ContextMenuCommandInteraction<Cached> { + public commandType: ApplicationCommandType.Message; + public get targetMessage(): NonNullable<CommandInteractionOption<Cached>['message']>; + public inGuild(): this is MessageContextMenuCommandInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is MessageContextMenuCommandInteraction<'cached'>; + public inRawGuild(): this is MessageContextMenuCommandInteraction<'raw'>; +} + +export type MessageFlagsString = keyof typeof MessageFlags; + +export class MessageFlagsBitField extends BitField<MessageFlagsString> { + public static Flags: typeof MessageFlags; + public static resolve(bit?: BitFieldResolvable<MessageFlagsString, number>): number; +} + +export class MessageMentions<InGuild extends boolean = boolean> { + private constructor( + message: Message, + users: APIUser[] | Collection<Snowflake, User>, + roles: Snowflake[] | Collection<Snowflake, Role>, + everyone: boolean, + repliedUser?: APIUser | User, + ); + private _channels: Collection<Snowflake, Channel> | null; + private readonly _content: string; + private _members: Collection<Snowflake, GuildMember> | null; + private _parsedUsers: Collection<Snowflake, User> | null; + + public get channels(): Collection<Snowflake, Channel>; + public readonly client: Client; + public everyone: boolean; + public readonly guild: If<InGuild, Guild>; + public has(data: UserResolvable | RoleResolvable | ChannelResolvable, options?: MessageMentionsHasOptions): boolean; + public get members(): If<InGuild, Collection<Snowflake, GuildMember>>; + public get parsedUsers(): Collection<Snowflake, User>; + public repliedUser: User | null; + public roles: Collection<Snowflake, Role>; + public users: Collection<Snowflake, User>; + public crosspostedChannels: Collection<Snowflake, CrosspostedChannel>; + public toJSON(): unknown; + + private static GlobalChannelsPattern: RegExp; + private static GlobalUsersPattern: RegExp; + public static ChannelsPattern: typeof FormattingPatterns.Channel; + public static EveryonePattern: RegExp; + public static RolesPattern: typeof FormattingPatterns.Role; + public static UsersPattern: typeof FormattingPatterns.User; +} + +export type MessagePayloadOption = + | MessageCreateOptions + | MessageEditOptions + | WebhookMessageCreateOptions + | WebhookMessageEditOptions + | InteractionReplyOptions + | InteractionUpdateOptions; + +export class MessagePayload { + public constructor(target: MessageTarget, options: MessagePayloadOption); + public body: RawMessagePayloadData | null; + public get isUser(): boolean; + public get isWebhook(): boolean; + public get isMessage(): boolean; + public get isMessageManager(): boolean; + public get isInteraction(): boolean; + public files: RawFile[] | null; + public options: MessagePayloadOption; + public target: MessageTarget; + + public static create( + target: MessageTarget, + options: string | MessagePayloadOption, + extra?: MessagePayloadOption, + ): MessagePayload; + public static resolveFile( + fileLike: BufferResolvable | Stream | AttachmentPayload | JSONEncodable<AttachmentPayload>, + ): Promise<RawFile>; + + public makeContent(): string | undefined; + public resolveBody(): this; + public resolveFiles(): Promise<this>; +} + +export class MessageReaction { + private constructor(client: Client<true>, data: RawMessageReactionData, message: Message); + private _emoji: GuildEmoji | ReactionEmoji; + + public readonly client: Client<true>; + public count: number; + public get emoji(): GuildEmoji | ReactionEmoji; + public me: boolean; + public message: Message | PartialMessage; + public get partial(): false; + public users: ReactionUserManager; + public react(): Promise<MessageReaction>; + public remove(): Promise<MessageReaction>; + public fetch(): Promise<MessageReaction>; + public toJSON(): unknown; + public valueOf(): Snowflake | string; +} + +export interface ModalComponentData { + customId: string; + title: string; + components: ( + | JSONEncodable<APIActionRowComponent<APIModalActionRowComponent>> + | ActionRowData<ModalActionRowComponentData> + )[]; +} + +export interface BaseModalData { + customId: string; + type: ComponentType; +} + +export interface TextInputModalData extends BaseModalData { + type: ComponentType.TextInput; + value: string; +} + +export interface ActionRowModalData { + type: ComponentType.ActionRow; + components: TextInputModalData[]; +} + +export class ModalSubmitFields { + constructor(components: ModalActionRowComponent[][]); + public components: ActionRowModalData[]; + public fields: Collection<string, ModalActionRowComponent>; + public getField<T extends ComponentType>(customId: string, type: T): { type: T } & TextInputModalData; + public getField(customId: string, type?: ComponentType): TextInputModalData; + public getTextInputValue(customId: string): string; +} + +export interface ModalMessageModalSubmitInteraction<Cached extends CacheType = CacheType> + extends ModalSubmitInteraction<Cached> { + message: Message<BooleanCache<Cached>>; + channelId: Snowflake; + update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<Message>; + update( + options: string | MessagePayload | InteractionUpdateOptions, + ): Promise<InteractionResponse<BooleanCache<Cached>>>; + inGuild(): this is ModalMessageModalSubmitInteraction<'raw' | 'cached'>; + inCachedGuild(): this is ModalMessageModalSubmitInteraction<'cached'>; + inRawGuild(): this is ModalMessageModalSubmitInteraction<'raw'>; +} + +export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> { + private constructor(client: Client<true>, data: APIModalSubmitInteraction); + public type: InteractionType.ModalSubmit; + public readonly customId: string; + public readonly components: ActionRowModalData[]; + public readonly fields: ModalSubmitFields; + public deferred: boolean; + public ephemeral: boolean | null; + public message: Message<BooleanCache<Cached>> | null; + public replied: boolean; + public readonly webhook: InteractionWebhook; + public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<Message<BooleanCache<Cached>>>; + public reply( + options: string | MessagePayload | InteractionReplyOptions, + ): Promise<InteractionResponse<BooleanCache<Cached>>>; + public deleteReply(message?: MessageResolvable | '@original'): Promise<void>; + public editReply( + options: string | MessagePayload | InteractionEditReplyOptions, + ): Promise<Message<BooleanCache<Cached>>>; + public deferReply( + options: InteractionDeferReplyOptions & { fetchReply: true }, + ): Promise<Message<BooleanCache<Cached>>>; + public deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse<BooleanCache<Cached>>>; + public fetchReply(message?: Snowflake | '@original'): Promise<Message<BooleanCache<Cached>>>; + public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<Message<BooleanCache<Cached>>>; + public deferUpdate( + options: InteractionDeferUpdateOptions & { fetchReply: true }, + ): Promise<Message<BooleanCache<Cached>>>; + public deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse<BooleanCache<Cached>>>; + public inGuild(): this is ModalSubmitInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is ModalSubmitInteraction<'cached'>; + public inRawGuild(): this is ModalSubmitInteraction<'raw'>; + public isFromMessage(): this is ModalMessageModalSubmitInteraction<Cached>; +} + +export class NewsChannel extends BaseGuildTextChannel { + public threads: GuildTextThreadManager<AllowedThreadTypeForNewsChannel>; + public type: ChannelType.GuildAnnouncement; + public addFollower(channel: TextChannelResolvable, reason?: string): Promise<NewsChannel>; +} + +export class OAuth2Guild extends BaseGuild { + private constructor(client: Client<true>, data: RawOAuth2GuildData); + public owner: boolean; + public permissions: Readonly<PermissionsBitField>; +} + +export class PartialGroupDMChannel extends BaseChannel { + private constructor(client: Client<true>, data: RawPartialGroupDMChannelData); + public type: ChannelType.GroupDM; + public flags: null; + public name: string | null; + public icon: string | null; + public recipients: PartialRecipient[]; + public iconURL(options?: ImageURLOptions): string | null; + public toString(): ChannelMention; +} + +export interface GuildForumTagEmoji { + id: Snowflake | null; + name: string | null; +} + +export interface GuildForumTag { + id: Snowflake; + name: string; + moderated: boolean; + emoji: GuildForumTagEmoji | null; +} + +export type GuildForumTagData = Partial<GuildForumTag> & { name: string }; + +export interface DefaultReactionEmoji { + id: Snowflake | null; + name: string | null; +} + +export class ForumChannel extends TextBasedChannelMixin(GuildChannel, true, [ + 'send', + 'lastMessage', + 'lastPinAt', + 'bulkDelete', + 'sendTyping', + 'createMessageCollector', + 'awaitMessages', + 'createMessageComponentCollector', + 'awaitMessageComponent', +]) { + public type: ChannelType.GuildForum; + public threads: GuildForumThreadManager; + public availableTags: GuildForumTag[]; + public defaultReactionEmoji: DefaultReactionEmoji | null; + public defaultThreadRateLimitPerUser: number | null; + public rateLimitPerUser: number | null; + public defaultAutoArchiveDuration: ThreadAutoArchiveDuration | null; + public nsfw: boolean; + public topic: string | null; + public defaultSortOrder: SortOrderType | null; + public defaultForumLayout: ForumLayoutType; + + public setAvailableTags(tags: GuildForumTagData[], reason?: string): Promise<this>; + public setDefaultReactionEmoji(emojiId: DefaultReactionEmoji | null, reason?: string): Promise<this>; + public setDefaultThreadRateLimitPerUser(rateLimit: number, reason?: string): Promise<this>; + public createInvite(options?: InviteCreateOptions): Promise<Invite>; + public fetchInvites(cache?: boolean): Promise<Collection<string, Invite>>; + public setDefaultAutoArchiveDuration( + defaultAutoArchiveDuration: ThreadAutoArchiveDuration, + reason?: string, + ): Promise<this>; + public setTopic(topic: string | null, reason?: string): Promise<this>; + public setDefaultSortOrder(defaultSortOrder: SortOrderType | null, reason?: string): Promise<this>; + public setDefaultForumLayout(defaultForumLayout: ForumLayoutType, reason?: string): Promise<this>; +} + +export class PermissionOverwrites extends Base { + private constructor(client: Client<true>, data: RawPermissionOverwriteData, channel: NonThreadGuildBasedChannel); + public allow: Readonly<PermissionsBitField>; + public readonly channel: NonThreadGuildBasedChannel; + public deny: Readonly<PermissionsBitField>; + public id: Snowflake; + public type: OverwriteType; + public edit(options: PermissionOverwriteOptions, reason?: string): Promise<PermissionOverwrites>; + public delete(reason?: string): Promise<PermissionOverwrites>; + public toJSON(): unknown; + public static resolveOverwriteOptions( + options: PermissionOverwriteOptions, + initialPermissions: { allow?: PermissionResolvable; deny?: PermissionResolvable }, + ): ResolvedOverwriteOptions; + public static resolve(overwrite: OverwriteResolvable, guild: Guild): APIOverwrite; +} + +export type PermissionsString = keyof typeof PermissionFlagsBits; + +export class PermissionsBitField extends BitField<PermissionsString, bigint> { + public any(permission: PermissionResolvable, checkAdmin?: boolean): boolean; + public has(permission: PermissionResolvable, checkAdmin?: boolean): boolean; + public missing(bits: BitFieldResolvable<PermissionsString, bigint>, checkAdmin?: boolean): PermissionsString[]; + public serialize(checkAdmin?: boolean): Record<PermissionsString, boolean>; + public toArray(): PermissionsString[]; + + public static All: bigint; + public static Default: bigint; + public static StageModerator: bigint; + public static Flags: typeof PermissionFlagsBits; + public static resolve(permission?: PermissionResolvable): bigint; +} + +export class Presence extends Base { + protected constructor(client: Client<true>, data?: RawPresenceData); + public activities: Activity[]; + public clientStatus: ClientPresenceStatusData | null; + public guild: Guild | null; + public get member(): GuildMember | null; + public status: PresenceStatus; + public get user(): User | null; + public userId: Snowflake; + public equals(presence: Presence): boolean; +} + +export class ReactionCollector extends Collector<Snowflake | string, MessageReaction, [User]> { + public constructor(message: Message, options?: ReactionCollectorOptions); + private _handleChannelDeletion(channel: NonThreadGuildBasedChannel): void; + private _handleGuildDeletion(guild: Guild): void; + private _handleMessageDeletion(message: Message): void; + + public message: Message; + public options: ReactionCollectorOptions; + public total: number; + public users: Collection<Snowflake, User>; + + public static key(reaction: MessageReaction): Snowflake | string; + + public collect(reaction: MessageReaction, user: User): Snowflake | string | null; + public dispose(reaction: MessageReaction, user: User): Snowflake | string | null; + public empty(): void; + + public on( + event: 'collect' | 'dispose' | 'remove' | 'ignore', + listener: (reaction: MessageReaction, user: User) => void, + ): this; + public on(event: 'end', listener: (collected: Collection<Snowflake, MessageReaction>, reason: string) => void): this; + public on(event: string, listener: (...args: any[]) => void): this; + + public once( + event: 'collect' | 'dispose' | 'remove' | 'ignore', + listener: (reaction: MessageReaction, user: User) => void, + ): this; + public once( + event: 'end', + listener: (collected: Collection<Snowflake, MessageReaction>, reason: string) => void, + ): this; + public once(event: string, listener: (...args: any[]) => void): this; +} + +export class ReactionEmoji extends Emoji { + private constructor(reaction: MessageReaction, emoji: RawReactionEmojiData); + public reaction: MessageReaction; + public toJSON(): unknown; +} + +export class RichPresenceAssets { + private constructor(activity: Activity, assets: RawRichPresenceAssets); + public readonly activity: Activity; + public largeImage: Snowflake | null; + public largeText: string | null; + public smallImage: Snowflake | null; + public smallText: string | null; + public largeImageURL(options?: ImageURLOptions): string | null; + public smallImageURL(options?: ImageURLOptions): string | null; +} + +export class Role extends Base { + private constructor(client: Client<true>, data: RawRoleData, guild: Guild); + public color: number; + public get createdAt(): Date; + public get createdTimestamp(): number; + public get editable(): boolean; + public flags: RoleFlagsBitField; + public guild: Guild; + public get hexColor(): HexColorString; + public hoist: boolean; + public id: Snowflake; + public managed: boolean; + public get members(): Collection<Snowflake, GuildMember>; + public mentionable: boolean; + public name: string; + public permissions: Readonly<PermissionsBitField>; + public get position(): number; + public rawPosition: number; + public tags: RoleTagData | null; + public comparePositionTo(role: RoleResolvable): number; + public icon: string | null; + public unicodeEmoji: string | null; + public delete(reason?: string): Promise<Role>; + public edit(options: RoleEditOptions): Promise<Role>; + public equals(role: Role): boolean; + public iconURL(options?: ImageURLOptions): string | null; + public permissionsIn( + channel: NonThreadGuildBasedChannel | Snowflake, + checkAdmin?: boolean, + ): Readonly<PermissionsBitField>; + public setColor(color: ColorResolvable, reason?: string): Promise<Role>; + public setHoist(hoist?: boolean, reason?: string): Promise<Role>; + public setMentionable(mentionable?: boolean, reason?: string): Promise<Role>; + public setName(name: string, reason?: string): Promise<Role>; + public setPermissions(permissions: PermissionResolvable, reason?: string): Promise<Role>; + public setIcon(icon: BufferResolvable | Base64Resolvable | EmojiResolvable | null, reason?: string): Promise<Role>; + public setPosition(position: number, options?: SetRolePositionOptions): Promise<Role>; + public setUnicodeEmoji(unicodeEmoji: string | null, reason?: string): Promise<Role>; + public toJSON(): unknown; + public toString(): RoleMention; +} + +export type RoleFlagsString = keyof typeof RoleFlags; + +export class RoleFlagsBitField extends BitField<RoleFlagsString> { + public static Flags: typeof RoleFlags; + public static resolve(bit?: BitFieldResolvable<RoleFlagsString, number>): number; +} + +export class StringSelectMenuInteraction< + Cached extends CacheType = CacheType, +> extends MessageComponentInteraction<Cached> { + public constructor(client: Client<true>, data: APIMessageStringSelectInteractionData); + public get component(): CacheTypeReducer< + Cached, + StringSelectMenuComponent, + APIStringSelectComponent, + StringSelectMenuComponent | APIStringSelectComponent, + StringSelectMenuComponent | APIStringSelectComponent + >; + public componentType: ComponentType.StringSelect; + public values: string[]; + public inGuild(): this is StringSelectMenuInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is StringSelectMenuInteraction<'cached'>; + public inRawGuild(): this is StringSelectMenuInteraction<'raw'>; +} + +export { + /** @deprecated Use {@link StringSelectMenuInteraction} instead */ + StringSelectMenuInteraction as SelectMenuInteraction, +}; + +export class UserSelectMenuInteraction< + Cached extends CacheType = CacheType, +> extends MessageComponentInteraction<Cached> { + public constructor(client: Client<true>, data: APIMessageUserSelectInteractionData); + public get component(): CacheTypeReducer< + Cached, + UserSelectMenuComponent, + APIUserSelectComponent, + UserSelectMenuComponent | APIUserSelectComponent, + UserSelectMenuComponent | APIUserSelectComponent + >; + public componentType: ComponentType.UserSelect; + public values: Snowflake[]; + public users: Collection<Snowflake, User>; + public members: Collection< + Snowflake, + CacheTypeReducer<Cached, GuildMember, APIGuildMember, GuildMember | APIGuildMember, GuildMember | APIGuildMember> + >; + public inGuild(): this is UserSelectMenuInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is UserSelectMenuInteraction<'cached'>; + public inRawGuild(): this is UserSelectMenuInteraction<'raw'>; +} + +export class RoleSelectMenuInteraction< + Cached extends CacheType = CacheType, +> extends MessageComponentInteraction<Cached> { + public constructor(client: Client<true>, data: APIMessageRoleSelectInteractionData); + public get component(): CacheTypeReducer< + Cached, + RoleSelectMenuComponent, + APIRoleSelectComponent, + RoleSelectMenuComponent | APIRoleSelectComponent, + RoleSelectMenuComponent | APIRoleSelectComponent + >; + public componentType: ComponentType.RoleSelect; + public values: Snowflake[]; + public roles: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole, Role | APIRole, Role | APIRole>>; + public inGuild(): this is RoleSelectMenuInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is RoleSelectMenuInteraction<'cached'>; + public inRawGuild(): this is RoleSelectMenuInteraction<'raw'>; +} + +export class MentionableSelectMenuInteraction< + Cached extends CacheType = CacheType, +> extends MessageComponentInteraction<Cached> { + public constructor(client: Client<true>, data: APIMessageMentionableSelectInteractionData); + public get component(): CacheTypeReducer< + Cached, + MentionableSelectMenuComponent, + APIMentionableSelectComponent, + MentionableSelectMenuComponent | APIMentionableSelectComponent, + MentionableSelectMenuComponent | APIMentionableSelectComponent + >; + public componentType: ComponentType.MentionableSelect; + public values: Snowflake[]; + public users: Collection<Snowflake, User>; + public members: Collection< + Snowflake, + CacheTypeReducer<Cached, GuildMember, APIGuildMember, GuildMember | APIGuildMember, GuildMember | APIGuildMember> + >; + public roles: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole, Role | APIRole, Role | APIRole>>; + public inGuild(): this is MentionableSelectMenuInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is MentionableSelectMenuInteraction<'cached'>; + public inRawGuild(): this is MentionableSelectMenuInteraction<'raw'>; +} + +export class ChannelSelectMenuInteraction< + Cached extends CacheType = CacheType, +> extends MessageComponentInteraction<Cached> { + public constructor(client: Client<true>, data: APIMessageChannelSelectInteractionData); + public get component(): CacheTypeReducer< + Cached, + ChannelSelectMenuComponent, + APIChannelSelectComponent, + ChannelSelectMenuComponent | APIChannelSelectComponent, + ChannelSelectMenuComponent | APIChannelSelectComponent + >; + public componentType: ComponentType.ChannelSelect; + public values: Snowflake[]; + public channels: Collection< + Snowflake, + CacheTypeReducer<Cached, Channel, APIChannel, Channel | APIChannel, Channel | APIChannel> + >; + public inGuild(): this is ChannelSelectMenuInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is ChannelSelectMenuInteraction<'cached'>; + public inRawGuild(): this is ChannelSelectMenuInteraction<'raw'>; +} + +// Ideally this should be named SelectMenuInteraction, but that's the name of the "old" StringSelectMenuInteraction, meaning +// the type name is reserved as a re-export to prevent a breaking change from being made, as such: +// TODO: Rename this to SelectMenuInteraction in the next major +export type AnySelectMenuInteraction<Cached extends CacheType = CacheType> = + | StringSelectMenuInteraction<Cached> + | UserSelectMenuInteraction<Cached> + | RoleSelectMenuInteraction<Cached> + | MentionableSelectMenuInteraction<Cached> + | ChannelSelectMenuInteraction<Cached>; + +export type SelectMenuType = APISelectMenuComponent['type']; + +export interface ShardEventTypes { + death: [process: ChildProcess | Worker]; + disconnect: []; + error: [error: Error]; + message: [message: any]; + ready: []; + reconnecting: []; + resume: []; + spawn: [process: ChildProcess | Worker]; +} + +export class Shard extends EventEmitter { + private constructor(manager: ShardingManager, id: number); + private _evals: Map<string, Promise<unknown>>; + private _exitListener: (...args: any[]) => void; + private _fetches: Map<string, Promise<unknown>>; + private _handleExit(respawn?: boolean, timeout?: number): void; + private _handleMessage(message: unknown): void; + private incrementMaxListeners(emitter: EventEmitter | ChildProcess): void; + private decrementMaxListeners(emitter: EventEmitter | ChildProcess): void; + + public args: string[]; + public execArgv: string[]; + public env: unknown; + public id: number; + public manager: ShardingManager; + public process: ChildProcess | null; + public ready: boolean; + public silent: boolean; + public worker: Worker | null; + public eval(script: string): Promise<unknown>; + public eval<T>(fn: (client: Client) => T): Promise<T>; + public eval<T, P>(fn: (client: Client<true>, context: Serialized<P>) => T, context: P): Promise<T>; + public fetchClientValue(prop: string): Promise<unknown>; + public kill(): void; + public respawn(options?: { delay?: number; timeout?: number }): Promise<ChildProcess>; + public send(message: unknown): Promise<Shard>; + public spawn(timeout?: number): Promise<ChildProcess>; + + public on<K extends keyof ShardEventTypes>( + event: K, + listener: (...args: ShardEventTypes[K]) => Awaitable<void>, + ): this; + + public once<K extends keyof ShardEventTypes>( + event: K, + listener: (...args: ShardEventTypes[K]) => Awaitable<void>, + ): this; +} + +export class ShardClientUtil { + private constructor(client: Client<true>, mode: ShardingManagerMode); + private _handleMessage(message: unknown): void; + private _respond(type: string, message: unknown): void; + private incrementMaxListeners(emitter: EventEmitter | ChildProcess): void; + private decrementMaxListeners(emitter: EventEmitter | ChildProcess): void; + + public client: Client; + public get count(): number; + public get ids(): number[]; + public mode: ShardingManagerMode; + public parentPort: MessagePort | null; + public broadcastEval<T>(fn: (client: Client) => Awaitable<T>): Promise<Serialized<T>[]>; + public broadcastEval<T>(fn: (client: Client) => Awaitable<T>, options: { shard: number }): Promise<Serialized<T>>; + public broadcastEval<T, P>( + fn: (client: Client<true>, context: Serialized<P>) => Awaitable<T>, + options: { context: P }, + ): Promise<Serialized<T>[]>; + public broadcastEval<T, P>( + fn: (client: Client<true>, context: Serialized<P>) => Awaitable<T>, + options: { context: P; shard: number }, + ): Promise<Serialized<T>>; + public fetchClientValues(prop: string): Promise<unknown[]>; + public fetchClientValues(prop: string, shard: number): Promise<unknown>; + public respawnAll(options?: MultipleShardRespawnOptions): Promise<void>; + public send(message: unknown): Promise<void>; + + public static singleton(client: Client<true>, mode: ShardingManagerMode): ShardClientUtil; + public static shardIdForGuildId(guildId: Snowflake, shardCount: number): number; +} + +export class ShardingManager extends EventEmitter { + public constructor(file: string, options?: ShardingManagerOptions); + private _performOnShards(method: string, args: unknown[]): Promise<unknown[]>; + private _performOnShards(method: string, args: unknown[], shard: number): Promise<unknown>; + + public file: string; + public respawn: boolean; + public silent: boolean; + public shardArgs: string[]; + public shards: Collection<number, Shard>; + public token: string | null; + public totalShards: number | 'auto'; + public shardList: number[] | 'auto'; + public broadcast(message: unknown): Promise<Shard[]>; + public broadcastEval<T>(fn: (client: Client) => Awaitable<T>): Promise<Serialized<T>[]>; + public broadcastEval<T>(fn: (client: Client) => Awaitable<T>, options: { shard: number }): Promise<Serialized<T>>; + public broadcastEval<T, P>( + fn: (client: Client<true>, context: Serialized<P>) => Awaitable<T>, + options: { context: P }, + ): Promise<Serialized<T>[]>; + public broadcastEval<T, P>( + fn: (client: Client<true>, context: Serialized<P>) => Awaitable<T>, + options: { context: P; shard: number }, + ): Promise<Serialized<T>>; + public createShard(id: number): Shard; + public fetchClientValues(prop: string): Promise<unknown[]>; + public fetchClientValues(prop: string, shard: number): Promise<unknown>; + public respawnAll(options?: MultipleShardRespawnOptions): Promise<Collection<number, Shard>>; + public spawn(options?: MultipleShardSpawnOptions): Promise<Collection<number, Shard>>; + + public on(event: 'shardCreate', listener: (shard: Shard) => Awaitable<void>): this; + + public once(event: 'shardCreate', listener: (shard: Shard) => Awaitable<void>): this; +} + +export interface FetchRecommendedShardCountOptions { + guildsPerShard?: number; + multipleOf?: number; +} + +export { + DiscordSnowflake as SnowflakeUtil, + SnowflakeGenerateOptions, + DeconstructedSnowflake, +} from '@sapphire/snowflake'; + +export class StageChannel extends BaseGuildVoiceChannel { + public get stageInstance(): StageInstance | null; + public topic: string | null; + public type: ChannelType.GuildStageVoice; + public createStageInstance(options: StageInstanceCreateOptions): Promise<StageInstance>; + public setTopic(topic: string): Promise<StageChannel>; +} + +export class DirectoryChannel extends BaseChannel { + public flags: Readonly<ChannelFlagsBitField>; + public guild: InviteGuild; + public guildId: Snowflake; + public name: string; +} + +export class StageInstance extends Base { + private constructor(client: Client<true>, data: RawStageInstanceData, channel: StageChannel); + public id: Snowflake; + public guildId: Snowflake; + public channelId: Snowflake; + public topic: string; + public privacyLevel: StageInstancePrivacyLevel; + /** @deprecated See https://github.com/discord/discord-api-docs/pull/4296 for more information */ + public discoverableDisabled: boolean | null; + public guildScheduledEventId?: Snowflake; + public get channel(): StageChannel | null; + public get guild(): Guild | null; + public get guildScheduledEvent(): GuildScheduledEvent | null; + public edit(options: StageInstanceEditOptions): Promise<StageInstance>; + public delete(): Promise<StageInstance>; + public setTopic(topic: string): Promise<StageInstance>; + public get createdTimestamp(): number; + public get createdAt(): Date; +} + +export class Sticker extends Base { + private constructor(client: Client<true>, data: RawStickerData); + public get createdTimestamp(): number; + public get createdAt(): Date; + public available: boolean | null; + public description: string | null; + public format: StickerFormatType; + public get guild(): Guild | null; + public guildId: Snowflake | null; + public id: Snowflake; + public name: string; + public packId: Snowflake | null; + public get partial(): boolean; + public sortValue: number | null; + public tags: string | null; + public type: StickerType | null; + public user: User | null; + public get url(): string; + public fetch(): Promise<Sticker>; + public fetchPack(): Promise<StickerPack | null>; + public fetchUser(): Promise<User | null>; + public edit(options?: GuildStickerEditOptions): Promise<Sticker>; + public delete(reason?: string): Promise<Sticker>; + public equals(other: Sticker | unknown): boolean; +} + +export class StickerPack extends Base { + private constructor(client: Client<true>, data: RawStickerPackData); + public get createdTimestamp(): number; + public get createdAt(): Date; + public bannerId: Snowflake | null; + public get coverSticker(): Sticker | null; + public coverStickerId: Snowflake | null; + public description: string; + public id: Snowflake; + public name: string; + public skuId: Snowflake; + public stickers: Collection<Snowflake, Sticker>; + public bannerURL(options?: ImageURLOptions): string | null; +} + +export class Sweepers { + public constructor(client: Client<true>, options: SweeperOptions); + public readonly client: Client; + public intervals: Record<SweeperKey, NodeJS.Timeout | null>; + public options: SweeperOptions; + + public sweepApplicationCommands( + filter: CollectionSweepFilter< + SweeperDefinitions['applicationCommands'][0], + SweeperDefinitions['applicationCommands'][1] + >, + ): number; + public sweepAutoModerationRules( + filter: CollectionSweepFilter< + SweeperDefinitions['autoModerationRules'][0], + SweeperDefinitions['autoModerationRules'][1] + >, + ): number; + public sweepBans(filter: CollectionSweepFilter<SweeperDefinitions['bans'][0], SweeperDefinitions['bans'][1]>): number; + public sweepEmojis( + filter: CollectionSweepFilter<SweeperDefinitions['emojis'][0], SweeperDefinitions['emojis'][1]>, + ): number; + public sweepInvites( + filter: CollectionSweepFilter<SweeperDefinitions['invites'][0], SweeperDefinitions['invites'][1]>, + ): number; + public sweepGuildMembers( + filter: CollectionSweepFilter<SweeperDefinitions['guildMembers'][0], SweeperDefinitions['guildMembers'][1]>, + ): number; + public sweepMessages( + filter: CollectionSweepFilter<SweeperDefinitions['messages'][0], SweeperDefinitions['messages'][1]>, + ): number; + public sweepPresences( + filter: CollectionSweepFilter<SweeperDefinitions['presences'][0], SweeperDefinitions['presences'][1]>, + ): number; + public sweepReactions( + filter: CollectionSweepFilter<SweeperDefinitions['reactions'][0], SweeperDefinitions['reactions'][1]>, + ): number; + public sweepStageInstances( + filter: CollectionSweepFilter<SweeperDefinitions['stageInstances'][0], SweeperDefinitions['stageInstances'][1]>, + ): number; + public sweepStickers( + filter: CollectionSweepFilter<SweeperDefinitions['stickers'][0], SweeperDefinitions['stickers'][1]>, + ): number; + public sweepThreadMembers( + filter: CollectionSweepFilter<SweeperDefinitions['threadMembers'][0], SweeperDefinitions['threadMembers'][1]>, + ): number; + public sweepThreads( + filter: CollectionSweepFilter<SweeperDefinitions['threads'][0], SweeperDefinitions['threads'][1]>, + ): number; + public sweepUsers( + filter: CollectionSweepFilter<SweeperDefinitions['users'][0], SweeperDefinitions['users'][1]>, + ): number; + public sweepVoiceStates( + filter: CollectionSweepFilter<SweeperDefinitions['voiceStates'][0], SweeperDefinitions['voiceStates'][1]>, + ): number; + + public static archivedThreadSweepFilter( + lifetime?: number, + ): GlobalSweepFilter<SweeperDefinitions['threads'][0], SweeperDefinitions['threads'][1]>; + public static expiredInviteSweepFilter( + lifetime?: number, + ): GlobalSweepFilter<SweeperDefinitions['invites'][0], SweeperDefinitions['invites'][1]>; + public static filterByLifetime<K, V>(options?: LifetimeFilterOptions<K, V>): GlobalSweepFilter<K, V>; + public static outdatedMessageSweepFilter( + lifetime?: number, + ): GlobalSweepFilter<SweeperDefinitions['messages'][0], SweeperDefinitions['messages'][1]>; +} + +export type SystemChannelFlagsString = keyof typeof GuildSystemChannelFlags; + +export class SystemChannelFlagsBitField extends BitField<SystemChannelFlagsString> { + public static Flags: typeof GuildSystemChannelFlags; + public static resolve(bit?: BitFieldResolvable<SystemChannelFlagsString, number>): number; +} + +export class Team extends Base { + private constructor(client: Client<true>, data: RawTeamData); + public id: Snowflake; + public name: string; + public icon: string | null; + public ownerId: Snowflake | null; + public members: Collection<Snowflake, TeamMember>; + public get owner(): TeamMember | null; + public get createdAt(): Date; + public get createdTimestamp(): number; + + public iconURL(options?: ImageURLOptions): string | null; + public toJSON(): unknown; + public toString(): string; +} + +export class TeamMember extends Base { + private constructor(team: Team, data: RawTeamMemberData); + public team: Team; + public get id(): Snowflake; + public permissions: string[]; + public membershipState: TeamMemberMembershipState; + public user: User; + + public toString(): UserMention; +} + +export class TextChannel extends BaseGuildTextChannel { + public rateLimitPerUser: number; + public threads: GuildTextThreadManager<AllowedThreadTypeForTextChannel>; + public type: ChannelType.GuildText; +} + +export type AnyThreadChannel<Forum extends boolean = boolean> = PublicThreadChannel<Forum> | PrivateThreadChannel; + +export interface PublicThreadChannel<Forum extends boolean = boolean> extends ThreadChannel<Forum> { + type: ChannelType.PublicThread | ChannelType.AnnouncementThread; +} + +export interface PrivateThreadChannel extends ThreadChannel<false> { + get createdTimestamp(): number; + get createdAt(): Date; + type: ChannelType.PrivateThread; +} + +export class ThreadChannel<Forum extends boolean = boolean> extends TextBasedChannelMixin(BaseChannel, true, [ + 'fetchWebhooks', + 'createWebhook', + 'setNSFW', +]) { + private constructor(guild: Guild, data?: RawThreadChannelData, client?: Client<true>); + public archived: boolean | null; + public get archivedAt(): Date | null; + public archiveTimestamp: number | null; + public get createdAt(): Date | null; + private _createdTimestamp: number | null; + public get createdTimestamp(): number | null; + public autoArchiveDuration: ThreadAutoArchiveDuration | null; + public get editable(): boolean; + public flags: Readonly<ChannelFlagsBitField>; + public guild: Guild; + public guildId: Snowflake; + public get guildMembers(): Collection<Snowflake, GuildMember>; + public invitable: boolean | null; + public get joinable(): boolean; + public get joined(): boolean; + public locked: boolean | null; + public get manageable(): boolean; + public get viewable(): boolean; + public get sendable(): boolean; + public memberCount: number | null; + public messageCount: number | null; + public appliedTags: Snowflake[]; + public totalMessageSent: number | null; + public members: ThreadMemberManager; + public name: string; + public ownerId: Snowflake | null; + public get parent(): If<Forum, ForumChannel, TextChannel | NewsChannel> | null; + public parentId: Snowflake | null; + public rateLimitPerUser: number | null; + public type: ThreadChannelType; + public get unarchivable(): boolean; + public delete(reason?: string): Promise<this>; + public edit(options: ThreadEditOptions): Promise<AnyThreadChannel>; + public join(): Promise<AnyThreadChannel>; + public leave(): Promise<AnyThreadChannel>; + public permissionsFor(memberOrRole: GuildMember | Role, checkAdmin?: boolean): Readonly<PermissionsBitField>; + public permissionsFor( + memberOrRole: GuildMemberResolvable | RoleResolvable, + checkAdmin?: boolean, + ): Readonly<PermissionsBitField> | null; + public fetchOwner(options?: BaseFetchOptions): Promise<ThreadMember | null>; + public fetchStarterMessage(options?: BaseFetchOptions): Promise<Message<true> | null>; + public setArchived(archived?: boolean, reason?: string): Promise<AnyThreadChannel>; + public setAutoArchiveDuration( + autoArchiveDuration: ThreadAutoArchiveDuration, + reason?: string, + ): Promise<AnyThreadChannel>; + public setInvitable(invitable?: boolean, reason?: string): Promise<AnyThreadChannel>; + public setLocked(locked?: boolean, reason?: string): Promise<AnyThreadChannel>; + public setName(name: string, reason?: string): Promise<AnyThreadChannel>; + // The following 3 methods can only be run on forum threads. + public setAppliedTags(appliedTags: Snowflake[], reason?: string): Promise<ThreadChannel<true>>; + public pin(reason?: string): Promise<ThreadChannel<true>>; + public unpin(reason?: string): Promise<ThreadChannel<true>>; + public toString(): ChannelMention; +} + +export class ThreadMember<HasMemberData extends boolean = boolean> extends Base { + private constructor(thread: ThreadChannel, data: RawThreadMemberData, extra?: unknown); + public flags: ThreadMemberFlagsBitField; + private member: If<HasMemberData, GuildMember>; + public get guildMember(): HasMemberData extends true ? GuildMember : GuildMember | null; + public id: Snowflake; + public get joinedAt(): Date | null; + public joinedTimestamp: number | null; + public get manageable(): boolean; + public thread: AnyThreadChannel; + public get user(): User | null; + public get partial(): false; + public remove(reason?: string): Promise<ThreadMember>; +} + +export type ThreadMemberFlagsString = keyof typeof ThreadMemberFlags; + +export class ThreadMemberFlagsBitField extends BitField<ThreadMemberFlagsString> { + public static Flags: typeof ThreadMemberFlags; + public static resolve(bit?: BitFieldResolvable<ThreadMemberFlagsString, number>): number; +} + +export class Typing extends Base { + private constructor(channel: TextBasedChannel, user: PartialUser, data?: RawTypingData); + public channel: TextBasedChannel; + public user: User | PartialUser; + public startedTimestamp: number; + public get startedAt(): Date; + public get guild(): Guild | null; + public get member(): GuildMember | null; + public inGuild(): this is this & { + channel: TextChannel | NewsChannel | ThreadChannel; + get guild(): Guild; + }; +} + +export class User extends PartialTextBasedChannel(Base) { + protected constructor(client: Client<true>, data: RawUserData); + private _equals(user: APIUser): boolean; + + public accentColor: number | null | undefined; + public avatar: string | null; + public avatarDecoration: string | null; + public banner: string | null | undefined; + public bot: boolean; + public get createdAt(): Date; + public get createdTimestamp(): number; + public discriminator: string; + public get displayName(): string; + public get defaultAvatarURL(): string; + public get dmChannel(): DMChannel | null; + public flags: Readonly<UserFlagsBitField> | null; + public globalName: string | null; + public get hexAccentColor(): HexColorString | null | undefined; + public id: Snowflake; + public get partial(): false; + public system: boolean; + public get tag(): string; + public username: string; + public avatarURL(options?: ImageURLOptions): string | null; + public avatarDecorationURL(options?: BaseImageURLOptions): string | null; + public bannerURL(options?: ImageURLOptions): string | null | undefined; + public createDM(force?: boolean): Promise<DMChannel>; + public deleteDM(): Promise<DMChannel>; + public displayAvatarURL(options?: ImageURLOptions): string; + public equals(user: User): boolean; + public fetch(force?: boolean): Promise<User>; + public fetchFlags(force?: boolean): Promise<UserFlagsBitField>; + public toString(): UserMention; +} + +export class UserContextMenuCommandInteraction< + Cached extends CacheType = CacheType, +> extends ContextMenuCommandInteraction<Cached> { + public commandType: ApplicationCommandType.User; + public get targetUser(): User; + public get targetMember(): CacheTypeReducer<Cached, GuildMember, APIInteractionGuildMember>; + public inGuild(): this is UserContextMenuCommandInteraction<'raw' | 'cached'>; + public inCachedGuild(): this is UserContextMenuCommandInteraction<'cached'>; + public inRawGuild(): this is UserContextMenuCommandInteraction<'raw'>; +} + +export type UserFlagsString = keyof typeof UserFlags; + +export class UserFlagsBitField extends BitField<UserFlagsString> { + public static Flags: typeof UserFlags; + public static resolve(bit?: BitFieldResolvable<UserFlagsString, number>): number; +} + +export function basename(path: string, ext?: string): string; +export function cleanContent(str: string, channel: TextBasedChannel): string; +export function discordSort<K, V extends { rawPosition: number; id: Snowflake }>( + collection: Collection<K, V>, +): Collection<K, V>; +export function cleanCodeBlockContent(text: string): string; +export function fetchRecommendedShardCount(token: string, options?: FetchRecommendedShardCountOptions): Promise<number>; +export function flatten(obj: unknown, ...props: Record<string, boolean | string>[]): unknown; +export function makeError(obj: MakeErrorOptions): Error; +export function makePlainError(err: Error): MakeErrorOptions; +export function mergeDefault(def: unknown, given: unknown): unknown; +export function moveElementInArray(array: unknown[], element: unknown, newIndex: number, offset?: boolean): number; +export function parseEmoji(text: string): { animated: boolean; name: string; id: Snowflake | null } | null; +export function resolveColor(color: ColorResolvable): number; +export function resolvePartialEmoji(emoji: EmojiIdentifierResolvable): Partial<APIPartialEmoji> | null; +export function verifyString(data: string, error?: typeof Error, errorMessage?: string, allowEmpty?: boolean): string; +export function setPosition<T extends Channel | Role>( + item: T, + position: number, + relative: boolean, + sorted: Collection<Snowflake, T>, + client: Client<true>, + route: string, + reason?: string, +): Promise<{ id: Snowflake; position: number }[]>; +export function parseWebhookURL(url: string): WebhookClientDataIdWithToken | null; + +export interface MappedComponentBuilderTypes { + [ComponentType.Button]: ButtonBuilder; + [ComponentType.StringSelect]: StringSelectMenuBuilder; + [ComponentType.UserSelect]: UserSelectMenuBuilder; + [ComponentType.RoleSelect]: RoleSelectMenuBuilder; + [ComponentType.MentionableSelect]: MentionableSelectMenuBuilder; + [ComponentType.ChannelSelect]: ChannelSelectMenuBuilder; + [ComponentType.ActionRow]: ActionRowBuilder; + [ComponentType.TextInput]: TextInputBuilder; +} + +export interface MappedComponentTypes { + [ComponentType.Button]: ButtonComponent; + [ComponentType.StringSelect]: StringSelectMenuComponent; + [ComponentType.UserSelect]: UserSelectMenuComponent; + [ComponentType.RoleSelect]: RoleSelectMenuComponent; + [ComponentType.MentionableSelect]: MentionableSelectMenuComponent; + [ComponentType.ChannelSelect]: ChannelSelectMenuComponent; + [ComponentType.ActionRow]: ActionRowComponent; + [ComponentType.TextInput]: TextInputComponent; +} + +export interface ChannelCreateOptions { + allowFromUnknownGuild?: boolean; +} + +export function createChannel(client: Client<true>, data: APIChannel, options?: ChannelCreateOptions): Channel; + +export function createComponent<T extends keyof MappedComponentTypes>( + data: APIMessageComponent & { type: T }, +): MappedComponentTypes[T]; +export function createComponent<C extends Component>(data: C): C; +export function createComponent(data: APIMessageComponent | Component): Component; +export function createComponentBuilder<T extends keyof MappedComponentBuilderTypes>( + data: APIMessageComponent & { type: T }, +): MappedComponentBuilderTypes[T]; +export function createComponentBuilder<C extends ComponentBuilder>(data: C): C; +export function createComponentBuilder(data: APIMessageComponent | ComponentBuilder): ComponentBuilder; + +/** @deprecated This class is redundant as all methods of the class can be imported from discord.js directly. */ +export class Formatters extends null { + /** @deprecated Import this method directly from discord.js instead. */ + public static blockQuote: typeof blockQuote; + /** @deprecated Import this method directly from discord.js instead. */ + public static bold: typeof bold; + /** @deprecated Import this method directly from discord.js instead. */ + public static channelMention: typeof channelMention; + /** @deprecated Import this method directly from discord.js instead. */ + public static codeBlock: typeof codeBlock; + /** @deprecated Import this method directly from discord.js instead. */ + public static formatEmoji: typeof formatEmoji; + /** @deprecated Import this method directly from discord.js instead. */ + public static hideLinkEmbed: typeof hideLinkEmbed; + /** @deprecated Import this method directly from discord.js instead. */ + public static hyperlink: typeof hyperlink; + /** @deprecated Import this method directly from discord.js instead. */ + public static inlineCode: typeof inlineCode; + /** @deprecated Import this method directly from discord.js instead. */ + public static italic: typeof italic; + /** @deprecated Import this method directly from discord.js instead. */ + public static quote: typeof quote; + /** @deprecated Import this method directly from discord.js instead. */ + public static roleMention: typeof roleMention; + /** @deprecated Import this method directly from discord.js instead. */ + public static spoiler: typeof spoiler; + /** @deprecated Import this method directly from discord.js instead. */ + public static strikethrough: typeof strikethrough; + /** @deprecated Import this method directly from discord.js instead. */ + public static time: typeof time; + /** @deprecated Import this property directly from discord.js instead. */ + public static TimestampStyles: typeof TimestampStyles; + /** @deprecated Import this method directly from discord.js instead. */ + public static underscore: typeof underscore; + /** @deprecated Import this method directly from discord.js instead. */ + public static userMention: typeof userMention; +} + +export type ComponentData = + | MessageActionRowComponentData + | ModalActionRowComponentData + | ActionRowData<MessageActionRowComponentData | ModalActionRowComponentData>; + +export class VoiceChannel extends BaseGuildVoiceChannel { + public get speakable(): boolean; + public type: ChannelType.GuildVoice; +} + +export class VoiceRegion { + private constructor(data: RawVoiceRegionData); + public custom: boolean; + public deprecated: boolean; + public id: string; + public name: string; + public optimal: boolean; + public toJSON(): unknown; +} + +export class VoiceState extends Base { + private constructor(guild: Guild, data: RawVoiceStateData); + public get channel(): VoiceBasedChannel | null; + public channelId: Snowflake | null; + public get deaf(): boolean | null; + public guild: Guild; + public id: Snowflake; + public get member(): GuildMember | null; + public get mute(): boolean | null; + public selfDeaf: boolean | null; + public selfMute: boolean | null; + public serverDeaf: boolean | null; + public serverMute: boolean | null; + public sessionId: string | null; + public streaming: boolean | null; + public selfVideo: boolean | null; + public suppress: boolean | null; + public requestToSpeakTimestamp: number | null; + + public setDeaf(deaf?: boolean, reason?: string): Promise<GuildMember>; + public setMute(mute?: boolean, reason?: string): Promise<GuildMember>; + public disconnect(reason?: string): Promise<GuildMember>; + public setChannel(channel: GuildVoiceChannelResolvable | null, reason?: string): Promise<GuildMember>; + public setRequestToSpeak(request?: boolean): Promise<this>; + public setSuppressed(suppressed?: boolean): Promise<this>; + public edit(options: VoiceStateEditOptions): Promise<this>; +} + +export class Webhook extends WebhookMixin() { + private constructor(client: Client<true>, data?: RawWebhookData); + public avatar: string | null; + public avatarURL(options?: ImageURLOptions): string | null; + public channelId: Snowflake; + public readonly client: Client; + public guildId: Snowflake; + public name: string; + public owner: User | APIUser | null; + public sourceGuild: Guild | APIPartialGuild | null; + public sourceChannel: NewsChannel | APIPartialChannel | null; + public token: string | null; + public type: WebhookType; + public applicationId: Snowflake | null; + public get channel(): TextChannel | VoiceChannel | NewsChannel | ForumChannel | StageChannel | null; + public isUserCreated(): this is this & { + type: WebhookType.Incoming; + applicationId: null; + owner: User | APIUser; + }; + public isApplicationCreated(): this is this & { + type: WebhookType.Application; + applicationId: Snowflake; + owner: User | APIUser; + }; + public isIncoming(): this is this & { + type: WebhookType.Incoming; + token: string; + }; + public isChannelFollower(): this is this & { + type: WebhookType.ChannelFollower; + sourceGuild: Guild | APIPartialGuild; + sourceChannel: NewsChannel | APIPartialChannel; + token: null; + applicationId: null; + owner: User | APIUser; + }; + + public editMessage( + message: MessageResolvable, + options: string | MessagePayload | WebhookMessageEditOptions, + ): Promise<Message>; + public fetchMessage(message: Snowflake, options?: WebhookFetchMessageOptions): Promise<Message>; + public send(options: string | MessagePayload | WebhookMessageCreateOptions): Promise<Message>; +} + +export class WebhookClient extends WebhookMixin(BaseClient) { + public constructor(data: WebhookClientData, options?: WebhookClientOptions); + public readonly client: this; + public options: WebhookClientOptions; + public token: string; + public editMessage( + message: MessageResolvable, + options: string | MessagePayload | WebhookMessageEditOptions, + ): Promise<APIMessage>; + public fetchMessage(message: Snowflake, options?: WebhookFetchMessageOptions): Promise<APIMessage>; + public send(options: string | MessagePayload | WebhookMessageCreateOptions): Promise<APIMessage>; +} + +export class WebSocketManager extends EventEmitter { + private constructor(client: Client); + private readonly packetQueue: unknown[]; + private destroyed: boolean; + + public readonly client: Client; + public gateway: string | null; + public shards: Collection<number, WebSocketShard>; + public status: Status; + public get ping(): number; + + public on(event: GatewayDispatchEvents, listener: (data: any, shardId: number) => void): this; + public once(event: GatewayDispatchEvents, listener: (data: any, shardId: number) => void): this; + + private debug(message: string, shardId?: number): void; + private connect(): Promise<void>; + private broadcast(packet: unknown): void; + private destroy(): Promise<void>; + private handlePacket(packet?: unknown, shard?: WebSocketShard): boolean; + private checkShardsReady(): void; + private triggerClientReady(): void; +} + +export interface WebSocketShardEventTypes { + ready: []; + resumed: []; + invalidSession: []; + destroyed: []; + close: [event: CloseEvent]; + allReady: [unavailableGuilds?: Set<Snowflake>]; +} + +export class WebSocketShard extends EventEmitter { + private constructor(manager: WebSocketManager, id: number); + private closeSequence: number; + private sessionInfo: SessionInfo | null; + public lastPingTimestamp: number; + private expectedGuilds: Set<Snowflake> | null; + private readyTimeout: NodeJS.Timeout | null; + + public manager: WebSocketManager; + public id: number; + public status: Status; + public ping: number; + + private debug(message: string): void; + private onReadyPacket(packet: unknown): void; + private gotGuild(guildId: Snowflake): void; + private checkReady(): void; + private emitClose(event?: CloseEvent): void; + + public send(data: unknown, important?: boolean): void; + + public on<K extends keyof WebSocketShardEventTypes>( + event: K, + listener: (...args: WebSocketShardEventTypes[K]) => Awaitable<void>, + ): this; + + public once<K extends keyof WebSocketShardEventTypes>( + event: K, + listener: (...args: WebSocketShardEventTypes[K]) => Awaitable<void>, + ): this; +} + +export class Widget extends Base { + private constructor(client: Client<true>, data: RawWidgetData); + private _patch(data: RawWidgetData): void; + public fetch(): Promise<Widget>; + public id: Snowflake; + public name: string; + public instantInvite?: string; + public channels: Collection<Snowflake, WidgetChannel>; + public members: Collection<string, WidgetMember>; + public presenceCount: number; +} + +export class WidgetMember extends Base { + private constructor(client: Client<true>, data: RawWidgetMemberData); + public id: string; + public username: string; + public discriminator: string; + public avatar: string | null; + public status: PresenceStatus; + public deaf: boolean | null; + public mute: boolean | null; + public selfDeaf: boolean | null; + public selfMute: boolean | null; + public suppress: boolean | null; + public channelId: Snowflake | null; + public avatarURL: string; + public activity: WidgetActivity | null; +} + +export class WelcomeChannel extends Base { + private constructor(guild: Guild, data: RawWelcomeChannelData); + private _emoji: Omit<APIEmoji, 'animated'>; + public channelId: Snowflake; + public guild: Guild | InviteGuild; + public description: string; + public get channel(): TextChannel | NewsChannel | ForumChannel | null; + public get emoji(): GuildEmoji | Emoji; +} + +export class WelcomeScreen extends Base { + private constructor(guild: Guild, data: RawWelcomeScreenData); + public get enabled(): boolean; + public guild: Guild | InviteGuild; + public description: string | null; + public welcomeChannels: Collection<Snowflake, WelcomeChannel>; +} + +//#endregion + +//#region Constants + +export type NonSystemMessageType = + | MessageType.Default + | MessageType.Reply + | MessageType.ChatInputCommand + | MessageType.ContextMenuCommand; + +export type DeletableMessageType = + | MessageType.AutoModerationAction + | MessageType.ChannelFollowAdd + | MessageType.ChannelPinnedMessage + | MessageType.ChatInputCommand + | MessageType.ContextMenuCommand + | MessageType.Default + | MessageType.GuildBoost + | MessageType.GuildBoostTier1 + | MessageType.GuildBoostTier2 + | MessageType.GuildBoostTier3 + | MessageType.GuildInviteReminder + | MessageType.InteractionPremiumUpsell + | MessageType.Reply + | MessageType.RoleSubscriptionPurchase + | MessageType.StageEnd + | MessageType.StageRaiseHand + | MessageType.StageSpeaker + | MessageType.StageStart + | MessageType.StageTopic + | MessageType.ThreadCreated + | MessageType.UserJoin; + +export const Constants: { + MaxBulkDeletableMessageAge: 1_209_600_000; + SweeperKeys: SweeperKey[]; + NonSystemMessageTypes: NonSystemMessageType[]; + TextBasedChannelTypes: TextBasedChannelTypes[]; + GuildTextBasedChannelTypes: GuildTextBasedChannelTypes[]; + ThreadChannelTypes: ThreadChannelType[]; + VoiceBasedChannelTypes: VoiceBasedChannelTypes[]; + SelectMenuTypes: SelectMenuType[]; + DeletableMessageTypes: DeletableMessageType[]; + StickerFormatExtensionMap: Record<StickerFormatType, ImageFormat>; +}; + +export const version: string; + +//#endregion + +//#region Errors +export enum DiscordjsErrorCodes { + ClientInvalidOption = 'ClientInvalidOption', + ClientInvalidProvidedShards = 'ClientInvalidProvidedShards', + ClientMissingIntents = 'ClientMissingIntents', + ClientNotReady = 'ClientNotReady', + + TokenInvalid = 'TokenInvalid', + TokenMissing = 'TokenMissing', + ApplicationCommandPermissionsTokenMissing = 'ApplicationCommandPermissionsTokenMissing', + + /** @deprecated */ + WSCloseRequested = 'WSCloseRequested', + /** @deprecated */ + WSConnectionExists = 'WSConnectionExists', + /** @deprecated */ + WSNotOpen = 'WSNotOpen', + ManagerDestroyed = 'ManagerDestroyed', + + BitFieldInvalid = 'BitFieldInvalid', + + /** @deprecated */ + ShardingInvalid = 'ShardingInvalid', + /** @deprecated */ + ShardingRequired = 'ShardingRequired', + /** @deprecated */ + InvalidIntents = 'InvalidIntents', + /** @deprecated */ + DisallowedIntents = 'DisallowedIntents', + ShardingNoShards = 'ShardingNoShards', + ShardingInProcess = 'ShardingInProcess', + ShardingInvalidEvalBroadcast = 'ShardingInvalidEvalBroadcast', + ShardingShardNotFound = 'ShardingShardNotFound', + ShardingAlreadySpawned = 'ShardingAlreadySpawned', + ShardingProcessExists = 'ShardingProcessExists', + ShardingWorkerExists = 'ShardingWorkerExists', + ShardingReadyTimeout = 'ShardingReadyTimeout', + ShardingReadyDisconnected = 'ShardingReadyDisconnected', + ShardingReadyDied = 'ShardingReadyDied', + ShardingNoChildExists = 'ShardingNoChildExists', + ShardingShardMiscalculation = 'ShardingShardMiscalculation', + + ColorRange = 'ColorRange', + ColorConvert = 'ColorConvert', + + InviteOptionsMissingChannel = 'InviteOptionsMissingChannel', + + ButtonLabel = 'ButtonLabel', + ButtonURL = 'ButtonURL', + ButtonCustomId = 'ButtonCustomId', + + SelectMenuCustomId = 'SelectMenuCustomId', + SelectMenuPlaceholder = 'SelectMenuPlaceholder', + SelectOptionLabel = 'SelectOptionLabel', + SelectOptionValue = 'SelectOptionValue', + SelectOptionDescription = 'SelectOptionDescription', + + InteractionCollectorError = 'InteractionCollectorError', + + FileNotFound = 'FileNotFound', + + UserBannerNotFetched = 'UserBannerNotFetched', + UserNoDMChannel = 'UserNoDMChannel', + + VoiceNotStageChannel = 'VoiceNotStageChannel', + + VoiceStateNotOwn = 'VoiceStateNotOwn', + VoiceStateInvalidType = 'VoiceStateInvalidType', + + ReqResourceType = 'ReqResourceType', + + ImageFormat = 'ImageFormat', + ImageSize = 'ImageSize', + + MessageBulkDeleteType = 'MessageBulkDeleteType', + MessageNonceType = 'MessageNonceType', + MessageContentType = 'MessageContentType', + + SplitMaxLen = 'SplitMaxLen', + + BanResolveId = 'BanResolveId', + FetchBanResolveId = 'FetchBanResolveId', + + PruneDaysType = 'PruneDaysType', + + GuildChannelResolve = 'GuildChannelResolve', + GuildVoiceChannelResolve = 'GuildVoiceChannelResolve', + GuildChannelOrphan = 'GuildChannelOrphan', + GuildChannelUnowned = 'GuildChannelUnowned', + GuildOwned = 'GuildOwned', + GuildMembersTimeout = 'GuildMembersTimeout', + GuildUncachedMe = 'GuildUncachedMe', + ChannelNotCached = 'ChannelNotCached', + StageChannelResolve = 'StageChannelResolve', + GuildScheduledEventResolve = 'GuildScheduledEventResolve', + FetchOwnerId = 'FetchOwnerId', + + InvalidType = 'InvalidType', + InvalidElement = 'InvalidElement', + + MessageThreadParent = 'MessageThreadParent', + MessageExistingThread = 'MessageExistingThread', + ThreadInvitableType = 'ThreadInvitableType', + + WebhookMessage = 'WebhookMessage', + WebhookTokenUnavailable = 'WebhookTokenUnavailable', + WebhookURLInvalid = 'WebhookURLInvalid', + WebhookApplication = 'WebhookApplication', + MessageReferenceMissing = 'MessageReferenceMissing', + + EmojiType = 'EmojiType', + EmojiManaged = 'EmojiManaged', + MissingManageGuildExpressionsPermission = 'MissingManageGuildExpressionsPermission', + /** @deprecated Use {@link MissingManageGuildExpressionsPermission} instead. */ + MissingManageEmojisAndStickersPermission = 'MissingManageEmojisAndStickersPermission', + + NotGuildSticker = 'NotGuildSticker', + + ReactionResolveUser = 'ReactionResolveUser', + + VanityURL = 'VanityURL', + + InviteResolveCode = 'InviteResolveCode', + + InviteNotFound = 'InviteNotFound', + + DeleteGroupDMChannel = 'DeleteGroupDMChannel', + FetchGroupDMChannel = 'FetchGroupDMChannel', + + MemberFetchNonceLength = 'MemberFetchNonceLength', + + GlobalCommandPermissions = 'GlobalCommandPermissions', + GuildUncachedEntityResolve = 'GuildUncachedEntityResolve', + + InteractionAlreadyReplied = 'InteractionAlreadyReplied', + InteractionNotReplied = 'InteractionNotReplied', + /** @deprecated */ + InteractionEphemeralReplied = 'InteractionEphemeralReplied', + + CommandInteractionOptionNotFound = 'CommandInteractionOptionNotFound', + CommandInteractionOptionType = 'CommandInteractionOptionType', + CommandInteractionOptionEmpty = 'CommandInteractionOptionEmpty', + CommandInteractionOptionNoSubcommand = 'CommandInteractionOptionNoSubcommand', + CommandInteractionOptionNoSubcommandGroup = 'CommandInteractionOptionNoSubcommandGroup', + AutocompleteInteractionOptionNoFocusedOption = 'AutocompleteInteractionOptionNoFocusedOption', + + ModalSubmitInteractionFieldNotFound = 'ModalSubmitInteractionFieldNotFound', + ModalSubmitInteractionFieldType = 'ModalSubmitInteractionFieldType', + + InvalidMissingScopes = 'InvalidMissingScopes', + InvalidScopesWithPermissions = 'InvalidScopesWithPermissions', + + NotImplemented = 'NotImplemented', + + SweepFilterReturn = 'SweepFilterReturn', + + GuildForumMessageRequired = 'GuildForumMessageRequired', +} + +export interface DiscordjsErrorFields<Name extends string> { + readonly name: `${Name} [${DiscordjsErrorCodes}]`; + get code(): DiscordjsErrorCodes; +} + +export function DiscordjsErrorMixin<T, N extends string>( + Base: Constructable<T>, + name: N, +): Constructable<T & DiscordjsErrorFields<N>>; + +export class DiscordjsError extends DiscordjsErrorMixin(Error, 'Error') {} + +export class DiscordjsTypeError extends DiscordjsErrorMixin(TypeError, 'TypeError') {} + +export class DiscordjsRangeError extends DiscordjsErrorMixin(RangeError, 'RangeError') {} + +//#endregion + +//#region Managers + +export abstract class BaseManager { + protected constructor(client: Client); + public readonly client: Client; +} + +export abstract class DataManager<K, Holds, R> extends BaseManager { + protected constructor(client: Client<true>, holds: Constructable<Holds>); + public readonly holds: Constructable<Holds>; + public get cache(): Collection<K, Holds>; + public resolve(resolvable: Holds): Holds; + public resolve(resolvable: R): Holds | null; + public resolveId(resolvable: K | Holds): K; + public resolveId(resolvable: R): K | null; + public valueOf(): Collection<K, Holds>; +} + +export abstract class CachedManager<K, Holds, R> extends DataManager<K, Holds, R> { + protected constructor(client: Client<true>, holds: Constructable<Holds>, iterable?: Iterable<Holds>); + private readonly _cache: Collection<K, Holds>; + private _add(data: unknown, cache?: boolean, { id, extras }?: { id: K; extras: unknown[] }): Holds; +} + +export type ApplicationCommandDataResolvable = + | ApplicationCommandData + | RESTPostAPIApplicationCommandsJSONBody + | JSONEncodable<RESTPostAPIApplicationCommandsJSONBody>; + +export class ApplicationCommandManager< + ApplicationCommandScope = ApplicationCommand<{ guild: GuildResolvable }>, + PermissionsOptionsExtras = { guild: GuildResolvable }, + PermissionsGuildType = null, +> extends CachedManager<Snowflake, ApplicationCommandScope, ApplicationCommandResolvable> { + protected constructor(client: Client<true>, iterable?: Iterable<unknown>); + public permissions: ApplicationCommandPermissionsManager< + { command?: ApplicationCommandResolvable } & PermissionsOptionsExtras, + { command: ApplicationCommandResolvable } & PermissionsOptionsExtras, + PermissionsGuildType, + null + >; + private commandPath({ id, guildId }: { id?: Snowflake; guildId?: Snowflake }): string; + public create(command: ApplicationCommandDataResolvable, guildId?: Snowflake): Promise<ApplicationCommandScope>; + public delete(command: ApplicationCommandResolvable, guildId?: Snowflake): Promise<ApplicationCommandScope | null>; + public edit( + command: ApplicationCommandResolvable, + data: Partial<ApplicationCommandDataResolvable>, + ): Promise<ApplicationCommandScope>; + public edit( + command: ApplicationCommandResolvable, + data: Partial<ApplicationCommandDataResolvable>, + guildId: Snowflake, + ): Promise<ApplicationCommand>; + public fetch( + id: Snowflake, + options: FetchApplicationCommandOptions & { guildId: Snowflake }, + ): Promise<ApplicationCommand>; + public fetch(options: FetchApplicationCommandOptions): Promise<Collection<string, ApplicationCommandScope>>; + public fetch(id: Snowflake, options?: FetchApplicationCommandOptions): Promise<ApplicationCommandScope>; + public fetch( + id?: Snowflake, + options?: FetchApplicationCommandOptions, + ): Promise<Collection<Snowflake, ApplicationCommandScope>>; + public set( + commands: readonly ApplicationCommandDataResolvable[], + ): Promise<Collection<Snowflake, ApplicationCommandScope>>; + public set( + commands: readonly ApplicationCommandDataResolvable[], + guildId: Snowflake, + ): Promise<Collection<Snowflake, ApplicationCommand>>; + private static transformCommand(command: ApplicationCommandDataResolvable): RESTPostAPIApplicationCommandsJSONBody; +} + +export class ApplicationCommandPermissionsManager< + BaseOptions, + FetchSingleOptions, + GuildType, + CommandIdType, +> extends BaseManager { + private constructor(manager: ApplicationCommandManager | GuildApplicationCommandManager | ApplicationCommand); + private manager: ApplicationCommandManager | GuildApplicationCommandManager | ApplicationCommand; + + public commandId: CommandIdType; + public guild: GuildType; + public guildId: Snowflake | null; + public add( + options: FetchSingleOptions & EditApplicationCommandPermissionsMixin, + ): Promise<ApplicationCommandPermissions[]>; + public has( + options: FetchSingleOptions & { + permissionId: ApplicationCommandPermissionIdResolvable; + permissionType?: ApplicationCommandPermissionType; + }, + ): Promise<boolean>; + public fetch(options: FetchSingleOptions): Promise<ApplicationCommandPermissions[]>; + public fetch(options: BaseOptions): Promise<Collection<Snowflake, ApplicationCommandPermissions[]>>; + public remove( + options: + | (FetchSingleOptions & { + token: string; + channels?: readonly (GuildChannelResolvable | ChannelPermissionConstant)[]; + roles?: readonly (RoleResolvable | RolePermissionConstant)[]; + users: readonly UserResolvable[]; + }) + | (FetchSingleOptions & { + token: string; + channels?: readonly (GuildChannelResolvable | ChannelPermissionConstant)[]; + roles: readonly (RoleResolvable | RolePermissionConstant)[]; + users?: readonly UserResolvable[]; + }) + | (FetchSingleOptions & { + token: string; + channels: readonly (GuildChannelResolvable | ChannelPermissionConstant)[]; + roles?: readonly (RoleResolvable | RolePermissionConstant)[]; + users?: readonly UserResolvable[]; + }), + ): Promise<ApplicationCommandPermissions[]>; + public set( + options: FetchSingleOptions & EditApplicationCommandPermissionsMixin, + ): Promise<ApplicationCommandPermissions[]>; + private permissionsPath(guildId: Snowflake, commandId?: Snowflake): string; +} + +export class AutoModerationRuleManager extends CachedManager< + Snowflake, + AutoModerationRule, + AutoModerationRuleResolvable +> { + private constructor(guild: Guild, iterable: unknown); + public guild: Guild; + public create(options: AutoModerationRuleCreateOptions): Promise<AutoModerationRule>; + public edit( + autoModerationRule: AutoModerationRuleResolvable, + options: AutoModerationRuleEditOptions, + ): Promise<AutoModerationRule>; + public fetch(options: AutoModerationRuleResolvable | FetchAutoModerationRuleOptions): Promise<AutoModerationRule>; + public fetch(options?: FetchAutoModerationRulesOptions): Promise<Collection<Snowflake, AutoModerationRule>>; + public delete(autoModerationRule: AutoModerationRuleResolvable, reason?: string): Promise<void>; +} + +export class BaseGuildEmojiManager extends CachedManager<Snowflake, GuildEmoji, EmojiResolvable> { + protected constructor(client: Client<true>, iterable?: Iterable<RawGuildEmojiData>); + public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null; +} + +export class CategoryChannelChildManager extends DataManager<Snowflake, CategoryChildChannel, GuildChannelResolvable> { + private constructor(channel: CategoryChannel); + + public channel: CategoryChannel; + public get guild(): Guild; + public create<T extends CategoryChannelType>( + options: CategoryCreateChannelOptions & { type: T }, + ): Promise<MappedChannelCategoryTypes[T]>; + public create(options: CategoryCreateChannelOptions): Promise<TextChannel>; +} + +export class ChannelManager extends CachedManager<Snowflake, Channel, ChannelResolvable> { + private constructor(client: Client<true>, iterable: Iterable<RawChannelData>); + public fetch(id: Snowflake, options?: FetchChannelOptions): Promise<Channel | null>; +} + +export type FetchGuildApplicationCommandFetchOptions = Omit<FetchApplicationCommandOptions, 'guildId'>; + +export class GuildApplicationCommandManager extends ApplicationCommandManager<ApplicationCommand, {}, Guild> { + private constructor(guild: Guild, iterable?: Iterable<RawApplicationCommandData>); + public guild: Guild; + public create(command: ApplicationCommandDataResolvable): Promise<ApplicationCommand>; + public delete(command: ApplicationCommandResolvable): Promise<ApplicationCommand | null>; + public edit( + command: ApplicationCommandResolvable, + data: Partial<ApplicationCommandDataResolvable>, + ): Promise<ApplicationCommand>; + public fetch(id: Snowflake, options?: FetchGuildApplicationCommandFetchOptions): Promise<ApplicationCommand>; + public fetch(options: FetchGuildApplicationCommandFetchOptions): Promise<Collection<Snowflake, ApplicationCommand>>; + public fetch( + id?: undefined, + options?: FetchGuildApplicationCommandFetchOptions, + ): Promise<Collection<Snowflake, ApplicationCommand>>; + public set(commands: ApplicationCommandDataResolvable[]): Promise<Collection<Snowflake, ApplicationCommand>>; +} + +export type MappedGuildChannelTypes = { + [ChannelType.GuildCategory]: CategoryChannel; +} & MappedChannelCategoryTypes; + +export type GuildChannelTypes = CategoryChannelType | ChannelType.GuildCategory; + +export class GuildChannelManager extends CachedManager<Snowflake, GuildBasedChannel, GuildChannelResolvable> { + private constructor(guild: Guild, iterable?: Iterable<RawGuildChannelData>); + public get channelCountWithoutThreads(): number; + public guild: Guild; + + public addFollower( + channel: NewsChannel | Snowflake, + targetChannel: TextChannelResolvable, + reason?: string, + ): Promise<Snowflake>; + public create<T extends GuildChannelTypes>( + options: GuildChannelCreateOptions & { type: T }, + ): Promise<MappedGuildChannelTypes[T]>; + public create(options: GuildChannelCreateOptions): Promise<TextChannel>; + public createWebhook(options: WebhookCreateOptions): Promise<Webhook>; + public edit(channel: GuildChannelResolvable, data: GuildChannelEditOptions): Promise<GuildChannel>; + public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<GuildBasedChannel | null>; + public fetch( + id?: undefined, + options?: BaseFetchOptions, + ): Promise<Collection<Snowflake, NonThreadGuildBasedChannel | null>>; + public fetchWebhooks(channel: GuildChannelResolvable): Promise<Collection<Snowflake, Webhook>>; + public setPosition( + channel: GuildChannelResolvable, + position: number, + options?: SetChannelPositionOptions, + ): Promise<GuildChannel>; + public setPositions(channelPositions: readonly ChannelPosition[]): Promise<Guild>; + public fetchActiveThreads(cache?: boolean): Promise<FetchedThreads>; + private rawFetchGuildActiveThreads(): Promise<RESTGetAPIGuildThreadsResult>; + public delete(channel: GuildChannelResolvable, reason?: string): Promise<void>; +} + +export class GuildEmojiManager extends BaseGuildEmojiManager { + private constructor(guild: Guild, iterable?: Iterable<RawGuildEmojiData>); + public guild: Guild; + public create(options: GuildEmojiCreateOptions): Promise<GuildEmoji>; + public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<GuildEmoji>; + public fetch(id?: undefined, options?: BaseFetchOptions): Promise<Collection<Snowflake, GuildEmoji>>; + public fetchAuthor(emoji: EmojiResolvable): Promise<User>; + public delete(emoji: EmojiResolvable, reason?: string): Promise<void>; + public edit(emoji: EmojiResolvable, options: GuildEmojiEditOptions): Promise<GuildEmoji>; +} + +export class GuildEmojiRoleManager extends DataManager<Snowflake, Role, RoleResolvable> { + private constructor(emoji: GuildEmoji); + public emoji: GuildEmoji; + public guild: Guild; + public add( + roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection<Snowflake, Role>, + ): Promise<GuildEmoji>; + public set(roles: readonly RoleResolvable[] | Collection<Snowflake, Role>): Promise<GuildEmoji>; + public remove( + roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection<Snowflake, Role>, + ): Promise<GuildEmoji>; +} + +export class GuildManager extends CachedManager<Snowflake, Guild, GuildResolvable> { + private constructor(client: Client<true>, iterable?: Iterable<RawGuildData>); + public create(options: GuildCreateOptions): Promise<Guild>; + public fetch(options: Snowflake | FetchGuildOptions): Promise<Guild>; + public fetch(options?: FetchGuildsOptions): Promise<Collection<Snowflake, OAuth2Guild>>; +} + +export interface AddOrRemoveGuildMemberRoleOptions { + user: GuildMemberResolvable; + role: RoleResolvable; + reason?: string; +} + +export class GuildMemberManager extends CachedManager<Snowflake, GuildMember, GuildMemberResolvable> { + private constructor(guild: Guild, iterable?: Iterable<RawGuildMemberData>); + public guild: Guild; + public get me(): GuildMember | null; + public add( + user: UserResolvable, + options: AddGuildMemberOptions & { fetchWhenExisting: false }, + ): Promise<GuildMember | null>; + public add(user: UserResolvable, options: AddGuildMemberOptions): Promise<GuildMember>; + public ban(user: UserResolvable, options?: BanOptions): Promise<GuildMember | User | Snowflake>; + public edit(user: UserResolvable, options: GuildMemberEditOptions): Promise<GuildMember>; + public fetch( + options: UserResolvable | FetchMemberOptions | (FetchMembersOptions & { user: UserResolvable }), + ): Promise<GuildMember>; + public fetch(options?: FetchMembersOptions): Promise<Collection<Snowflake, GuildMember>>; + public fetchMe(options?: BaseFetchOptions): Promise<GuildMember>; + public kick(user: UserResolvable, reason?: string): Promise<GuildMember | User | Snowflake>; + public list(options?: GuildListMembersOptions): Promise<Collection<Snowflake, GuildMember>>; + public prune(options: GuildPruneMembersOptions & { dry?: false; count: false }): Promise<null>; + public prune(options?: GuildPruneMembersOptions): Promise<number>; + public search(options: GuildSearchMembersOptions): Promise<Collection<Snowflake, GuildMember>>; + public unban(user: UserResolvable, reason?: string): Promise<User | null>; + public addRole(options: AddOrRemoveGuildMemberRoleOptions): Promise<GuildMember | User | Snowflake>; + public removeRole(options: AddOrRemoveGuildMemberRoleOptions): Promise<GuildMember | User | Snowflake>; +} + +export class GuildBanManager extends CachedManager<Snowflake, GuildBan, GuildBanResolvable> { + private constructor(guild: Guild, iterable?: Iterable<RawGuildBanData>); + public guild: Guild; + public create(user: UserResolvable, options?: BanOptions): Promise<GuildMember | User | Snowflake>; + public fetch(options: UserResolvable | FetchBanOptions): Promise<GuildBan>; + public fetch(options?: FetchBansOptions): Promise<Collection<Snowflake, GuildBan>>; + public remove(user: UserResolvable, reason?: string): Promise<User | null>; +} + +export class GuildInviteManager extends DataManager<string, Invite, InviteResolvable> { + private constructor(guild: Guild, iterable?: Iterable<RawInviteData>); + public guild: Guild; + public create(channel: GuildInvitableChannelResolvable, options?: InviteCreateOptions): Promise<Invite>; + public fetch(options: InviteResolvable | FetchInviteOptions): Promise<Invite>; + public fetch(options?: FetchInvitesOptions): Promise<Collection<string, Invite>>; + public delete(invite: InviteResolvable, reason?: string): Promise<Invite>; +} + +export class GuildScheduledEventManager extends CachedManager< + Snowflake, + GuildScheduledEvent, + GuildScheduledEventResolvable +> { + private constructor(guild: Guild, iterable?: Iterable<RawGuildScheduledEventData>); + public guild: Guild; + public create(options: GuildScheduledEventCreateOptions): Promise<GuildScheduledEvent>; + public fetch(): Promise<Collection<Snowflake, GuildScheduledEvent>>; + public fetch< + T extends GuildScheduledEventResolvable | FetchGuildScheduledEventOptions | FetchGuildScheduledEventsOptions, + >(options?: T): Promise<GuildScheduledEventManagerFetchResult<T>>; + public edit<S extends GuildScheduledEventStatus, T extends GuildScheduledEventSetStatusArg<S>>( + guildScheduledEvent: GuildScheduledEventResolvable, + options: GuildScheduledEventEditOptions<S, T>, + ): Promise<GuildScheduledEvent<T>>; + public delete(guildScheduledEvent: GuildScheduledEventResolvable): Promise<void>; + public fetchSubscribers<T extends FetchGuildScheduledEventSubscribersOptions>( + guildScheduledEvent: GuildScheduledEventResolvable, + options?: T, + ): Promise<GuildScheduledEventManagerFetchSubscribersResult<T>>; +} + +export class GuildStickerManager extends CachedManager<Snowflake, Sticker, StickerResolvable> { + private constructor(guild: Guild, iterable?: Iterable<RawStickerData>); + public guild: Guild; + public create(options: GuildStickerCreateOptions): Promise<Sticker>; + public edit(sticker: StickerResolvable, data?: GuildStickerEditOptions): Promise<Sticker>; + public delete(sticker: StickerResolvable, reason?: string): Promise<void>; + public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<Sticker>; + public fetch(id?: Snowflake, options?: BaseFetchOptions): Promise<Collection<Snowflake, Sticker>>; + public fetchUser(sticker: StickerResolvable): Promise<User | null>; +} + +export class GuildMemberRoleManager extends DataManager<Snowflake, Role, RoleResolvable> { + private constructor(member: GuildMember); + public get hoist(): Role | null; + public get icon(): Role | null; + public get color(): Role | null; + public get highest(): Role; + public get premiumSubscriberRole(): Role | null; + public get botRole(): Role | null; + public member: GuildMember; + public guild: Guild; + + public add( + roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection<Snowflake, Role>, + reason?: string, + ): Promise<GuildMember>; + public set(roles: readonly RoleResolvable[] | Collection<Snowflake, Role>, reason?: string): Promise<GuildMember>; + public remove( + roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection<Snowflake, Role>, + reason?: string, + ): Promise<GuildMember>; +} + +export abstract class MessageManager<InGuild extends boolean = boolean> extends CachedManager< + Snowflake, + Message<InGuild>, + MessageResolvable +> { + protected constructor(channel: TextBasedChannel, iterable?: Iterable<RawMessageData>); + public channel: TextBasedChannel; + public delete(message: MessageResolvable): Promise<void>; + public edit( + message: MessageResolvable, + options: string | MessagePayload | MessageEditOptions, + ): Promise<Message<InGuild>>; + public fetch(options: MessageResolvable | FetchMessageOptions): Promise<Message<InGuild>>; + public fetch(options?: FetchMessagesOptions): Promise<Collection<Snowflake, Message<InGuild>>>; + public fetchPinned(cache?: boolean): Promise<Collection<Snowflake, Message<InGuild>>>; + public react(message: MessageResolvable, emoji: EmojiIdentifierResolvable): Promise<void>; + public pin(message: MessageResolvable, reason?: string): Promise<void>; + public unpin(message: MessageResolvable, reason?: string): Promise<void>; +} + +export class DMMessageManager extends MessageManager { + public channel: DMChannel; +} + +export class GuildMessageManager extends MessageManager<true> { + public channel: GuildTextBasedChannel; + public crosspost(message: MessageResolvable): Promise<Message<true>>; +} + +export class PermissionOverwriteManager extends CachedManager< + Snowflake, + PermissionOverwrites, + PermissionOverwriteResolvable +> { + private constructor(client: Client<true>, iterable?: Iterable<RawPermissionOverwriteData>); + public set( + overwrites: readonly OverwriteResolvable[] | Collection<Snowflake, OverwriteResolvable>, + reason?: string, + ): Promise<NonThreadGuildBasedChannel>; + private upsert( + userOrRole: RoleResolvable | UserResolvable, + options: PermissionOverwriteOptions, + overwriteOptions?: GuildChannelOverwriteOptions, + existing?: PermissionOverwrites, + ): Promise<NonThreadGuildBasedChannel>; + public create( + userOrRole: RoleResolvable | UserResolvable, + options: PermissionOverwriteOptions, + overwriteOptions?: GuildChannelOverwriteOptions, + ): Promise<NonThreadGuildBasedChannel>; + public edit( + userOrRole: RoleResolvable | UserResolvable, + options: PermissionOverwriteOptions, + overwriteOptions?: GuildChannelOverwriteOptions, + ): Promise<NonThreadGuildBasedChannel>; + public delete(userOrRole: RoleResolvable | UserResolvable, reason?: string): Promise<NonThreadGuildBasedChannel>; +} + +export class PresenceManager extends CachedManager<Snowflake, Presence, PresenceResolvable> { + private constructor(client: Client<true>, iterable?: Iterable<RawPresenceData>); +} + +export class ReactionManager extends CachedManager<Snowflake | string, MessageReaction, MessageReactionResolvable> { + private constructor(message: Message, iterable?: Iterable<RawMessageReactionData>); + public message: Message; + public removeAll(): Promise<Message>; +} + +export class ReactionUserManager extends CachedManager<Snowflake, User, UserResolvable> { + private constructor(reaction: MessageReaction, iterable?: Iterable<RawUserData>); + public reaction: MessageReaction; + public fetch(options?: FetchReactionUsersOptions): Promise<Collection<Snowflake, User>>; + public remove(user?: UserResolvable): Promise<MessageReaction>; +} + +export class RoleManager extends CachedManager<Snowflake, Role, RoleResolvable> { + private constructor(guild: Guild, iterable?: Iterable<RawRoleData>); + public get everyone(): Role; + public get highest(): Role; + public guild: Guild; + public get premiumSubscriberRole(): Role | null; + public botRoleFor(user: UserResolvable): Role | null; + public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<Role | null>; + public fetch(id?: undefined, options?: BaseFetchOptions): Promise<Collection<Snowflake, Role>>; + public create(options?: RoleCreateOptions): Promise<Role>; + public edit(role: RoleResolvable, options: RoleEditOptions): Promise<Role>; + public delete(role: RoleResolvable, reason?: string): Promise<void>; + public setPosition(role: RoleResolvable, position: number, options?: SetRolePositionOptions): Promise<Role>; + public setPositions(rolePositions: readonly RolePosition[]): Promise<Guild>; + public comparePositions(role1: RoleResolvable, role2: RoleResolvable): number; +} + +export class StageInstanceManager extends CachedManager<Snowflake, StageInstance, StageInstanceResolvable> { + private constructor(guild: Guild, iterable?: Iterable<RawStageInstanceData>); + public guild: Guild; + public create(channel: StageChannelResolvable, options: StageInstanceCreateOptions): Promise<StageInstance>; + public fetch(channel: StageChannelResolvable, options?: BaseFetchOptions): Promise<StageInstance>; + public edit(channel: StageChannelResolvable, options: StageInstanceEditOptions): Promise<StageInstance>; + public delete(channel: StageChannelResolvable): Promise<void>; +} + +export class ThreadManager<Forum extends boolean = boolean> extends CachedManager< + Snowflake, + ThreadChannel<Forum>, + ThreadChannelResolvable +> { + protected constructor(channel: TextChannel | NewsChannel | ForumChannel, iterable?: Iterable<RawThreadChannelData>); + public channel: If<Forum, ForumChannel, TextChannel | NewsChannel>; + public fetch(options: ThreadChannelResolvable, cacheOptions?: BaseFetchOptions): Promise<AnyThreadChannel | null>; + public fetch( + options: FetchThreadsOptions & { archived: FetchArchivedThreadOptions }, + cacheOptions?: { cache?: boolean }, + ): Promise<FetchedThreadsMore>; + public fetch(options?: FetchThreadsOptions, cacheOptions?: { cache?: boolean }): Promise<FetchedThreads>; + public fetchArchived(options?: FetchArchivedThreadOptions, cache?: boolean): Promise<FetchedThreadsMore>; + public fetchActive(cache?: boolean): Promise<FetchedThreads>; +} + +export class GuildTextThreadManager<AllowedThreadType> extends ThreadManager<false> { + public create(options: GuildTextThreadCreateOptions<AllowedThreadType>): Promise<ThreadChannel>; +} + +export class GuildForumThreadManager extends ThreadManager<true> { + public create(options: GuildForumThreadCreateOptions): Promise<ThreadChannel>; +} + +export class ThreadMemberManager extends CachedManager<Snowflake, ThreadMember, ThreadMemberResolvable> { + private constructor(thread: ThreadChannel, iterable?: Iterable<RawThreadMemberData>); + public thread: AnyThreadChannel; + public get me(): ThreadMember | null; + public add(member: UserResolvable | '@me', reason?: string): Promise<Snowflake>; + + public fetch( + options: ThreadMember<true> | ((FetchThreadMemberOptions & { withMember: true }) | { member: ThreadMember<true> }), + ): Promise<ThreadMember<true>>; + + public fetch(options: ThreadMemberResolvable | FetchThreadMemberOptions): Promise<ThreadMember>; + + public fetch( + options: FetchThreadMembersWithGuildMemberDataOptions, + ): Promise<Collection<Snowflake, ThreadMember<true>>>; + + public fetch(options?: FetchThreadMembersWithoutGuildMemberDataOptions): Promise<Collection<Snowflake, ThreadMember>>; + public fetchMe(options?: BaseFetchOptions): Promise<ThreadMember>; + public remove(id: Snowflake | '@me', reason?: string): Promise<Snowflake>; +} + +export class UserManager extends CachedManager<Snowflake, User, UserResolvable> { + private constructor(client: Client<true>, iterable?: Iterable<RawUserData>); + private dmChannel(userId: Snowflake): DMChannel | null; + public createDM(user: UserResolvable, options?: BaseFetchOptions): Promise<DMChannel>; + public deleteDM(user: UserResolvable): Promise<DMChannel>; + public fetch(user: UserResolvable, options?: BaseFetchOptions): Promise<User>; + public fetchFlags(user: UserResolvable, options?: BaseFetchOptions): Promise<UserFlagsBitField>; + public send(user: UserResolvable, options: string | MessagePayload | MessageCreateOptions): Promise<Message>; +} + +export class VoiceStateManager extends CachedManager<Snowflake, VoiceState, typeof VoiceState> { + private constructor(guild: Guild, iterable?: Iterable<RawVoiceStateData>); + public guild: Guild; +} + +//#endregion + +//#region Mixins + +// Model the TextBasedChannel mixin system, allowing application of these fields +// to the classes that use these methods without having to manually add them +// to each of those classes + +export type Constructable<T> = abstract new (...args: any[]) => T; +export function PartialTextBasedChannel<T>( + Base?: Constructable<T>, +): Constructable<T & PartialTextBasedChannelFields<false>>; + +export function TextBasedChannelMixin< + T, + InGuild extends boolean = boolean, + I extends keyof TextBasedChannelFields<InGuild> = never, +>( + Base?: Constructable<T>, + inGuild?: InGuild, + ignore?: I[], +): Constructable<T & Omit<TextBasedChannelFields<InGuild>, I>>; + +export interface PartialTextBasedChannelFields<InGuild extends boolean = boolean> { + send(options: string | MessagePayload | MessageCreateOptions): Promise<Message<InGuild>>; +} + +export interface TextBasedChannelFields<InGuild extends boolean = boolean> + extends PartialTextBasedChannelFields<InGuild> { + lastMessageId: Snowflake | null; + get lastMessage(): Message | null; + lastPinTimestamp: number | null; + get lastPinAt(): Date | null; + messages: If<InGuild, GuildMessageManager, DMMessageManager>; + awaitMessageComponent<T extends MessageComponentType>( + options?: AwaitMessageCollectorOptionsParams<T, true>, + ): Promise<MappedInteractionTypes[T]>; + awaitMessages(options?: AwaitMessagesOptions): Promise<Collection<Snowflake, Message>>; + bulkDelete( + messages: Collection<Snowflake, Message> | readonly MessageResolvable[] | number, + filterOld?: boolean, + ): Promise<Collection<Snowflake, Message | PartialMessage | undefined>>; + createMessageComponentCollector<T extends MessageComponentType>( + options?: MessageChannelCollectorOptionsParams<T, true>, + ): InteractionCollector<MappedInteractionTypes[T]>; + createMessageCollector(options?: MessageCollectorOptions): MessageCollector; + createWebhook(options: ChannelWebhookCreateOptions): Promise<Webhook>; + fetchWebhooks(): Promise<Collection<Snowflake, Webhook>>; + sendTyping(): Promise<void>; + setRateLimitPerUser(rateLimitPerUser: number, reason?: string): Promise<this>; + setNSFW(nsfw?: boolean, reason?: string): Promise<this>; +} + +export function PartialWebhookMixin<T>(Base?: Constructable<T>): Constructable<T & PartialWebhookFields>; +export function WebhookMixin<T>(Base?: Constructable<T>): Constructable<T & WebhookFields>; + +export interface PartialWebhookFields { + id: Snowflake; + get url(): string; + deleteMessage(message: MessageResolvable | APIMessage | '@original', threadId?: Snowflake): Promise<void>; + editMessage( + message: MessageResolvable | '@original', + options: string | MessagePayload | WebhookMessageEditOptions, + ): Promise<APIMessage | Message>; + fetchMessage(message: Snowflake | '@original', options?: WebhookFetchMessageOptions): Promise<APIMessage | Message>; + send( + options: string | MessagePayload | InteractionReplyOptions | WebhookMessageCreateOptions, + ): Promise<APIMessage | Message>; +} + +export interface WebhookFields extends PartialWebhookFields { + get createdAt(): Date; + get createdTimestamp(): number; + delete(reason?: string): Promise<void>; + edit(options: WebhookEditOptions): Promise<Webhook>; + sendSlackMessage(body: unknown): Promise<boolean>; +} + +//#endregion + +//#region Typedefs + +export type ActivitiesOptions = Omit<ActivityOptions, 'shardId'>; + +export interface ActivityOptions { + name: string; + state?: string; + url?: string; + type?: ActivityType; + shardId?: number | readonly number[]; +} + +export interface AddGuildMemberOptions { + accessToken: string; + nick?: string; + roles?: Collection<Snowflake, Role> | RoleResolvable[]; + mute?: boolean; + deaf?: boolean; + force?: boolean; + fetchWhenExisting?: boolean; +} + +export type AllowedPartial = User | Channel | GuildMember | Message | MessageReaction | ThreadMember; + +export type AllowedThreadTypeForNewsChannel = ChannelType.AnnouncementThread; + +export type AllowedThreadTypeForTextChannel = ChannelType.PublicThread | ChannelType.PrivateThread; + +export interface BaseApplicationCommandData { + name: string; + nameLocalizations?: LocalizationMap; + dmPermission?: boolean; + defaultMemberPermissions?: PermissionResolvable | null; + nsfw?: boolean; +} + +export interface AttachmentData { + name?: string; + description?: string; +} + +export type CommandOptionDataTypeResolvable = ApplicationCommandOptionType; + +export type CommandOptionChannelResolvableType = ApplicationCommandOptionType.Channel; + +export type CommandOptionChoiceResolvableType = + | ApplicationCommandOptionType.String + | CommandOptionNumericResolvableType; + +export type CommandOptionNumericResolvableType = + | ApplicationCommandOptionType.Number + | ApplicationCommandOptionType.Integer; + +export type CommandOptionSubOptionResolvableType = + | ApplicationCommandOptionType.Subcommand + | ApplicationCommandOptionType.SubcommandGroup; + +export type CommandOptionNonChoiceResolvableType = Exclude< + CommandOptionDataTypeResolvable, + CommandOptionChoiceResolvableType | CommandOptionSubOptionResolvableType | CommandOptionChannelResolvableType +>; + +export interface BaseApplicationCommandOptionsData { + name: string; + nameLocalizations?: LocalizationMap; + description: string; + descriptionLocalizations?: LocalizationMap; + required?: boolean; + autocomplete?: never; +} + +export interface UserApplicationCommandData extends BaseApplicationCommandData { + type: ApplicationCommandType.User; +} + +export interface MessageApplicationCommandData extends BaseApplicationCommandData { + type: ApplicationCommandType.Message; +} + +export interface ChatInputApplicationCommandData extends BaseApplicationCommandData { + description: string; + descriptionLocalizations?: LocalizationMap; + type?: ApplicationCommandType.ChatInput; + options?: readonly ApplicationCommandOptionData[]; +} + +export type ApplicationCommandData = + | UserApplicationCommandData + | MessageApplicationCommandData + | ChatInputApplicationCommandData; + +export interface ApplicationCommandChannelOptionData extends BaseApplicationCommandOptionsData { + type: CommandOptionChannelResolvableType; + channelTypes?: readonly ApplicationCommandOptionAllowedChannelTypes[]; + channel_types?: readonly ApplicationCommandOptionAllowedChannelTypes[]; +} + +export interface ApplicationCommandChannelOption extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.Channel; + channelTypes?: readonly ApplicationCommandOptionAllowedChannelTypes[]; +} + +export interface ApplicationCommandRoleOptionData extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.Role; +} + +export interface ApplicationCommandRoleOption extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.Role; +} + +export interface ApplicationCommandUserOptionData extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.User; +} + +export interface ApplicationCommandUserOption extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.User; +} + +export interface ApplicationCommandMentionableOptionData extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.Mentionable; +} + +export interface ApplicationCommandMentionableOption extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.Mentionable; +} + +export interface ApplicationCommandAttachmentOption extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.Attachment; +} + +export interface ApplicationCommandAutocompleteNumericOption + extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> { + type: CommandOptionNumericResolvableType; + minValue?: number; + maxValue?: number; + autocomplete: true; +} + +export interface ApplicationCommandAutocompleteStringOption + extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> { + type: ApplicationCommandOptionType.String; + minLength?: number; + maxLength?: number; + autocomplete: true; +} + +export interface ApplicationCommandAutocompleteNumericOptionData + extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> { + type: CommandOptionNumericResolvableType; + minValue?: number; + min_value?: number; + maxValue?: number; + max_value?: number; + autocomplete: true; +} + +export interface ApplicationCommandAutocompleteStringOptionData + extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> { + type: ApplicationCommandOptionType.String; + minLength?: number; + min_length?: number; + maxLength?: number; + max_length?: number; + autocomplete: true; +} + +export interface ApplicationCommandChoicesData<Type extends string | number = string | number> + extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> { + type: CommandOptionChoiceResolvableType; + choices?: readonly ApplicationCommandOptionChoiceData<Type>[]; + autocomplete?: false; +} + +export interface ApplicationCommandChoicesOption<Type extends string | number = string | number> + extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> { + type: CommandOptionChoiceResolvableType; + choices?: readonly ApplicationCommandOptionChoiceData<Type>[]; + autocomplete?: false; +} + +export interface ApplicationCommandNumericOptionData extends ApplicationCommandChoicesData<number> { + type: CommandOptionNumericResolvableType; + minValue?: number; + min_value?: number; + maxValue?: number; + max_value?: number; +} + +export interface ApplicationCommandStringOptionData extends ApplicationCommandChoicesData<string> { + type: ApplicationCommandOptionType.String; + minLength?: number; + min_length?: number; + maxLength?: number; + max_length?: number; +} + +export interface ApplicationCommandBooleanOptionData extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.Boolean; +} + +export interface ApplicationCommandNumericOption extends ApplicationCommandChoicesOption<number> { + type: CommandOptionNumericResolvableType; + minValue?: number; + maxValue?: number; +} + +export interface ApplicationCommandStringOption extends ApplicationCommandChoicesOption<string> { + type: ApplicationCommandOptionType.String; + minLength?: number; + maxLength?: number; +} + +export interface ApplicationCommandBooleanOption extends BaseApplicationCommandOptionsData { + type: ApplicationCommandOptionType.Boolean; +} + +export interface ApplicationCommandSubGroupData extends Omit<BaseApplicationCommandOptionsData, 'required'> { + type: ApplicationCommandOptionType.SubcommandGroup; + options: readonly ApplicationCommandSubCommandData[]; +} + +export interface ApplicationCommandSubGroup extends Omit<BaseApplicationCommandOptionsData, 'required'> { + type: ApplicationCommandOptionType.SubcommandGroup; + options?: readonly ApplicationCommandSubCommand[]; +} + +export interface ApplicationCommandSubCommandData extends Omit<BaseApplicationCommandOptionsData, 'required'> { + type: ApplicationCommandOptionType.Subcommand; + options?: readonly Exclude< + ApplicationCommandOptionData, + ApplicationCommandSubGroupData | ApplicationCommandSubCommandData + >[]; +} + +export interface ApplicationCommandSubCommand extends Omit<BaseApplicationCommandOptionsData, 'required'> { + type: ApplicationCommandOptionType.Subcommand; + options?: readonly Exclude<ApplicationCommandOption, ApplicationCommandSubGroup | ApplicationCommandSubCommand>[]; +} + +export interface ApplicationCommandNonOptionsData extends BaseApplicationCommandOptionsData { + type: CommandOptionNonChoiceResolvableType; +} + +export interface ApplicationCommandNonOptions extends BaseApplicationCommandOptionsData { + type: Exclude<CommandOptionNonChoiceResolvableType, ApplicationCommandOptionType>; +} + +export type ApplicationCommandOptionData = + | ApplicationCommandSubGroupData + | ApplicationCommandNonOptionsData + | ApplicationCommandChannelOptionData + | ApplicationCommandAutocompleteNumericOptionData + | ApplicationCommandAutocompleteStringOptionData + | ApplicationCommandNumericOptionData + | ApplicationCommandStringOptionData + | ApplicationCommandRoleOptionData + | ApplicationCommandUserOptionData + | ApplicationCommandMentionableOptionData + | ApplicationCommandBooleanOptionData + | ApplicationCommandSubCommandData; + +export type ApplicationCommandOption = + | ApplicationCommandSubGroup + | ApplicationCommandAutocompleteNumericOption + | ApplicationCommandAutocompleteStringOption + | ApplicationCommandNonOptions + | ApplicationCommandChannelOption + | ApplicationCommandNumericOption + | ApplicationCommandStringOption + | ApplicationCommandRoleOption + | ApplicationCommandUserOption + | ApplicationCommandMentionableOption + | ApplicationCommandBooleanOption + | ApplicationCommandAttachmentOption + | ApplicationCommandSubCommand; + +export interface ApplicationCommandOptionChoiceData<Value extends string | number = string | number> { + name: string; + nameLocalizations?: LocalizationMap; + value: Value; +} + +export interface ApplicationCommandPermissions { + id: Snowflake; + type: ApplicationCommandPermissionType; + permission: boolean; +} + +export interface ApplicationCommandPermissionsUpdateData { + id: Snowflake; + guildId: Snowflake; + applicationId: Snowflake; + permissions: readonly ApplicationCommandPermissions[]; +} + +export interface EditApplicationCommandPermissionsMixin { + permissions: readonly ApplicationCommandPermissions[]; + token: string; +} + +export type ChannelPermissionConstant = Snowflake; + +export type RolePermissionConstant = Snowflake; + +export type ApplicationCommandPermissionIdResolvable = + | GuildChannelResolvable + | RoleResolvable + | UserResolvable + | ChannelPermissionConstant + | RolePermissionConstant; + +export type ApplicationCommandResolvable = ApplicationCommand | Snowflake; + +export type ApplicationFlagsString = keyof typeof ApplicationFlags; + +export interface ApplicationRoleConnectionMetadataEditOptions { + name: string; + nameLocalizations?: LocalizationMap | null; + description: string; + descriptionLocalizations?: LocalizationMap | null; + key: string; + type: ApplicationRoleConnectionMetadataType; +} + +export interface AuditLogChange { + key: APIAuditLogChange['key']; + old?: APIAuditLogChange['old_value']; + new?: APIAuditLogChange['new_value']; +} + +export interface AutoModerationAction { + type: AutoModerationActionType; + metadata: AutoModerationActionMetadata; +} + +export interface AutoModerationActionMetadata { + channelId: Snowflake | null; + durationSeconds: number | null; + customMessage: string | null; +} + +export interface AutoModerationTriggerMetadata { + keywordFilter: string[]; + regexPatterns: string[]; + presets: AutoModerationRuleKeywordPresetType[]; + allowList: string[]; + mentionTotalLimit: number | null; + mentionRaidProtectionEnabled: boolean; +} + +export type AwaitMessageComponentOptions<T extends CollectedMessageInteraction> = Omit< + MessageComponentCollectorOptions<T>, + 'max' | 'maxComponents' | 'maxUsers' +>; + +export type ModalSubmitInteractionCollectorOptions<T extends ModalSubmitInteraction> = Omit< + InteractionCollectorOptions<T>, + 'channel' | 'message' | 'guild' | 'interactionType' +>; + +export type AwaitModalSubmitOptions<T extends ModalSubmitInteraction> = Omit< + ModalSubmitInteractionCollectorOptions<T>, + 'max' | 'maxComponents' | 'maxUsers' +> & { + time: number; +}; + +export interface AwaitMessagesOptions extends MessageCollectorOptions { + errors?: string[]; +} + +export interface AwaitReactionsOptions extends ReactionCollectorOptions { + errors?: string[]; +} + +export interface BanOptions { + /** @deprecated Use {@link deleteMessageSeconds} instead. */ + deleteMessageDays?: number; + deleteMessageSeconds?: number; + reason?: string; +} + +export type Base64Resolvable = Buffer | Base64String; + +export type Base64String = string; + +export interface BaseFetchOptions { + cache?: boolean; + force?: boolean; +} + +export type BitFieldResolvable<T extends string, N extends number | bigint> = + | RecursiveReadonlyArray<T | N | `${bigint}` | Readonly<BitField<T, N>>> + | T + | N + | `${bigint}` + | Readonly<BitField<T, N>>; + +export type BufferResolvable = Buffer | string; + +export interface Caches { + AutoModerationRuleManager: [manager: typeof AutoModerationRuleManager, holds: typeof AutoModerationRule]; + ApplicationCommandManager: [manager: typeof ApplicationCommandManager, holds: typeof ApplicationCommand]; + BaseGuildEmojiManager: [manager: typeof BaseGuildEmojiManager, holds: typeof GuildEmoji]; + DMMessageManager: [manager: typeof MessageManager, holds: typeof Message<false>]; + GuildEmojiManager: [manager: typeof GuildEmojiManager, holds: typeof GuildEmoji]; + // TODO: ChannelManager: [manager: typeof ChannelManager, holds: typeof Channel]; + // TODO: GuildChannelManager: [manager: typeof GuildChannelManager, holds: typeof GuildChannel]; + // TODO: GuildManager: [manager: typeof GuildManager, holds: typeof Guild]; + GuildMemberManager: [manager: typeof GuildMemberManager, holds: typeof GuildMember]; + GuildBanManager: [manager: typeof GuildBanManager, holds: typeof GuildBan]; + GuildForumThreadManager: [manager: typeof GuildForumThreadManager, holds: typeof ThreadChannel<true>]; + GuildInviteManager: [manager: typeof GuildInviteManager, holds: typeof Invite]; + GuildMessageManager: [manager: typeof GuildMessageManager, holds: typeof Message<true>]; + GuildScheduledEventManager: [manager: typeof GuildScheduledEventManager, holds: typeof GuildScheduledEvent]; + GuildStickerManager: [manager: typeof GuildStickerManager, holds: typeof Sticker]; + GuildTextThreadManager: [manager: typeof GuildTextThreadManager, holds: typeof ThreadChannel<false>]; + MessageManager: [manager: typeof MessageManager, holds: typeof Message]; + // TODO: PermissionOverwriteManager: [manager: typeof PermissionOverwriteManager, holds: typeof PermissionOverwrites]; + PresenceManager: [manager: typeof PresenceManager, holds: typeof Presence]; + ReactionManager: [manager: typeof ReactionManager, holds: typeof MessageReaction]; + ReactionUserManager: [manager: typeof ReactionUserManager, holds: typeof User]; + // TODO: RoleManager: [manager: typeof RoleManager, holds: typeof Role]; + StageInstanceManager: [manager: typeof StageInstanceManager, holds: typeof StageInstance]; + ThreadManager: [manager: typeof ThreadManager, holds: typeof ThreadChannel]; + ThreadMemberManager: [manager: typeof ThreadMemberManager, holds: typeof ThreadMember]; + UserManager: [manager: typeof UserManager, holds: typeof User]; + VoiceStateManager: [manager: typeof VoiceStateManager, holds: typeof VoiceState]; +} + +export type CacheConstructors = { + [K in keyof Caches]: Caches[K][0] & { name: K }; +}; + +type OverriddenCaches = + | 'DMMessageManager' + | 'GuildForumThreadManager' + | 'GuildMessageManager' + | 'GuildTextThreadManager'; + +// This doesn't actually work the way it looks 😢. +// Narrowing the type of `manager.name` doesn't propagate type information to `holds` and the return type. +export type CacheFactory = ( + managerType: CacheConstructors[Exclude<keyof Caches, OverriddenCaches>], + holds: Caches[(typeof manager)['name']][1], + manager: CacheConstructors[keyof Caches], +) => (typeof manager)['prototype'] extends DataManager<infer K, infer V, any> ? Collection<K, V> : never; + +export type CacheWithLimitsOptions = { + [K in keyof Caches]?: Caches[K][0]['prototype'] extends DataManager<infer K, infer V, any> + ? LimitedCollectionOptions<K, V> | number + : never; +}; + +export interface CategoryCreateChannelOptions { + name: string; + permissionOverwrites?: OverwriteResolvable[] | Collection<Snowflake, OverwriteResolvable>; + topic?: string; + type?: CategoryChannelType; + nsfw?: boolean; + bitrate?: number; + userLimit?: number; + rateLimitPerUser?: number; + position?: number; + rtcRegion?: string; + videoQualityMode?: VideoQualityMode; + availableTags?: GuildForumTagData[]; + defaultReactionEmoji?: DefaultReactionEmoji; + defaultAutoArchiveDuration?: ThreadAutoArchiveDuration; + defaultSortOrder?: SortOrderType; + defaultForumLayout?: ForumLayoutType; + reason?: string; +} + +export interface ChannelCreationOverwrites { + allow?: PermissionResolvable; + deny?: PermissionResolvable; + id: RoleResolvable | UserResolvable; +} + +export type ChannelMention = `<#${Snowflake}>`; + +export interface ChannelPosition { + channel: NonThreadGuildBasedChannel | Snowflake; + lockPermissions?: boolean; + parent?: CategoryChannelResolvable | null; + position?: number; +} + +export type GuildTextChannelResolvable = TextChannel | NewsChannel | Snowflake; +export type ChannelResolvable = Channel | Snowflake; + +export interface ChannelWebhookCreateOptions { + name: string; + avatar?: BufferResolvable | Base64Resolvable | null; + reason?: string; +} + +export interface WebhookCreateOptions extends ChannelWebhookCreateOptions { + channel: TextChannel | NewsChannel | VoiceChannel | StageChannel | ForumChannel | Snowflake; +} + +export interface ClientEvents { + applicationCommandPermissionsUpdate: [data: ApplicationCommandPermissionsUpdateData]; + autoModerationActionExecution: [autoModerationActionExecution: AutoModerationActionExecution]; + autoModerationRuleCreate: [autoModerationRule: AutoModerationRule]; + autoModerationRuleDelete: [autoModerationRule: AutoModerationRule]; + autoModerationRuleUpdate: [ + oldAutoModerationRule: AutoModerationRule | null, + newAutoModerationRule: AutoModerationRule, + ]; + cacheSweep: [message: string]; + channelCreate: [channel: NonThreadGuildBasedChannel]; + channelDelete: [channel: DMChannel | NonThreadGuildBasedChannel]; + channelPinsUpdate: [channel: TextBasedChannel, date: Date]; + channelUpdate: [ + oldChannel: DMChannel | NonThreadGuildBasedChannel, + newChannel: DMChannel | NonThreadGuildBasedChannel, + ]; + debug: [message: string]; + warn: [message: string]; + emojiCreate: [emoji: GuildEmoji]; + emojiDelete: [emoji: GuildEmoji]; + emojiUpdate: [oldEmoji: GuildEmoji, newEmoji: GuildEmoji]; + error: [error: Error]; + guildAuditLogEntryCreate: [auditLogEntry: GuildAuditLogsEntry, guild: Guild]; + guildAvailable: [guild: Guild]; + guildBanAdd: [ban: GuildBan]; + guildBanRemove: [ban: GuildBan]; + guildCreate: [guild: Guild]; + guildDelete: [guild: Guild]; + guildUnavailable: [guild: Guild]; + guildIntegrationsUpdate: [guild: Guild]; + guildMemberAdd: [member: GuildMember]; + guildMemberAvailable: [member: GuildMember | PartialGuildMember]; + guildMemberRemove: [member: GuildMember | PartialGuildMember]; + guildMembersChunk: [ + members: Collection<Snowflake, GuildMember>, + guild: Guild, + data: { index: number; count: number; notFound: unknown[]; nonce: string | undefined }, + ]; + guildMemberUpdate: [oldMember: GuildMember | PartialGuildMember, newMember: GuildMember]; + guildUpdate: [oldGuild: Guild, newGuild: Guild]; + inviteCreate: [invite: Invite]; + inviteDelete: [invite: Invite]; + messageCreate: [message: Message]; + messageDelete: [message: Message | PartialMessage]; + messageReactionRemoveAll: [ + message: Message | PartialMessage, + reactions: Collection<string | Snowflake, MessageReaction>, + ]; + messageReactionRemoveEmoji: [reaction: MessageReaction | PartialMessageReaction]; + messageDeleteBulk: [messages: Collection<Snowflake, Message | PartialMessage>, channel: GuildTextBasedChannel]; + messageReactionAdd: [reaction: MessageReaction | PartialMessageReaction, user: User | PartialUser]; + messageReactionRemove: [reaction: MessageReaction | PartialMessageReaction, user: User | PartialUser]; + messageUpdate: [oldMessage: Message | PartialMessage, newMessage: Message | PartialMessage]; + presenceUpdate: [oldPresence: Presence | null, newPresence: Presence]; + ready: [client: Client<true>]; + invalidated: []; + roleCreate: [role: Role]; + roleDelete: [role: Role]; + roleUpdate: [oldRole: Role, newRole: Role]; + threadCreate: [thread: AnyThreadChannel, newlyCreated: boolean]; + threadDelete: [thread: AnyThreadChannel]; + threadListSync: [threads: Collection<Snowflake, AnyThreadChannel>, guild: Guild]; + threadMemberUpdate: [oldMember: ThreadMember, newMember: ThreadMember]; + threadMembersUpdate: [ + addedMembers: Collection<Snowflake, ThreadMember>, + removedMembers: Collection<Snowflake, ThreadMember | PartialThreadMember>, + thread: AnyThreadChannel, + ]; + threadUpdate: [oldThread: AnyThreadChannel, newThread: AnyThreadChannel]; + typingStart: [typing: Typing]; + userUpdate: [oldUser: User | PartialUser, newUser: User]; + voiceStateUpdate: [oldState: VoiceState, newState: VoiceState]; + /** @deprecated Use {@link webhooksUpdate} instead. */ + webhookUpdate: ClientEvents['webhooksUpdate']; + webhooksUpdate: [channel: TextChannel | NewsChannel | VoiceChannel | ForumChannel]; + interactionCreate: [interaction: Interaction]; + shardDisconnect: [closeEvent: CloseEvent, shardId: number]; + shardError: [error: Error, shardId: number]; + shardReady: [shardId: number, unavailableGuilds: Set<Snowflake> | undefined]; + shardReconnecting: [shardId: number]; + shardResume: [shardId: number, replayedEvents: number]; + stageInstanceCreate: [stageInstance: StageInstance]; + stageInstanceUpdate: [oldStageInstance: StageInstance | null, newStageInstance: StageInstance]; + stageInstanceDelete: [stageInstance: StageInstance]; + stickerCreate: [sticker: Sticker]; + stickerDelete: [sticker: Sticker]; + stickerUpdate: [oldSticker: Sticker, newSticker: Sticker]; + guildScheduledEventCreate: [guildScheduledEvent: GuildScheduledEvent]; + guildScheduledEventUpdate: [ + oldGuildScheduledEvent: GuildScheduledEvent | null, + newGuildScheduledEvent: GuildScheduledEvent, + ]; + guildScheduledEventDelete: [guildScheduledEvent: GuildScheduledEvent]; + guildScheduledEventUserAdd: [guildScheduledEvent: GuildScheduledEvent, user: User]; + guildScheduledEventUserRemove: [guildScheduledEvent: GuildScheduledEvent, user: User]; +} + +export interface ClientFetchInviteOptions { + guildScheduledEventId?: Snowflake; +} + +export interface ClientOptions { + shards?: number | number[] | 'auto'; + shardCount?: number; + closeTimeout?: number; + makeCache?: CacheFactory; + allowedMentions?: MessageMentionOptions; + partials?: Partials[]; + failIfNotExists?: boolean; + presence?: PresenceData; + intents: BitFieldResolvable<GatewayIntentsString, number>; + waitGuildTimeout?: number; + sweepers?: SweeperOptions; + ws?: WebSocketOptions; + rest?: Partial<RESTOptions>; + jsonTransformer?: (obj: unknown) => unknown; +} + +export type ClientPresenceStatus = 'online' | 'idle' | 'dnd'; + +export interface ClientPresenceStatusData { + web?: ClientPresenceStatus; + mobile?: ClientPresenceStatus; + desktop?: ClientPresenceStatus; +} + +export interface ClientUserEditOptions { + username?: string; + avatar?: BufferResolvable | Base64Resolvable | null; +} + +export interface CloseEvent { + /** @deprecated */ + wasClean: boolean; + code: number; + /** @deprecated */ + reason: string; +} + +export type CollectorFilter<T extends unknown[]> = (...args: T) => boolean | Promise<boolean>; + +export interface CollectorOptions<T extends unknown[]> { + filter?: CollectorFilter<T>; + time?: number; + idle?: number; + dispose?: boolean; +} + +export interface CollectorResetTimerOptions { + time?: number; + idle?: number; +} + +export type ColorResolvable = + | keyof typeof Colors + | 'Random' + | readonly [red: number, green: number, blue: number] + | number + | HexColorString; + +export interface CommandInteractionOption<Cached extends CacheType = CacheType> { + name: string; + type: ApplicationCommandOptionType; + value?: string | number | boolean; + focused?: boolean; + autocomplete?: boolean; + options?: CommandInteractionOption[]; + user?: User; + member?: CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>; + channel?: CacheTypeReducer<Cached, GuildBasedChannel, APIInteractionDataResolvedChannel>; + role?: CacheTypeReducer<Cached, Role, APIRole>; + attachment?: Attachment; + message?: Message<BooleanCache<Cached>>; +} + +export interface CommandInteractionResolvedData<Cached extends CacheType = CacheType> { + users?: Collection<Snowflake, User>; + members?: Collection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>; + roles?: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>; + channels?: Collection<Snowflake, CacheTypeReducer<Cached, Channel, APIInteractionDataResolvedChannel>>; + messages?: Collection<Snowflake, CacheTypeReducer<Cached, Message, APIMessage>>; + attachments?: Collection<Snowflake, Attachment>; +} + +export type AutocompleteFocusedOption = Pick<CommandInteractionOption, 'name'> & { + focused: true; + type: + | ApplicationCommandOptionType.String + | ApplicationCommandOptionType.Integer + | ApplicationCommandOptionType.Number; + value: string; +}; + +export declare const Colors: { + Default: 0x000000; + White: 0xffffff; + Aqua: 0x1abc9c; + Green: 0x57f287; + Blue: 0x3498db; + Yellow: 0xfee75c; + Purple: 0x9b59b6; + LuminousVividPink: 0xe91e63; + Fuchsia: 0xeb459e; + Gold: 0xf1c40f; + Orange: 0xe67e22; + Red: 0xed4245; + Grey: 0x95a5a6; + Navy: 0x34495e; + DarkAqua: 0x11806a; + DarkGreen: 0x1f8b4c; + DarkBlue: 0x206694; + DarkPurple: 0x71368a; + DarkVividPink: 0xad1457; + DarkGold: 0xc27c0e; + DarkOrange: 0xa84300; + DarkRed: 0x992d22; + DarkGrey: 0x979c9f; + DarkerGrey: 0x7f8c8d; + LightGrey: 0xbcc0c0; + DarkNavy: 0x2c3e50; + Blurple: 0x5865f2; + Greyple: 0x99aab5; + DarkButNotBlack: 0x2c2f33; + NotQuiteBlack: 0x23272a; +}; + +export enum Events { + ApplicationCommandPermissionsUpdate = 'applicationCommandPermissionsUpdate', + AutoModerationActionExecution = 'autoModerationActionExecution', + AutoModerationRuleCreate = 'autoModerationRuleCreate', + AutoModerationRuleDelete = 'autoModerationRuleDelete', + AutoModerationRuleUpdate = 'autoModerationRuleUpdate', + ClientReady = 'ready', + GuildAuditLogEntryCreate = 'guildAuditLogEntryCreate', + GuildAvailable = 'guildAvailable', + GuildCreate = 'guildCreate', + GuildDelete = 'guildDelete', + GuildUpdate = 'guildUpdate', + GuildUnavailable = 'guildUnavailable', + GuildMemberAdd = 'guildMemberAdd', + GuildMemberRemove = 'guildMemberRemove', + GuildMemberUpdate = 'guildMemberUpdate', + GuildMemberAvailable = 'guildMemberAvailable', + GuildMembersChunk = 'guildMembersChunk', + GuildIntegrationsUpdate = 'guildIntegrationsUpdate', + GuildRoleCreate = 'roleCreate', + GuildRoleDelete = 'roleDelete', + InviteCreate = 'inviteCreate', + InviteDelete = 'inviteDelete', + GuildRoleUpdate = 'roleUpdate', + GuildEmojiCreate = 'emojiCreate', + GuildEmojiDelete = 'emojiDelete', + GuildEmojiUpdate = 'emojiUpdate', + GuildBanAdd = 'guildBanAdd', + GuildBanRemove = 'guildBanRemove', + ChannelCreate = 'channelCreate', + ChannelDelete = 'channelDelete', + ChannelUpdate = 'channelUpdate', + ChannelPinsUpdate = 'channelPinsUpdate', + MessageCreate = 'messageCreate', + MessageDelete = 'messageDelete', + MessageUpdate = 'messageUpdate', + MessageBulkDelete = 'messageDeleteBulk', + MessageReactionAdd = 'messageReactionAdd', + MessageReactionRemove = 'messageReactionRemove', + MessageReactionRemoveAll = 'messageReactionRemoveAll', + MessageReactionRemoveEmoji = 'messageReactionRemoveEmoji', + ThreadCreate = 'threadCreate', + ThreadDelete = 'threadDelete', + ThreadUpdate = 'threadUpdate', + ThreadListSync = 'threadListSync', + ThreadMemberUpdate = 'threadMemberUpdate', + ThreadMembersUpdate = 'threadMembersUpdate', + UserUpdate = 'userUpdate', + PresenceUpdate = 'presenceUpdate', + VoiceServerUpdate = 'voiceServerUpdate', + VoiceStateUpdate = 'voiceStateUpdate', + TypingStart = 'typingStart', + WebhooksUpdate = 'webhookUpdate', + InteractionCreate = 'interactionCreate', + Error = 'error', + Warn = 'warn', + Debug = 'debug', + CacheSweep = 'cacheSweep', + ShardDisconnect = 'shardDisconnect', + ShardError = 'shardError', + ShardReconnecting = 'shardReconnecting', + ShardReady = 'shardReady', + ShardResume = 'shardResume', + Invalidated = 'invalidated', + Raw = 'raw', + StageInstanceCreate = 'stageInstanceCreate', + StageInstanceUpdate = 'stageInstanceUpdate', + StageInstanceDelete = 'stageInstanceDelete', + GuildStickerCreate = 'stickerCreate', + GuildStickerDelete = 'stickerDelete', + GuildStickerUpdate = 'stickerUpdate', + GuildScheduledEventCreate = 'guildScheduledEventCreate', + GuildScheduledEventUpdate = 'guildScheduledEventUpdate', + GuildScheduledEventDelete = 'guildScheduledEventDelete', + GuildScheduledEventUserAdd = 'guildScheduledEventUserAdd', + GuildScheduledEventUserRemove = 'guildScheduledEventUserRemove', +} + +export enum ShardEvents { + Death = 'death', + Disconnect = 'disconnect', + Error = 'error', + Message = 'message', + Ready = 'ready', + Reconnecting = 'reconnecting', + Resume = 'resume', + Spawn = 'spawn', +} + +export enum WebSocketShardEvents { + Close = 'close', + Destroyed = 'destroyed', + InvalidSession = 'invalidSession', + Ready = 'ready', + Resumed = 'resumed', + AllReady = 'allReady', +} + +export enum Status { + Ready = 0, + Connecting = 1, + Reconnecting = 2, + Idle = 3, + Nearly = 4, + Disconnected = 5, + WaitingForGuilds = 6, + Identifying = 7, + Resuming = 8, +} + +export interface GuildScheduledEventInviteURLCreateOptions extends InviteCreateOptions { + channel?: GuildInvitableChannelResolvable; +} + +export interface RoleCreateOptions extends RoleData { + reason?: string; +} + +export interface RoleEditOptions extends RoleData { + reason?: string; +} + +export interface StageInstanceCreateOptions { + topic: string; + privacyLevel?: StageInstancePrivacyLevel; + sendStartNotification?: boolean; +} + +export interface CrosspostedChannel { + channelId: Snowflake; + guildId: Snowflake; + type: ChannelType; + name: string; +} + +export type DateResolvable = Date | number | string; + +export interface GuildTemplateEditOptions { + name?: string; + description?: string; +} + +export interface EmbedField { + name: string; + value: string; + inline: boolean; +} + +export type EmojiIdentifierResolvable = + | EmojiResolvable + | `${'' | 'a:'}${string}:${Snowflake}` + | `<${'' | 'a'}:${string}:${Snowflake}>` + | string; + +export type EmojiResolvable = Snowflake | GuildEmoji | ReactionEmoji; + +export interface ErrorEvent { + error: unknown; + message: string; + type: string; + target: WebSocket; +} + +export interface FetchApplicationCommandOptions extends BaseFetchOptions { + guildId?: Snowflake; + locale?: LocaleString; + withLocalizations?: boolean; +} + +export interface FetchArchivedThreadOptions { + type?: 'public' | 'private'; + fetchAll?: boolean; + before?: ThreadChannelResolvable | DateResolvable; + limit?: number; +} + +export interface FetchAutoModerationRuleOptions extends BaseFetchOptions { + autoModerationRule: AutoModerationRuleResolvable; +} + +export interface FetchAutoModerationRulesOptions { + cache?: boolean; +} + +export interface FetchBanOptions extends BaseFetchOptions { + user: UserResolvable; +} + +export interface FetchBansOptions { + limit?: number; + before?: Snowflake; + after?: Snowflake; + cache?: boolean; +} + +export interface FetchChannelOptions extends BaseFetchOptions { + allowUnknownGuild?: boolean; +} + +export interface FetchedThreads { + threads: Collection<Snowflake, AnyThreadChannel>; + members: Collection<Snowflake, ThreadMember>; +} + +export interface FetchedThreadsMore extends FetchedThreads { + hasMore: boolean; +} + +export interface FetchGuildOptions extends BaseFetchOptions { + guild: GuildResolvable; + withCounts?: boolean; +} + +export interface FetchGuildsOptions { + before?: Snowflake; + after?: Snowflake; + limit?: number; +} + +export interface FetchGuildScheduledEventOptions extends BaseFetchOptions { + guildScheduledEvent: GuildScheduledEventResolvable; + withUserCount?: boolean; +} + +export interface FetchGuildScheduledEventsOptions { + cache?: boolean; + withUserCount?: boolean; +} + +export interface FetchGuildScheduledEventSubscribersOptions { + limit?: number; + withMember?: boolean; +} + +interface FetchInviteOptions extends BaseFetchOptions { + code: string; +} + +interface FetchInvitesOptions { + channelId?: GuildInvitableChannelResolvable; + cache?: boolean; +} + +export interface FetchMemberOptions extends BaseFetchOptions { + user: UserResolvable; +} + +export interface FetchMembersOptions { + user?: UserResolvable | UserResolvable[]; + query?: string; + limit?: number; + withPresences?: boolean; + time?: number; + nonce?: string; +} + +export interface FetchMessageOptions extends BaseFetchOptions { + message: MessageResolvable; +} + +export interface FetchMessagesOptions { + limit?: number; + before?: Snowflake; + after?: Snowflake; + around?: Snowflake; + cache?: boolean; +} + +export interface FetchReactionUsersOptions { + limit?: number; + after?: Snowflake; +} + +export interface FetchThreadMemberOptions extends BaseFetchOptions { + member: ThreadMemberResolvable; + withMember?: boolean; +} + +export interface FetchThreadMembersWithGuildMemberDataOptions { + withMember: true; + after?: Snowflake; + limit?: number; + cache?: boolean; +} + +export interface FetchThreadMembersWithoutGuildMemberDataOptions { + withMember?: false; + cache?: boolean; +} + +export type FetchThreadMembersOptions = + | FetchThreadMembersWithGuildMemberDataOptions + | FetchThreadMembersWithoutGuildMemberDataOptions; + +export interface FetchThreadsOptions { + archived?: FetchArchivedThreadOptions; +} + +export interface AttachmentPayload { + attachment: BufferResolvable | Stream; + name?: string; + description?: string; +} + +export type GlobalSweepFilter<K, V> = () => ((value: V, key: K, collection: Collection<K, V>) => boolean) | null; + +interface GuildAuditLogsTypes { + [AuditLogEvent.GuildUpdate]: ['Guild', 'Update']; + [AuditLogEvent.ChannelCreate]: ['Channel', 'Create']; + [AuditLogEvent.ChannelUpdate]: ['Channel', 'Update']; + [AuditLogEvent.ChannelDelete]: ['Channel', 'Delete']; + [AuditLogEvent.ChannelOverwriteCreate]: ['Channel', 'Create']; + [AuditLogEvent.ChannelOverwriteUpdate]: ['Channel', 'Update']; + [AuditLogEvent.ChannelOverwriteDelete]: ['Channel', 'Delete']; + [AuditLogEvent.MemberKick]: ['User', 'Delete']; + [AuditLogEvent.MemberPrune]: ['User', 'Delete']; + [AuditLogEvent.MemberBanAdd]: ['User', 'Delete']; + [AuditLogEvent.MemberBanRemove]: ['User', 'Create']; + [AuditLogEvent.MemberUpdate]: ['User', 'Update']; + [AuditLogEvent.MemberRoleUpdate]: ['User', 'Update']; + [AuditLogEvent.MemberMove]: ['User', 'Update']; + [AuditLogEvent.MemberDisconnect]: ['User', 'Delete']; + [AuditLogEvent.BotAdd]: ['User', 'Create']; + [AuditLogEvent.RoleCreate]: ['Role', 'Create']; + [AuditLogEvent.RoleUpdate]: ['Role', 'Update']; + [AuditLogEvent.RoleDelete]: ['Role', 'Delete']; + [AuditLogEvent.InviteCreate]: ['Invite', 'Create']; + [AuditLogEvent.InviteUpdate]: ['Invite', 'Update']; + [AuditLogEvent.InviteDelete]: ['Invite', 'Delete']; + [AuditLogEvent.WebhookCreate]: ['Webhook', 'Create']; + [AuditLogEvent.WebhookUpdate]: ['Webhook', 'Update']; + [AuditLogEvent.WebhookDelete]: ['Webhook', 'Delete']; + [AuditLogEvent.EmojiCreate]: ['Emoji', 'Create']; + [AuditLogEvent.EmojiUpdate]: ['Emoji', 'Update']; + [AuditLogEvent.EmojiDelete]: ['Emoji', 'Delete']; + [AuditLogEvent.MessageDelete]: ['Message', 'Delete']; + [AuditLogEvent.MessageBulkDelete]: ['Message', 'Delete']; + [AuditLogEvent.MessagePin]: ['Message', 'Create']; + [AuditLogEvent.MessageUnpin]: ['Message', 'Delete']; + [AuditLogEvent.IntegrationCreate]: ['Integration', 'Create']; + [AuditLogEvent.IntegrationUpdate]: ['Integration', 'Update']; + [AuditLogEvent.IntegrationDelete]: ['Integration', 'Delete']; + [AuditLogEvent.StageInstanceCreate]: ['StageInstance', 'Create']; + [AuditLogEvent.StageInstanceUpdate]: ['StageInstance', 'Update']; + [AuditLogEvent.StageInstanceDelete]: ['StageInstance', 'Delete']; + [AuditLogEvent.StickerCreate]: ['Sticker', 'Create']; + [AuditLogEvent.StickerUpdate]: ['Sticker', 'Update']; + [AuditLogEvent.StickerDelete]: ['Sticker', 'Delete']; + [AuditLogEvent.GuildScheduledEventCreate]: ['GuildScheduledEvent', 'Create']; + [AuditLogEvent.GuildScheduledEventUpdate]: ['GuildScheduledEvent', 'Update']; + [AuditLogEvent.GuildScheduledEventDelete]: ['GuildScheduledEvent', 'Delete']; + [AuditLogEvent.ThreadCreate]: ['Thread', 'Create']; + [AuditLogEvent.ThreadUpdate]: ['Thread', 'Update']; + [AuditLogEvent.ThreadDelete]: ['Thread', 'Delete']; + [AuditLogEvent.ApplicationCommandPermissionUpdate]: ['ApplicationCommand', 'Update']; + [AuditLogEvent.AutoModerationRuleCreate]: ['AutoModerationRule', 'Create']; + [AuditLogEvent.AutoModerationRuleUpdate]: ['AutoModerationRule', 'Update']; + [AuditLogEvent.AutoModerationRuleDelete]: ['AutoModerationRule', 'Delete']; + [AuditLogEvent.AutoModerationBlockMessage]: ['AutoModerationRule', 'Create']; + [AuditLogEvent.AutoModerationFlagToChannel]: ['AutoModerationRule', 'Create']; + [AuditLogEvent.AutoModerationUserCommunicationDisabled]: ['AutoModerationRule', 'Create']; +} + +export type GuildAuditLogsActionType = GuildAuditLogsTypes[keyof GuildAuditLogsTypes][1] | 'All'; + +export interface GuildAuditLogsEntryExtraField { + [AuditLogEvent.MemberPrune]: { removed: number; days: number }; + [AuditLogEvent.MemberMove]: { channel: VoiceBasedChannel | { id: Snowflake }; count: number }; + [AuditLogEvent.MessageDelete]: { channel: GuildTextBasedChannel | { id: Snowflake }; count: number }; + [AuditLogEvent.MessageBulkDelete]: { channel: GuildTextBasedChannel | { id: Snowflake }; count: number }; + [AuditLogEvent.MessagePin]: { channel: GuildTextBasedChannel | { id: Snowflake }; messageId: Snowflake }; + [AuditLogEvent.MessageUnpin]: { channel: GuildTextBasedChannel | { id: Snowflake }; messageId: Snowflake }; + [AuditLogEvent.MemberDisconnect]: { count: number }; + [AuditLogEvent.ChannelOverwriteCreate]: + | Role + | GuildMember + | { id: Snowflake; name: string; type: AuditLogOptionsType.Role } + | { id: Snowflake; type: AuditLogOptionsType.Member }; + [AuditLogEvent.ChannelOverwriteUpdate]: + | Role + | GuildMember + | { id: Snowflake; name: string; type: AuditLogOptionsType.Role } + | { id: Snowflake; type: AuditLogOptionsType.Member }; + [AuditLogEvent.ChannelOverwriteDelete]: + | Role + | GuildMember + | { id: Snowflake; name: string; type: AuditLogOptionsType.Role } + | { id: Snowflake; type: AuditLogOptionsType.Member }; + [AuditLogEvent.StageInstanceCreate]: StageChannel | { id: Snowflake }; + [AuditLogEvent.StageInstanceDelete]: StageChannel | { id: Snowflake }; + [AuditLogEvent.StageInstanceUpdate]: StageChannel | { id: Snowflake }; + [AuditLogEvent.ApplicationCommandPermissionUpdate]: { applicationId: Snowflake }; + [AuditLogEvent.AutoModerationBlockMessage]: { + autoModerationRuleName: string; + autoModerationRuleTriggerType: AuditLogRuleTriggerType; + channel: GuildTextBasedChannel | { id: Snowflake }; + }; + [AuditLogEvent.AutoModerationFlagToChannel]: { + autoModerationRuleName: string; + autoModerationRuleTriggerType: AuditLogRuleTriggerType; + channel: GuildTextBasedChannel | { id: Snowflake }; + }; + [AuditLogEvent.AutoModerationUserCommunicationDisabled]: { + autoModerationRuleName: string; + autoModerationRuleTriggerType: AuditLogRuleTriggerType; + channel: GuildTextBasedChannel | { id: Snowflake }; + }; +} + +export interface GuildAuditLogsEntryTargetField<TActionType extends GuildAuditLogsActionType> { + User: User | null; + Guild: Guild; + Webhook: Webhook; + Invite: Invite; + Message: TActionType extends AuditLogEvent.MessageBulkDelete ? Guild | { id: Snowflake } : User; + Integration: Integration; + Channel: NonThreadGuildBasedChannel | { id: Snowflake; [x: string]: unknown }; + Thread: AnyThreadChannel | { id: Snowflake; [x: string]: unknown }; + StageInstance: StageInstance; + Sticker: Sticker; + GuildScheduledEvent: GuildScheduledEvent; + ApplicationCommand: ApplicationCommand | { id: Snowflake }; + AutoModerationRule: AutoModerationRule; +} + +export interface GuildAuditLogsFetchOptions<T extends GuildAuditLogsResolvable> { + before?: Snowflake | GuildAuditLogsEntry; + after?: Snowflake | GuildAuditLogsEntry; + limit?: number; + user?: UserResolvable; + type?: T; +} + +export type GuildAuditLogsResolvable = AuditLogEvent | null; + +export type GuildAuditLogsTargetType = GuildAuditLogsTypes[keyof GuildAuditLogsTypes][0] | 'All' | 'Unknown'; + +export type GuildAuditLogsTargets = { + [key in GuildAuditLogsTargetType]: GuildAuditLogsTargetType; +}; + +export type GuildBanResolvable = GuildBan | UserResolvable; + +export type GuildChannelResolvable = Snowflake | GuildBasedChannel; + +export interface AutoModerationRuleCreateOptions { + name: string; + eventType: AutoModerationRuleEventType; + triggerType: AutoModerationRuleTriggerType; + triggerMetadata?: AutoModerationTriggerMetadataOptions; + actions: AutoModerationActionOptions[]; + enabled?: boolean; + exemptRoles?: Collection<Snowflake, Role> | RoleResolvable[]; + exemptChannels?: Collection<Snowflake, GuildBasedChannel> | GuildChannelResolvable[]; + reason?: string; +} + +export interface AutoModerationRuleEditOptions extends Partial<Omit<AutoModerationRuleCreateOptions, 'triggerType'>> {} + +export interface AutoModerationTriggerMetadataOptions extends Partial<AutoModerationTriggerMetadata> {} + +export interface AutoModerationActionOptions { + type: AutoModerationActionType; + metadata?: AutoModerationActionMetadataOptions; +} + +export interface AutoModerationActionMetadataOptions extends Partial<Omit<AutoModerationActionMetadata, 'channelId'>> { + channel?: GuildTextChannelResolvable | ThreadChannel; +} + +export interface GuildChannelCreateOptions extends Omit<CategoryCreateChannelOptions, 'type'> { + parent?: CategoryChannelResolvable | null; + type?: Exclude< + ChannelType, + | ChannelType.DM + | ChannelType.GroupDM + | ChannelType.PublicThread + | ChannelType.AnnouncementThread + | ChannelType.PrivateThread + >; +} + +export interface GuildChannelCloneOptions extends Omit<GuildChannelCreateOptions, 'name'> { + name?: string; +} + +export interface GuildChannelEditOptions { + name?: string; + type?: ChannelType.GuildText | ChannelType.GuildAnnouncement; + position?: number; + topic?: string | null; + nsfw?: boolean; + bitrate?: number; + userLimit?: number; + parent?: CategoryChannelResolvable | null; + rateLimitPerUser?: number; + lockPermissions?: boolean; + permissionOverwrites?: readonly OverwriteResolvable[] | Collection<Snowflake, OverwriteResolvable>; + defaultAutoArchiveDuration?: ThreadAutoArchiveDuration; + rtcRegion?: string | null; + videoQualityMode?: VideoQualityMode | null; + availableTags?: GuildForumTagData[]; + defaultReactionEmoji?: DefaultReactionEmoji | null; + defaultThreadRateLimitPerUser?: number; + flags?: ChannelFlagsResolvable; + defaultSortOrder?: SortOrderType | null; + defaultForumLayout?: ForumLayoutType; + reason?: string; +} + +export interface GuildChannelOverwriteOptions { + reason?: string; + type?: OverwriteType; +} + +export interface GuildCreateOptions { + name: string; + icon?: BufferResolvable | Base64Resolvable | null; + verificationLevel?: GuildVerificationLevel; + defaultMessageNotifications?: GuildDefaultMessageNotifications; + explicitContentFilter?: GuildExplicitContentFilter; + roles?: PartialRoleData[]; + channels?: PartialChannelData[]; + afkChannelId?: Snowflake | number; + afkTimeout?: number; + systemChannelId?: Snowflake | number; + systemChannelFlags?: SystemChannelFlagsResolvable; +} + +export interface GuildWidgetSettings { + enabled: boolean; + channel: TextChannel | NewsChannel | VoiceBasedChannel | ForumChannel | null; +} + +export interface GuildEditOptions { + name?: string; + verificationLevel?: GuildVerificationLevel | null; + defaultMessageNotifications?: GuildDefaultMessageNotifications | null; + explicitContentFilter?: GuildExplicitContentFilter | null; + afkTimeout?: number; + afkChannel?: VoiceChannelResolvable | null; + icon?: BufferResolvable | Base64Resolvable | null; + owner?: GuildMemberResolvable; + splash?: BufferResolvable | Base64Resolvable | null; + discoverySplash?: BufferResolvable | Base64Resolvable | null; + banner?: BufferResolvable | Base64Resolvable | null; + systemChannel?: TextChannelResolvable | null; + systemChannelFlags?: SystemChannelFlagsResolvable; + rulesChannel?: TextChannelResolvable | null; + publicUpdatesChannel?: TextChannelResolvable | null; + safetyAlertsChannel?: TextChannelResolvable | null; + preferredLocale?: Locale | null; + features?: `${GuildFeature}`[]; + description?: string | null; + premiumProgressBarEnabled?: boolean; + reason?: string; +} + +export interface GuildEmojiCreateOptions { + attachment: BufferResolvable | Base64Resolvable; + name: string; + roles?: Collection<Snowflake, Role> | RoleResolvable[]; + reason?: string; +} + +export interface GuildEmojiEditOptions { + name?: string; + roles?: Collection<Snowflake, Role> | RoleResolvable[]; + reason?: string; +} + +export interface GuildStickerCreateOptions { + file: BufferResolvable | Stream | AttachmentPayload | JSONEncodable<AttachmentBuilder>; + name: string; + tags: string; + description?: string | null; + reason?: string; +} + +export interface GuildStickerEditOptions { + name?: string; + description?: string | null; + tags?: string; + reason?: string; +} + +export interface GuildMemberEditOptions { + nick?: string | null; + roles?: Collection<Snowflake, Role> | readonly RoleResolvable[]; + mute?: boolean; + deaf?: boolean; + channel?: GuildVoiceChannelResolvable | null; + communicationDisabledUntil?: DateResolvable | null; + flags?: GuildMemberFlagsResolvable; + reason?: string; +} + +export type GuildMemberResolvable = GuildMember | UserResolvable; + +export type GuildResolvable = Guild | NonThreadGuildBasedChannel | GuildMember | GuildEmoji | Invite | Role | Snowflake; + +export interface GuildPruneMembersOptions { + count?: boolean; + days?: number; + dry?: boolean; + reason?: string; + roles?: RoleResolvable[]; +} + +export interface GuildWidgetSettingsData { + enabled: boolean; + channel: TextChannel | NewsChannel | VoiceBasedChannel | ForumChannel | Snowflake | null; +} + +export interface GuildSearchMembersOptions { + query: string; + limit?: number; + cache?: boolean; +} + +export interface GuildListMembersOptions { + after?: Snowflake; + limit?: number; + cache?: boolean; +} + +// TODO: use conditional types for better TS support +export interface GuildScheduledEventCreateOptions { + name: string; + scheduledStartTime: DateResolvable; + scheduledEndTime?: DateResolvable; + privacyLevel: GuildScheduledEventPrivacyLevel; + entityType: GuildScheduledEventEntityType; + description?: string; + channel?: GuildVoiceChannelResolvable; + entityMetadata?: GuildScheduledEventEntityMetadataOptions; + image?: BufferResolvable | Base64Resolvable | null; + reason?: string; +} + +export interface GuildScheduledEventEditOptions< + S extends GuildScheduledEventStatus, + T extends GuildScheduledEventSetStatusArg<S>, +> extends Omit<Partial<GuildScheduledEventCreateOptions>, 'channel'> { + channel?: GuildVoiceChannelResolvable | null; + status?: T; +} + +export interface GuildScheduledEventEntityMetadata { + location: string | null; +} + +export interface GuildScheduledEventEntityMetadataOptions { + location?: string; +} + +export type GuildScheduledEventManagerFetchResult< + T extends GuildScheduledEventResolvable | FetchGuildScheduledEventOptions | FetchGuildScheduledEventsOptions, +> = T extends GuildScheduledEventResolvable | FetchGuildScheduledEventOptions + ? GuildScheduledEvent + : Collection<Snowflake, GuildScheduledEvent>; + +export type GuildScheduledEventManagerFetchSubscribersResult<T extends FetchGuildScheduledEventSubscribersOptions> = + T extends { withMember: true } + ? Collection<Snowflake, GuildScheduledEventUser<true>> + : Collection<Snowflake, GuildScheduledEventUser<false>>; + +export type GuildScheduledEventResolvable = Snowflake | GuildScheduledEvent; + +export type GuildScheduledEventSetStatusArg<T extends GuildScheduledEventStatus> = + T extends GuildScheduledEventStatus.Scheduled + ? GuildScheduledEventStatus.Active | GuildScheduledEventStatus.Canceled + : T extends GuildScheduledEventStatus.Active + ? GuildScheduledEventStatus.Completed + : never; + +export interface GuildScheduledEventUser<T> { + guildScheduledEventId: Snowflake; + user: User; + member: T extends true ? GuildMember : null; +} + +export type GuildTemplateResolvable = string; + +export type GuildVoiceChannelResolvable = VoiceBasedChannel | Snowflake; + +export interface GuildOnboardingPromptOptionEmoji { + id: Snowflake | null; + name: string; + animated: boolean; +} + +export type HexColorString = `#${string}`; + +export interface IntegrationAccount { + id: string | Snowflake; + name: string; +} + +export type IntegrationType = 'twitch' | 'youtube' | 'discord' | 'guild_subscription'; + +export type CollectedInteraction<Cached extends CacheType = CacheType> = + | StringSelectMenuInteraction<Cached> + | UserSelectMenuInteraction<Cached> + | RoleSelectMenuInteraction<Cached> + | MentionableSelectMenuInteraction<Cached> + | ChannelSelectMenuInteraction<Cached> + | ButtonInteraction<Cached> + | ModalSubmitInteraction<Cached>; + +export interface InteractionCollectorOptions<T extends CollectedInteraction, Cached extends CacheType = CacheType> + extends CollectorOptions<[T, Collection<Snowflake, T>]> { + channel?: TextBasedChannelResolvable; + componentType?: ComponentType; + guild?: GuildResolvable; + interactionType?: InteractionType; + max?: number; + maxComponents?: number; + maxUsers?: number; + message?: CacheTypeReducer<Cached, Message, APIMessage>; + interactionResponse?: InteractionResponse<BooleanCache<Cached>>; +} + +export interface InteractionDeferReplyOptions { + ephemeral?: boolean; + fetchReply?: boolean; +} + +export type InteractionDeferUpdateOptions = Omit<InteractionDeferReplyOptions, 'ephemeral'>; + +export interface InteractionReplyOptions extends BaseMessageOptions { + tts?: boolean; + ephemeral?: boolean; + fetchReply?: boolean; + flags?: BitFieldResolvable< + Extract<MessageFlagsString, 'Ephemeral' | 'SuppressEmbeds'>, + MessageFlags.Ephemeral | MessageFlags.SuppressEmbeds + >; +} + +export interface InteractionUpdateOptions extends MessageEditOptions { + fetchReply?: boolean; +} + +export interface InviteGenerationOptions { + permissions?: PermissionResolvable; + guild?: GuildResolvable; + disableGuildSelect?: boolean; + scopes: OAuth2Scopes[]; +} + +export type GuildInvitableChannelResolvable = + | TextChannel + | VoiceChannel + | NewsChannel + | StageChannel + | ForumChannel + | Snowflake; + +export interface InviteCreateOptions { + temporary?: boolean; + maxAge?: number; + maxUses?: number; + unique?: boolean; + reason?: string; + targetApplication?: ApplicationResolvable; + targetUser?: UserResolvable; + targetType?: InviteTargetType; +} + +export type InviteResolvable = string; + +export interface LifetimeFilterOptions<K, V> { + excludeFromSweep?: (value: V, key: K, collection: LimitedCollection<K, V>) => boolean; + getComparisonTimestamp?: (value: V, key: K, collection: LimitedCollection<K, V>) => number; + lifetime?: number; +} + +export interface MakeErrorOptions { + name: string; + message: string; + stack: string; +} + +export type ActionRowComponentOptions = + | ButtonComponentData + | StringSelectMenuComponentData + | UserSelectMenuComponentData + | RoleSelectMenuComponentData + | MentionableSelectMenuComponentData + | ChannelSelectMenuComponentData; + +export type MessageActionRowComponentResolvable = MessageActionRowComponent | ActionRowComponentOptions; + +export interface MessageActivity { + partyId?: string; + type: MessageActivityType; +} + +export interface BaseButtonComponentData extends BaseComponentData { + type: ComponentType.Button; + style: ButtonStyle; + disabled?: boolean; + emoji?: ComponentEmojiResolvable; + label?: string; +} + +export interface LinkButtonComponentData extends BaseButtonComponentData { + style: ButtonStyle.Link; + url: string; +} + +export interface InteractionButtonComponentData extends BaseButtonComponentData { + style: Exclude<ButtonStyle, ButtonStyle.Link>; + customId: string; +} + +export type ButtonComponentData = InteractionButtonComponentData | LinkButtonComponentData; + +export interface MessageCollectorOptions extends CollectorOptions<[Message, Collection<Snowflake, Message>]> { + max?: number; + maxProcessed?: number; +} + +export type MessageComponent = + | Component + | ActionRowBuilder<MessageActionRowComponentBuilder | ModalActionRowComponentBuilder> + | ButtonComponent + | StringSelectMenuComponent + | UserSelectMenuComponent + | RoleSelectMenuComponent + | MentionableSelectMenuComponent + | ChannelSelectMenuComponent; + +export type CollectedMessageInteraction<Cached extends CacheType = CacheType> = Exclude< + CollectedInteraction<Cached>, + ModalSubmitInteraction +>; + +export type MessageComponentCollectorOptions<T extends CollectedMessageInteraction> = Omit< + InteractionCollectorOptions<T>, + 'channel' | 'message' | 'guild' | 'interactionType' +>; + +export type MessageChannelComponentCollectorOptions<T extends CollectedMessageInteraction> = Omit< + InteractionCollectorOptions<T>, + 'channel' | 'guild' | 'interactionType' +>; + +export interface MessageEvent { + data: WebSocket.Data; + type: string; + target: WebSocket; +} + +export interface MessageInteraction { + id: Snowflake; + type: InteractionType; + commandName: string; + user: User; +} + +export interface MessageMentionsHasOptions { + ignoreDirect?: boolean; + ignoreRoles?: boolean; + ignoreRepliedUser?: boolean; + ignoreEveryone?: boolean; +} + +export interface MessageMentionOptions { + parse?: MessageMentionTypes[]; + roles?: Snowflake[]; + users?: Snowflake[]; + repliedUser?: boolean; +} + +export type MessageMentionTypes = 'roles' | 'users' | 'everyone'; + +export interface BaseMessageOptions { + content?: string; + embeds?: (JSONEncodable<APIEmbed> | APIEmbed)[]; + allowedMentions?: MessageMentionOptions; + files?: ( + | BufferResolvable + | Stream + | JSONEncodable<APIAttachment> + | Attachment + | AttachmentBuilder + | AttachmentPayload + )[]; + components?: ( + | JSONEncodable<APIActionRowComponent<APIMessageActionRowComponent>> + | ActionRowData<MessageActionRowComponentData | MessageActionRowComponentBuilder> + | APIActionRowComponent<APIMessageActionRowComponent> + )[]; +} + +export interface MessageCreateOptions extends BaseMessageOptions { + tts?: boolean; + nonce?: string | number; + reply?: ReplyOptions; + stickers?: StickerResolvable[]; + flags?: BitFieldResolvable< + Extract<MessageFlagsString, 'SuppressEmbeds' | 'SuppressNotifications'>, + MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications + >; +} + +export type GuildForumThreadMessageCreateOptions = BaseMessageOptions & + Pick<MessageCreateOptions, 'flags' | 'stickers'>; + +export interface MessageEditOptions extends Omit<BaseMessageOptions, 'content'> { + content?: string | null; + attachments?: JSONEncodable<AttachmentPayload>[]; + flags?: BitFieldResolvable<Extract<MessageFlagsString, 'SuppressEmbeds'>, MessageFlags.SuppressEmbeds>; +} + +export type MessageReactionResolvable = MessageReaction | Snowflake | string; + +export interface MessageReference { + channelId: Snowflake; + guildId: Snowflake | undefined; + messageId: Snowflake | undefined; +} + +export type MessageResolvable = Message | Snowflake; + +export interface BaseSelectMenuComponentData extends BaseComponentData { + customId: string; + disabled?: boolean; + maxValues?: number; + minValues?: number; + placeholder?: string; +} + +export interface StringSelectMenuComponentData extends BaseSelectMenuComponentData { + type: ComponentType.StringSelect; + options: SelectMenuComponentOptionData[]; +} + +export interface UserSelectMenuComponentData extends BaseSelectMenuComponentData { + type: ComponentType.UserSelect; +} + +export interface RoleSelectMenuComponentData extends BaseSelectMenuComponentData { + type: ComponentType.RoleSelect; +} + +export interface MentionableSelectMenuComponentData extends BaseSelectMenuComponentData { + type: ComponentType.MentionableSelect; +} + +export interface ChannelSelectMenuComponentData extends BaseSelectMenuComponentData { + type: ComponentType.ChannelSelect; + channelTypes?: ChannelType[]; +} + +export interface MessageSelectOption { + default: boolean; + description: string | null; + emoji: APIPartialEmoji | null; + label: string; + value: string; +} + +export interface SelectMenuComponentOptionData { + default?: boolean; + description?: string; + emoji?: ComponentEmojiResolvable; + label: string; + value: string; +} + +export interface TextInputComponentData extends BaseComponentData { + type: ComponentType.TextInput; + customId: string; + style: TextInputStyle; + label: string; + minLength?: number; + maxLength?: number; + required?: boolean; + value?: string; + placeholder?: string; +} + +export type MessageTarget = + | Interaction + | InteractionWebhook + | TextBasedChannel + | User + | GuildMember + | Webhook + | WebhookClient + | Message + | MessageManager; + +export interface MultipleShardRespawnOptions { + shardDelay?: number; + respawnDelay?: number; + timeout?: number; +} + +export interface MultipleShardSpawnOptions { + amount?: number | 'auto'; + delay?: number; + timeout?: number; +} + +export interface OverwriteData { + allow?: PermissionResolvable; + deny?: PermissionResolvable; + id: GuildMemberResolvable | RoleResolvable; + type?: OverwriteType; +} + +export type OverwriteResolvable = PermissionOverwrites | OverwriteData; + +export type PermissionFlags = Record<keyof typeof PermissionFlagsBits, bigint>; + +export type PermissionOverwriteOptions = Partial<Record<keyof typeof PermissionFlagsBits, boolean | null>>; + +export type PermissionResolvable = BitFieldResolvable<keyof typeof PermissionFlagsBits, bigint>; + +export type PermissionOverwriteResolvable = UserResolvable | RoleResolvable | PermissionOverwrites; + +export type RecursiveArray<T> = ReadonlyArray<T | RecursiveArray<T>>; + +export type RecursiveReadonlyArray<T> = ReadonlyArray<T | RecursiveReadonlyArray<T>>; + +export interface PartialRecipient { + username: string; +} + +export interface PresenceData { + status?: PresenceStatusData; + afk?: boolean; + activities?: ActivitiesOptions[]; + shardId?: number | number[]; +} + +export type PresenceResolvable = Presence | UserResolvable | Snowflake; + +export interface PartialChannelData { + id?: Snowflake | number; + parentId?: Snowflake | number; + type?: ChannelType.GuildText | ChannelType.GuildVoice | ChannelType.GuildCategory; + name: string; + topic?: string | null; + nsfw?: boolean; + bitrate?: number; + userLimit?: number; + rtcRegion?: string | null; + videoQualityMode?: VideoQualityMode; + permissionOverwrites?: PartialOverwriteData[]; + rateLimitPerUser?: number; +} + +export type Partialize< + T extends AllowedPartial, + N extends keyof T | null = null, + M extends keyof T | null = null, + E extends keyof T | '' = '', +> = { + readonly client: Client<true>; + id: Snowflake; + partial: true; +} & { + [K in keyof Omit<T, 'client' | 'id' | 'partial' | E>]: K extends N ? null : K extends M ? T[K] | null : T[K]; +}; + +export interface PartialDMChannel extends Partialize<DMChannel, null, null, 'lastMessageId'> { + lastMessageId: undefined; +} + +export interface PartialGuildMember extends Partialize<GuildMember, 'joinedAt' | 'joinedTimestamp' | 'pending'> {} + +export interface PartialMessage + extends Partialize<Message, 'type' | 'system' | 'pinned' | 'tts', 'content' | 'cleanContent' | 'author'> {} + +export interface PartialMessageReaction extends Partialize<MessageReaction, 'count'> {} + +export interface PartialThreadMember extends Partialize<ThreadMember, 'flags' | 'joinedAt' | 'joinedTimestamp'> {} + +export interface PartialOverwriteData { + id: Snowflake | number; + type?: OverwriteType; + allow?: PermissionResolvable; + deny?: PermissionResolvable; +} + +export interface PartialRoleData extends RoleData { + id?: Snowflake | number; +} + +export enum Partials { + User, + Channel, + GuildMember, + Message, + Reaction, + GuildScheduledEvent, + ThreadMember, +} + +export interface PartialUser extends Partialize<User, 'username' | 'tag' | 'discriminator'> {} + +export type PresenceStatusData = ClientPresenceStatus | 'invisible'; + +export type PresenceStatus = PresenceStatusData | 'offline'; + +export interface ReactionCollectorOptions extends CollectorOptions<[MessageReaction, User]> { + max?: number; + maxEmojis?: number; + maxUsers?: number; +} + +export interface ReplyOptions { + messageReference: MessageResolvable; + failIfNotExists?: boolean; +} + +export interface MessageReplyOptions extends Omit<MessageCreateOptions, 'reply'> { + failIfNotExists?: boolean; +} + +export interface ResolvedOverwriteOptions { + allow: PermissionsBitField; + deny: PermissionsBitField; +} + +export interface RoleData { + name?: string; + color?: ColorResolvable; + hoist?: boolean; + position?: number; + permissions?: PermissionResolvable; + mentionable?: boolean; + icon?: BufferResolvable | Base64Resolvable | EmojiResolvable | null; + unicodeEmoji?: string | null; +} + +export type RoleMention = '@everyone' | `<@&${Snowflake}>`; + +export interface RolePosition { + role: RoleResolvable; + position: number; +} + +export type RoleResolvable = Role | Snowflake; + +export interface RoleSubscriptionData { + roleSubscriptionListingId: Snowflake; + tierName: string; + totalMonthsSubscribed: number; + isRenewal: boolean; +} + +export interface RoleTagData { + botId?: Snowflake; + integrationId?: Snowflake; + premiumSubscriberRole?: true; + subscriptionListingId?: Snowflake; + availableForPurchase?: true; + guildConnections?: true; +} + +export interface SetChannelPositionOptions { + relative?: boolean; + reason?: string; +} + +export interface SetParentOptions { + lockPermissions?: boolean; + reason?: string; +} + +export interface SetRolePositionOptions { + relative?: boolean; + reason?: string; +} + +export type ShardingManagerMode = 'process' | 'worker'; + +export interface ShardingManagerOptions { + totalShards?: number | 'auto'; + shardList?: number[] | 'auto'; + mode?: ShardingManagerMode; + respawn?: boolean; + silent?: boolean; + shardArgs?: string[]; + token?: string; + execArgv?: string[]; +} + +export { Snowflake }; + +export type StageInstanceResolvable = StageInstance | Snowflake; + +export interface StartThreadOptions { + name: string; + autoArchiveDuration?: ThreadAutoArchiveDuration; + reason?: string; + rateLimitPerUser?: number; +} + +export type ClientStatus = number; + +export type StickerResolvable = Sticker | Snowflake; + +export type SystemChannelFlagsResolvable = BitFieldResolvable<SystemChannelFlagsString, number>; + +export type StageChannelResolvable = StageChannel | Snowflake; + +export interface StageInstanceEditOptions { + topic?: string; + privacyLevel?: StageInstancePrivacyLevel; +} + +export type SweeperKey = keyof SweeperDefinitions; + +export type CollectionSweepFilter<K, V> = (value: V, key: K, collection: Collection<K, V>) => boolean; + +export interface SweepOptions<K, V> { + interval: number; + filter: GlobalSweepFilter<K, V>; +} + +export interface LifetimeSweepOptions { + interval: number; + lifetime: number; + filter?: never; +} + +export interface SweeperDefinitions { + applicationCommands: [Snowflake, ApplicationCommand]; + autoModerationRules: [Snowflake, AutoModerationRule]; + bans: [Snowflake, GuildBan]; + emojis: [Snowflake, GuildEmoji]; + invites: [string, Invite, true]; + guildMembers: [Snowflake, GuildMember]; + messages: [Snowflake, Message, true]; + presences: [Snowflake, Presence]; + reactions: [string | Snowflake, MessageReaction]; + stageInstances: [Snowflake, StageInstance]; + stickers: [Snowflake, Sticker]; + threadMembers: [Snowflake, ThreadMember]; + threads: [Snowflake, AnyThreadChannel, true]; + users: [Snowflake, User]; + voiceStates: [Snowflake, VoiceState]; +} + +export type SweeperOptions = { + [K in keyof SweeperDefinitions]?: SweeperDefinitions[K][2] extends true + ? SweepOptions<SweeperDefinitions[K][0], SweeperDefinitions[K][1]> | LifetimeSweepOptions + : SweepOptions<SweeperDefinitions[K][0], SweeperDefinitions[K][1]>; +}; + +export interface LimitedCollectionOptions<K, V> { + maxSize?: number; + keepOverLimit?: (value: V, key: K, collection: LimitedCollection<K, V>) => boolean; +} + +export type Channel = + | CategoryChannel + | DMChannel + | PartialDMChannel + | PartialGroupDMChannel + | NewsChannel + | StageChannel + | TextChannel + | AnyThreadChannel + | VoiceChannel + | ForumChannel; + +export type TextBasedChannel = Exclude< + Extract<Channel, { type: TextChannelType }>, + PartialGroupDMChannel | ForumChannel +>; + +export type TextBasedChannelTypes = TextBasedChannel['type']; + +export type GuildTextBasedChannelTypes = Exclude<TextBasedChannelTypes, ChannelType.DM>; + +export type VoiceBasedChannel = Extract<Channel, { bitrate: number }>; + +export type GuildBasedChannel = Extract<Channel, { guild: Guild }>; + +export type CategoryChildChannel = Exclude<Extract<Channel, { parent: CategoryChannel | null }>, CategoryChannel>; + +export type NonThreadGuildBasedChannel = Exclude<GuildBasedChannel, AnyThreadChannel>; + +export type GuildTextBasedChannel = Extract<GuildBasedChannel, TextBasedChannel>; + +export type TextChannelResolvable = Snowflake | TextChannel; + +export type TextBasedChannelResolvable = Snowflake | TextBasedChannel; + +export type ThreadChannelResolvable = AnyThreadChannel | Snowflake; + +export type ThreadChannelType = ChannelType.AnnouncementThread | ChannelType.PublicThread | ChannelType.PrivateThread; + +export interface GuildTextThreadCreateOptions<AllowedThreadType> extends StartThreadOptions { + startMessage?: MessageResolvable; + type?: AllowedThreadType; + invitable?: AllowedThreadType extends ChannelType.PrivateThread ? boolean : never; +} + +export interface GuildForumThreadCreateOptions extends StartThreadOptions { + message: GuildForumThreadMessageCreateOptions | MessagePayload; + appliedTags?: Snowflake[]; +} + +export interface ThreadEditOptions { + name?: string; + archived?: boolean; + autoArchiveDuration?: ThreadAutoArchiveDuration; + rateLimitPerUser?: number; + locked?: boolean; + invitable?: boolean; + appliedTags?: Snowflake[]; + flags?: ChannelFlagsResolvable; + reason?: string; +} + +export type ThreadMemberResolvable = ThreadMember | UserResolvable; + +export type UserMention = `<@${Snowflake}>`; + +export type UserResolvable = User | Snowflake | Message | GuildMember | ThreadMember; + +export interface Vanity { + code: string | null; + uses: number; +} + +export type VoiceBasedChannelTypes = VoiceBasedChannel['type']; + +export type VoiceChannelResolvable = Snowflake | VoiceChannel; + +export interface VoiceStateEditOptions { + requestToSpeak?: boolean; + suppressed?: boolean; +} + +export type WebhookClientData = WebhookClientDataIdWithToken | WebhookClientDataURL; + +export interface WebhookClientDataIdWithToken { + id: Snowflake; + token: string; +} + +export interface WebhookClientDataURL { + url: string; +} + +export type WebhookClientOptions = Pick<ClientOptions, 'allowedMentions' | 'rest'>; + +export interface WebhookDeleteOptions { + token?: string; + reason?: string; +} + +export interface WebhookEditOptions { + name?: string; + avatar?: BufferResolvable | null; + channel?: GuildTextChannelResolvable | VoiceChannel | ForumChannel | StageChannel; + reason?: string; +} + +export interface WebhookMessageEditOptions extends Omit<MessageEditOptions, 'flags'> { + threadId?: Snowflake; +} + +export interface InteractionEditReplyOptions extends WebhookMessageEditOptions { + message?: MessageResolvable | '@original'; +} + +export interface WebhookFetchMessageOptions { + threadId?: Snowflake; +} + +export interface WebhookMessageCreateOptions extends Omit<MessageCreateOptions, 'nonce' | 'reply' | 'stickers'> { + username?: string; + avatarURL?: string; + threadId?: Snowflake; + threadName?: string; +} + +export interface WebSocketOptions { + large_threshold?: number; + version?: number; + buildStrategy?(manager: WSWebSocketManager): IShardingStrategy; + buildIdentifyThrottler?(manager: WSWebSocketManager): Awaitable<IIdentifyThrottler>; +} + +export interface WidgetActivity { + name: string; +} + +export interface WidgetChannel { + id: Snowflake; + name: string; + position: number; +} + +export interface WelcomeChannelData { + description: string; + channel: TextChannel | NewsChannel | ForumChannel | Snowflake; + emoji?: EmojiIdentifierResolvable; +} + +export interface WelcomeScreenEditOptions { + enabled?: boolean; + description?: string; + welcomeChannels?: WelcomeChannelData[]; +} + +export interface ClientApplicationInstallParams { + scopes: OAuth2Scopes[]; + permissions: Readonly<PermissionsBitField>; +} + +export type Serialized<T> = T extends symbol | bigint | (() => any) + ? never + : T extends number | string | boolean | undefined + ? T + : T extends { toJSON(): infer R } + ? R + : T extends ReadonlyArray<infer V> + ? Serialized<V>[] + : T extends ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> + ? {} + : { [K in keyof T]: Serialized<T[K]> }; + +//#endregion + +//#region Voice + +/** + * @internal Use `DiscordGatewayAdapterLibraryMethods` from `@discordjs/voice` instead. + */ +export interface InternalDiscordGatewayAdapterLibraryMethods { + onVoiceServerUpdate(data: GatewayVoiceServerUpdateDispatchData): void; + onVoiceStateUpdate(data: GatewayVoiceStateUpdateDispatchData): void; + destroy(): void; +} + +/** + * @internal Use `DiscordGatewayAdapterImplementerMethods` from `@discordjs/voice` instead. + */ +export interface InternalDiscordGatewayAdapterImplementerMethods { + sendPayload(payload: unknown): boolean; + destroy(): void; +} + +/** + * @internal Use `DiscordGatewayAdapterCreator` from `@discordjs/voice` instead. + */ +export type InternalDiscordGatewayAdapterCreator = ( + methods: InternalDiscordGatewayAdapterLibraryMethods, +) => InternalDiscordGatewayAdapterImplementerMethods; + +//#endregion + +// External +export * from 'discord-api-types/v10'; +export * from '@discordjs/builders'; +export * from '@discordjs/formatters'; +export * from '@discordjs/rest'; +export * from '@discordjs/util'; +export * from '@discordjs/ws'; diff --git a/node_modules/discord.js/typings/index.test-d.ts b/node_modules/discord.js/typings/index.test-d.ts new file mode 100644 index 0000000..86b2824 --- /dev/null +++ b/node_modules/discord.js/typings/index.test-d.ts @@ -0,0 +1,2311 @@ +import type { ChildProcess } from 'node:child_process'; +import type { Worker } from 'node:worker_threads'; +import { + APIInteractionGuildMember, + APIPartialChannel, + APIPartialGuild, + APIInteractionDataResolvedGuildMember, + APIInteractionDataResolvedChannel, + APIRole, + APIButtonComponent, + APISelectMenuComponent, + ApplicationCommandOptionType, + ComponentType, + ApplicationCommandPermissionType, + ChannelType, + InteractionType, + GatewayIntentBits, + Locale, + PermissionFlagsBits, + AuditLogEvent, + ButtonStyle, + TextInputStyle, + APITextInputComponent, + APIEmbed, + ApplicationCommandType, + APIMessage, + APIActionRowComponent, + APIActionRowComponentTypes, + APIStringSelectComponent, +} from 'discord-api-types/v10'; +import { + ApplicationCommand, + ApplicationCommandData, + ApplicationCommandManager, + ApplicationCommandOptionData, + ApplicationCommandResolvable, + ApplicationCommandSubCommandData, + ApplicationCommandSubGroupData, + CommandInteraction, + ButtonInteraction, + CacheType, + CategoryChannel, + Client, + ClientApplication, + ClientUser, + CloseEvent, + Collection, + ChatInputCommandInteraction, + CommandInteractionOption, + CommandInteractionOptionResolver, + CommandOptionNonChoiceResolvableType, + ContextMenuCommandInteraction, + DMChannel, + Guild, + GuildApplicationCommandManager, + GuildChannelManager, + GuildEmoji, + GuildEmojiManager, + GuildMember, + GuildResolvable, + IntentsBitField, + Interaction, + InteractionCollector, + Message, + AttachmentBuilder, + MessageCollector, + MessageComponentInteraction, + MessageReaction, + ModalBuilder, + NewsChannel, + Options, + PartialTextBasedChannelFields, + PartialUser, + PermissionsBitField, + ReactionCollector, + Role, + RoleManager, + Serialized, + ShardClientUtil, + ShardingManager, + Snowflake, + StageChannel, + TextBasedChannelFields, + TextBasedChannel, + TextBasedChannelTypes, + VoiceBasedChannel, + GuildBasedChannel, + NonThreadGuildBasedChannel, + GuildTextBasedChannel, + TextChannel, + ThreadChannel, + ThreadMember, + Typing, + User, + VoiceChannel, + Shard, + WebSocketShard, + Collector, + GuildAuditLogsEntry, + GuildAuditLogs, + StageInstance, + ActionRowBuilder, + ButtonComponent, + SelectMenuComponent, + RepliableInteraction, + ThreadChannelType, + Events, + WebSocketShardEvents, + Status, + CategoryChannelChildManager, + ActionRowData, + MessageActionRowComponentData, + PartialThreadMember, + ThreadMemberFlagsBitField, + ButtonBuilder, + EmbedBuilder, + MessageActionRowComponent, + StringSelectMenuBuilder, + TextInputBuilder, + TextInputComponent, + Embed, + MessageActionRowComponentBuilder, + GuildBanManager, + GuildBan, + MessageManager, + ChannelMention, + UserMention, + PartialGroupDMChannel, + Attachment, + MessageContextMenuCommandInteraction, + UserContextMenuCommandInteraction, + AnyThreadChannel, + ThreadMemberManager, + CollectedMessageInteraction, + ShardEvents, + Webhook, + WebhookClient, + InteractionWebhook, + ActionRowComponent, + ActionRow, + GuildAuditLogsActionType, + GuildAuditLogsTargetType, + ModalSubmitInteraction, + ForumChannel, + ChannelFlagsBitField, + GuildForumThreadManager, + GuildTextThreadManager, + AnySelectMenuInteraction, + StringSelectMenuInteraction, + StringSelectMenuComponent, + UserSelectMenuInteraction, + RoleSelectMenuInteraction, + ChannelSelectMenuInteraction, + MentionableSelectMenuInteraction, + MessageMentions, + AutoModerationActionExecution, + AutoModerationRule, + AutoModerationRuleManager, + PrivateThreadChannel, + PublicThreadChannel, + GuildMemberManager, + GuildMemberFlagsBitField, + ThreadManager, + FetchedThreads, + FetchedThreadsMore, + DMMessageManager, + GuildMessageManager, + ApplicationCommandChannelOptionData, + ApplicationCommandChannelOption, + ApplicationCommandChoicesOption, + ApplicationCommandChoicesData, + ApplicationCommandSubGroup, + ApplicationCommandSubCommand, + ChatInputApplicationCommandData, + ApplicationCommandPermissionsManager, + GuildOnboarding, + StringSelectMenuComponentData, + ButtonComponentData, +} from '.'; +import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd'; +import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders'; + +// Test type transformation: +declare const serialize: <T>(value: T) => Serialized<T>; +declare const notPropertyOf: <T, P extends PropertyKey>(value: T, property: P & Exclude<P, keyof T>) => void; + +const client: Client = new Client({ + intents: GatewayIntentBits.Guilds, + makeCache: Options.cacheWithLimits({ + MessageManager: 200, + // @ts-expect-error + Message: 100, + GuildMemberManager: { + maxSize: 200, + keepOverLimit: member => member.id === client.user?.id, + }, + }), +}); + +const testGuildId = '222078108977594368'; // DJS +const testUserId = '987654321098765432'; // example id +const globalCommandId = '123456789012345678'; // example id +const guildCommandId = '234567890123456789'; // example id + +client.on('autoModerationActionExecution', autoModerationActionExecution => + expectType<AutoModerationActionExecution>(autoModerationActionExecution), +); + +client.on('autoModerationRuleCreate', ({ client }) => expectType<Client<true>>(client)); +client.on('autoModerationRuleDelete', ({ client }) => expectType<Client<true>>(client)); + +client.on('autoModerationRuleUpdate', (oldAutoModerationRule, { client: newClient }) => { + expectType<Client<true>>(oldAutoModerationRule!.client); + expectType<Client<true>>(newClient); +}); + +client.on('channelCreate', ({ client }) => expectType<Client<true>>(client)); +client.on('channelDelete', ({ client }) => expectType<Client<true>>(client)); +client.on('channelPinsUpdate', ({ client }) => expectType<Client<true>>(client)); + +client.on('channelUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('emojiCreate', ({ client }) => expectType<Client<true>>(client)); +client.on('emojiDelete', ({ client }) => expectType<Client<true>>(client)); + +client.on('emojiUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('guildBanAdd', ({ client }) => expectType<Client<true>>(client)); +client.on('guildBanRemove', ({ client }) => expectType<Client<true>>(client)); +client.on('guildDelete', ({ client }) => expectType<Client<true>>(client)); +client.on('guildIntegrationsUpdate', ({ client }) => expectType<Client<true>>(client)); +client.on('guildMemberAdd', ({ client }) => expectType<Client<true>>(client)); +client.on('guildMemberAvailable', ({ client }) => expectType<Client<true>>(client)); + +client.on('guildMemberRemove', member => { + expectType<Client<true>>(member.client); + if (member.partial) return expectType<null>(member.joinedAt); + expectType<Date | null>(member.joinedAt); +}); + +client.on('guildMembersChunk', (members, { client }) => { + expectType<Client<true>>(members.first()!.client); + expectType<Client<true>>(client); +}); + +client.on('guildMemberUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('guildScheduledEventCreate', ({ client }) => expectType<Client<true>>(client)); +client.on('guildScheduledEventDelete', ({ client }) => expectType<Client<true>>(client)); + +client.on('guildScheduledEventUpdate', (oldGuildScheduledEvent, { client }) => { + expectType<Client<true>>(oldGuildScheduledEvent!.client); + expectType<Client<true>>(client); +}); + +client.on('guildScheduledEventUserAdd', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('guildScheduledEventUserRemove', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('guildUnavailable', ({ client }) => expectType<Client<true>>(client)); + +client.on('guildUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('interactionCreate', async interaction => { + expectType<Client<true>>(interaction.client); + expectType<Snowflake | null>(interaction.guildId); + expectType<Snowflake | null>(interaction.channelId); + expectType<GuildMember | APIInteractionGuildMember | null>(interaction.member); + + if (interaction.type === InteractionType.MessageComponent) { + expectType<Snowflake>(interaction.channelId); + } + + if (interaction.type !== InteractionType.ApplicationCommand) return; + + void new ActionRowBuilder<MessageActionRowComponentBuilder>(); + + const button = new ButtonBuilder(); + + const actionRow = new ActionRowBuilder<MessageActionRowComponentBuilder>({ + type: ComponentType.ActionRow, + components: [button.toJSON()], + }); + + actionRow.toJSON(); + + await interaction.reply({ content: 'Hi!', components: [actionRow] }); + + // @ts-expect-error + interaction.reply({ content: 'Hi!', components: [[button]] }); + + void new ActionRowBuilder({}); + + // @ts-expect-error + await interaction.reply({ content: 'Hi!', components: [button] }); + + await interaction.reply({ + content: 'test', + components: [ + { + components: [ + { + custom_id: 'abc', + label: 'abc', + style: ButtonStyle.Primary, + type: ComponentType.Button, + }, + ], + type: ComponentType.ActionRow, + }, + ], + }); + + // This is for testing never type resolution + if (!interaction.inGuild()) { + return; + } + + if (interaction.inRawGuild()) { + expectNotType<never>(interaction); + return; + } + + if (interaction.inCachedGuild()) { + expectNotType<never>(interaction); + return; + } +}); + +client.on('inviteCreate', ({ client }) => expectType<Client<true>>(client)); +client.on('inviteDelete', ({ client }) => expectType<Client<true>>(client)); + +// This is to check that stuff is the right type +declare const assertIsMessage: (m: Promise<Message>) => void; + +client.on('messageCreate', async message => { + const { client, channel } = message; + + // https://github.com/discordjs/discord.js/issues/8545 + { + // These should not throw any errors when comparing messages from any source. + channel.messages.cache.filter(m => m); + (await channel.messages.fetch()).filter(m => m.author.id === message.author.id); + + if (channel.isDMBased()) { + expectType<DMMessageManager>(channel.messages.channel.messages); + } else { + expectType<GuildMessageManager>(channel.messages.channel.messages); + } + } + + if (!message.inGuild() && message.partial) { + expectNotType<never>(message); + } + + expectType<Client<true>>(client); + assertIsMessage(channel.send('string')); + assertIsMessage(channel.send({})); + assertIsMessage(channel.send({ embeds: [] })); + + const attachment = new AttachmentBuilder('file.png'); + const embed = new EmbedBuilder(); + assertIsMessage(channel.send({ files: [attachment] })); + assertIsMessage(channel.send({ embeds: [embed] })); + assertIsMessage(channel.send({ embeds: [embed], files: [attachment] })); + + if (message.inGuild()) { + expectAssignable<Message<true>>(message); + const component = await message.awaitMessageComponent({ componentType: ComponentType.Button }); + expectType<ButtonInteraction<'cached'>>(component); + expectType<Message<true>>(await component.reply({ fetchReply: true })); + + const buttonCollector = message.createMessageComponentCollector({ componentType: ComponentType.Button }); + expectType<InteractionCollector<ButtonInteraction<'cached'>>>(buttonCollector); + expectAssignable< + ( + test: ButtonInteraction<'cached'>, + items: Collection<Snowflake, ButtonInteraction<'cached'>>, + ) => boolean | Promise<boolean> + >(buttonCollector.filter); + expectType<GuildTextBasedChannel>(message.channel); + expectType<Guild>(message.guild); + expectType<GuildMember | null>(message.member); + + expectType<MessageMentions<true>>(message.mentions); + expectType<Guild>(message.guild); + expectType<Collection<Snowflake, GuildMember>>(message.mentions.members); + } + + expectType<TextBasedChannel>(message.channel); + expectNotType<GuildTextBasedChannel>(message.channel); + + // @ts-expect-error + channel.send(); + // @ts-expect-error + channel.send({ another: 'property' }); + + // Check collector creations. + + // Verify that buttons interactions are inferred. + const buttonCollector = message.createMessageComponentCollector({ componentType: ComponentType.Button }); + expectAssignable<Promise<ButtonInteraction>>(message.awaitMessageComponent({ componentType: ComponentType.Button })); + expectAssignable<Promise<ButtonInteraction>>(channel.awaitMessageComponent({ componentType: ComponentType.Button })); + expectAssignable<InteractionCollector<ButtonInteraction>>(buttonCollector); + + // Verify that select menus interaction are inferred. + const selectMenuCollector = message.createMessageComponentCollector({ componentType: ComponentType.StringSelect }); + expectAssignable<Promise<StringSelectMenuInteraction>>( + message.awaitMessageComponent({ componentType: ComponentType.StringSelect }), + ); + expectAssignable<Promise<StringSelectMenuInteraction>>( + channel.awaitMessageComponent({ componentType: ComponentType.StringSelect }), + ); + expectAssignable<InteractionCollector<StringSelectMenuInteraction>>(selectMenuCollector); + + // Verify that message component interactions are default collected types. + const defaultCollector = message.createMessageComponentCollector(); + expectAssignable<Promise<MessageComponentInteraction>>(message.awaitMessageComponent()); + expectAssignable<Promise<MessageComponentInteraction>>(channel.awaitMessageComponent()); + expectAssignable<InteractionCollector<CollectedMessageInteraction>>(defaultCollector); + + // Verify that additional options don't affect default collector types. + const semiDefaultCollector = message.createMessageComponentCollector({ time: 10000 }); + expectType<InteractionCollector<CollectedMessageInteraction>>(semiDefaultCollector); + const semiDefaultCollectorChannel = message.createMessageComponentCollector({ time: 10000 }); + expectType<InteractionCollector<CollectedMessageInteraction>>(semiDefaultCollectorChannel); + + // Verify that interaction collector options can't be used. + message.createMessageComponentCollector({ + // @ts-expect-error + interactionType: InteractionType.ApplicationCommand, + }); + + // Make sure filter parameters are properly inferred. + message.createMessageComponentCollector({ + filter: i => { + expectType<CollectedMessageInteraction>(i); + return true; + }, + }); + + message.createMessageComponentCollector({ + componentType: ComponentType.Button, + filter: i => { + expectType<ButtonInteraction>(i); + return true; + }, + }); + + message.createMessageComponentCollector({ + componentType: ComponentType.StringSelect, + filter: i => { + expectType<StringSelectMenuInteraction>(i); + return true; + }, + }); + + message.awaitMessageComponent({ + filter: i => { + expectType<CollectedMessageInteraction>(i); + return true; + }, + }); + + message.awaitMessageComponent({ + componentType: ComponentType.Button, + filter: i => { + expectType<ButtonInteraction>(i); + return true; + }, + }); + + message.awaitMessageComponent({ + componentType: ComponentType.StringSelect, + filter: i => { + expectType<StringSelectMenuInteraction>(i); + return true; + }, + }); + + const webhook = await message.fetchWebhook(); + + if (webhook.isChannelFollower()) { + expectAssignable<Guild | APIPartialGuild>(webhook.sourceGuild); + expectAssignable<NewsChannel | APIPartialChannel>(webhook.sourceChannel); + } else if (webhook.isIncoming()) { + expectType<string>(webhook.token); + } + + expectNotType<Guild | APIPartialGuild>(webhook.sourceGuild); + expectNotType<NewsChannel | APIPartialChannel>(webhook.sourceChannel); + expectNotType<string>(webhook.token); + + channel.awaitMessageComponent({ + filter: i => { + expectType<CollectedMessageInteraction<'cached'>>(i); + return true; + }, + }); + + channel.awaitMessageComponent({ + componentType: ComponentType.Button, + filter: i => { + expectType<ButtonInteraction<'cached'>>(i); + return true; + }, + }); + + channel.awaitMessageComponent({ + componentType: ComponentType.StringSelect, + filter: i => { + expectType<StringSelectMenuInteraction<'cached'>>(i); + return true; + }, + }); + + // Check that both builders and builder data can be sent in messages + const row = new ActionRowBuilder<MessageActionRowComponentBuilder>(); + + const rawButtonsRow: ActionRowData<ButtonComponentData> = { + type: ComponentType.ActionRow, + components: [ + { type: ComponentType.Button, label: 'test', style: ButtonStyle.Primary, customId: 'test' }, + { + type: ComponentType.Button, + label: 'another test', + style: ButtonStyle.Link, + url: 'https://discord.js.org', + }, + ], + }; + + const buttonsRow: ActionRowData<ButtonBuilder> = { + type: ComponentType.ActionRow, + components: [new ButtonBuilder()], + }; + + const rawStringSelectMenuRow: ActionRowData<StringSelectMenuComponentData> = { + type: ComponentType.ActionRow, + components: [ + { + type: ComponentType.StringSelect, + options: [{ label: 'test', value: 'test' }], + customId: 'test', + }, + ], + }; + + const stringSelectRow: ActionRowData<StringSelectMenuBuilder> = { + type: ComponentType.ActionRow, + components: [new StringSelectMenuBuilder()], + }; + + const embedData = { description: 'test', color: 0xff0000 }; + + channel.send({ + components: [row, rawButtonsRow, buttonsRow, rawStringSelectMenuRow, stringSelectRow], + embeds: [embed, embedData], + }); +}); + +client.on('messageDelete', ({ client }) => expectType<Client<true>>(client)); + +client.on('messageDeleteBulk', (messages, { client }) => { + expectType<Client<true>>(messages.first()!.client); + expectType<Client<true>>(client); +}); + +client.on('messageReactionAdd', async (reaction, { client }) => { + expectType<Client<true>>(reaction.client); + expectType<Client<true>>(client); + + if (reaction.partial) { + expectType<null>(reaction.count); + reaction = await reaction.fetch(); + } + + expectType<number>(reaction.count); + if (reaction.message.partial) return expectType<string | null>(reaction.message.content); + expectType<string>(reaction.message.content); +}); + +client.on('messageReactionRemove', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('messageReactionRemoveAll', async (message, reactions) => { + console.log(`messageReactionRemoveAll - id: ${message.id} (${message.id.length})`); + if (message.partial) message = await message.fetch(); + console.log(`messageReactionRemoveAll - content: ${message.content}`); + expectType<Client<true>>(message.client); + expectType<Client<true>>(reactions.first()!.client); +}); + +client.on('messageReactionRemoveEmoji', ({ client }) => expectType<Client<true>>(client)); + +client.on('messageUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('presenceUpdate', (oldPresence, { client }) => { + expectType<Client<true>>(oldPresence!.client); + expectType<Client<true>>(client); +}); + +declare const slashCommandBuilder: SlashCommandBuilder; +declare const contextMenuCommandBuilder: ContextMenuCommandBuilder; + +client.on('ready', async client => { + expectType<Client<true>>(client); + console.log(`Client is logged in as ${client.user.tag} and ready!`); + + // Test fetching all global commands and ones from one guild + expectType<Collection<string, ApplicationCommand<{ guild: GuildResolvable }>>>( + await client.application!.commands.fetch(), + ); + expectType<Collection<string, ApplicationCommand<{ guild: GuildResolvable }>>>( + await client.application!.commands.fetch({ guildId: testGuildId }), + ); + + // Test command manager methods + const globalCommand = await client.application?.commands.fetch(globalCommandId); + const guildCommandFromGlobal = await client.application?.commands.fetch(guildCommandId, { guildId: testGuildId }); + const guildCommandFromGuild = await client.guilds.cache.get(testGuildId)?.commands.fetch(guildCommandId); + + await client.application?.commands.create(slashCommandBuilder); + await client.application?.commands.create(contextMenuCommandBuilder); + await guild.commands.create(slashCommandBuilder); + await guild.commands.create(contextMenuCommandBuilder); + + await client.application?.commands.edit(globalCommandId, slashCommandBuilder); + await client.application?.commands.edit(globalCommandId, contextMenuCommandBuilder); + await guild.commands.edit(guildCommandId, slashCommandBuilder); + await guild.commands.edit(guildCommandId, contextMenuCommandBuilder); + + await client.application?.commands.edit(globalCommandId, { defaultMemberPermissions: null }); + await globalCommand?.edit({ defaultMemberPermissions: null }); + await globalCommand?.setDefaultMemberPermissions(null); + await guildCommandFromGlobal?.edit({ dmPermission: false }); + + // @ts-expect-error + await client.guilds.cache.get(testGuildId)?.commands.fetch(guildCommandId, { guildId: testGuildId }); + + // Test command permissions + const globalPermissionsManager = client.application?.commands.permissions; + const guildPermissionsManager = client.guilds.cache.get(testGuildId)?.commands.permissions; + + // Permissions from global manager + await globalPermissionsManager?.add({ + command: globalCommandId, + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + await globalPermissionsManager?.has({ command: globalCommandId, guild: testGuildId, permissionId: testGuildId }); + await globalPermissionsManager?.fetch({ guild: testGuildId }); + await globalPermissionsManager?.fetch({ command: globalCommandId, guild: testGuildId }); + await globalPermissionsManager?.remove({ + command: globalCommandId, + guild: testGuildId, + roles: [testGuildId], + token: 'VeryRealToken', + }); + await globalPermissionsManager?.remove({ + command: globalCommandId, + guild: testGuildId, + users: [testUserId], + token: 'VeryRealToken', + }); + await globalPermissionsManager?.remove({ + command: globalCommandId, + guild: testGuildId, + channels: [testGuildId], + token: 'VeryRealToken', + }); + await globalPermissionsManager?.remove({ + command: globalCommandId, + guild: testGuildId, + roles: [testGuildId], + users: [testUserId], + channels: [testGuildId], + token: 'VeryRealToken', + }); + await globalPermissionsManager?.set({ + command: globalCommandId, + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + // @ts-expect-error + await globalPermissionsManager?.add({ + command: globalCommandId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + // @ts-expect-error + await globalPermissionsManager?.has({ command: globalCommandId, permissionId: testGuildId }); + // @ts-expect-error + await globalPermissionsManager?.fetch(); + // @ts-expect-error + await globalPermissionsManager?.fetch({ command: globalCommandId }); + // @ts-expect-error + await globalPermissionsManager?.remove({ command: globalCommandId, roles: [testGuildId], token: 'VeryRealToken' }); + // @ts-expect-error + await globalPermissionsManager?.remove({ command: globalCommandId, users: [testUserId], token: 'VeryRealToken' }); + // @ts-expect-error + await globalPermissionsManager?.remove({ + command: globalCommandId, + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + // @ts-expect-error + await globalPermissionsManager?.set({ + command: globalCommandId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + // @ts-expect-error + await globalPermissionsManager?.add({ + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + // @ts-expect-error + await globalPermissionsManager?.has({ guild: testGuildId, permissionId: testGuildId }); + // @ts-expect-error + await globalPermissionsManager?.remove({ guild: testGuildId, roles: [testGuildId], token: 'VeryRealToken' }); + // @ts-expect-error + await globalPermissionsManager?.remove({ guild: testGuildId, users: [testUserId], token: 'VeryRealToken' }); + // @ts-expect-error + await globalPermissionsManager?.remove({ + guild: testGuildId, + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + // @ts-expect-error + await globalPermissionsManager?.set({ + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + // Permissions from guild manager + await guildPermissionsManager?.add({ + command: globalCommandId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + await guildPermissionsManager?.has({ command: globalCommandId, permissionId: testGuildId }); + await guildPermissionsManager?.fetch({}); + await guildPermissionsManager?.fetch({ command: globalCommandId }); + await guildPermissionsManager?.remove({ command: globalCommandId, roles: [testGuildId], token: 'VeryRealToken' }); + await guildPermissionsManager?.remove({ command: globalCommandId, users: [testUserId], token: 'VeryRealToken' }); + await guildPermissionsManager?.remove({ command: globalCommandId, channels: [testGuildId], token: 'VeryRealToken' }); + await guildPermissionsManager?.remove({ + command: globalCommandId, + roles: [testGuildId], + users: [testUserId], + channels: [testGuildId], + token: 'VeryRealToken', + }); + await guildPermissionsManager?.set({ + command: globalCommandId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + await guildPermissionsManager?.add({ + command: globalCommandId, + // @ts-expect-error + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + // @ts-expect-error + await guildPermissionsManager?.has({ command: globalCommandId, guild: testGuildId, permissionId: testGuildId }); + // @ts-expect-error + await guildPermissionsManager?.fetch({ guild: testGuildId }); + // @ts-expect-error + await guildPermissionsManager?.fetch({ command: globalCommandId, guild: testGuildId }); + await guildPermissionsManager?.remove({ + command: globalCommandId, + // @ts-expect-error + guild: testGuildId, + roles: [testGuildId], + token: 'VeryRealToken', + }); + await guildPermissionsManager?.remove({ + command: globalCommandId, + // @ts-expect-error + guild: testGuildId, + users: [testUserId], + token: 'VeryRealToken', + }); + await guildPermissionsManager?.remove({ + command: globalCommandId, + // @ts-expect-error + guild: testGuildId, + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + await guildPermissionsManager?.set({ + command: globalCommandId, + // @ts-expect-error + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + // @ts-expect-error + await guildPermissionsManager?.add({ + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + // @ts-expect-error + await guildPermissionsManager?.has({ permissionId: testGuildId }); + // @ts-expect-error + await guildPermissionsManager?.remove({ roles: [testGuildId], token: 'VeryRealToken' }); + // @ts-expect-error + await guildPermissionsManager?.remove({ users: [testUserId], token: 'VeryRealToken' }); + // @ts-expect-error + await guildPermissionsManager?.remove({ roles: [testGuildId], users: [testUserId], token: 'VeryRealToken' }); + // @ts-expect-error + await guildPermissionsManager?.set({ + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + // Permissions from cached global ApplicationCommand + await globalCommand?.permissions.add({ + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + await globalCommand?.permissions.has({ guild: testGuildId, permissionId: testGuildId }); + await globalCommand?.permissions.fetch({ guild: testGuildId }); + await globalCommand?.permissions.remove({ guild: testGuildId, roles: [testGuildId], token: 'VeryRealToken' }); + await globalCommand?.permissions.remove({ guild: testGuildId, users: [testUserId], token: 'VeryRealToken' }); + await globalCommand?.permissions.remove({ + guild: testGuildId, + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + await globalCommand?.permissions.set({ + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + await globalCommand?.permissions.add({ + // @ts-expect-error + command: globalCommandId, + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + await globalCommand?.permissions.has({ + // @ts-expect-error + command: globalCommandId, + guild: testGuildId, + permissionId: testGuildId, + token: 'VeryRealToken', + }); + // @ts-expect-error + await globalCommand?.permissions.fetch({ command: globalCommandId, guild: testGuildId, token: 'VeryRealToken' }); + await globalCommand?.permissions.remove({ + // @ts-expect-error + command: globalCommandId, + guild: testGuildId, + roles: [testGuildId], + token: 'VeryRealToken', + }); + await globalCommand?.permissions.remove({ + // @ts-expect-error + command: globalCommandId, + guild: testGuildId, + users: [testUserId], + token: 'VeryRealToken', + }); + await globalCommand?.permissions.remove({ + // @ts-expect-error + command: globalCommandId, + guild: testGuildId, + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + await globalCommand?.permissions.set({ + // @ts-expect-error + command: globalCommandId, + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + // @ts-expect-error + await globalCommand?.permissions.add({ + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + // @ts-expect-error + await globalCommand?.permissions.has({ permissionId: testGuildId }); + // @ts-expect-error + await globalCommand?.permissions.fetch({}); + // @ts-expect-error + await globalCommand?.permissions.remove({ roles: [testGuildId], token: 'VeryRealToken' }); + // @ts-expect-error + await globalCommand?.permissions.remove({ users: [testUserId], token: 'VeryRealToken' }); + // @ts-expect-error + await globalCommand?.permissions.remove({ roles: [testGuildId], users: [testUserId], token: 'VeryRealToken' }); + // @ts-expect-error + await globalCommand?.permissions.set({ + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + }); + + // Permissions from cached guild ApplicationCommand + await guildCommandFromGlobal?.permissions.add({ + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + await guildCommandFromGlobal?.permissions.has({ permissionId: testGuildId }); + await guildCommandFromGlobal?.permissions.fetch({}); + await guildCommandFromGlobal?.permissions.remove({ roles: [testGuildId], token: 'VeryRealToken' }); + await guildCommandFromGlobal?.permissions.remove({ users: [testUserId], token: 'VeryRealToken' }); + await guildCommandFromGlobal?.permissions.remove({ + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + await guildCommandFromGlobal?.permissions.set({ + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + await guildCommandFromGlobal?.permissions.add({ + // @ts-expect-error + command: globalCommandId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + // @ts-expect-error + await guildCommandFromGlobal?.permissions.has({ command: guildCommandId, permissionId: testGuildId }); + await guildCommandFromGlobal?.permissions.remove({ + // @ts-expect-error + command: guildCommandId, + roles: [testGuildId], + token: 'VeryRealToken', + }); + await guildCommandFromGlobal?.permissions.remove({ + // @ts-expect-error + command: guildCommandId, + users: [testUserId], + token: 'VeryRealToken', + }); + await guildCommandFromGlobal?.permissions.remove({ + // @ts-expect-error + command: guildCommandId, + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + await guildCommandFromGlobal?.permissions.set({ + // @ts-expect-error + command: guildCommandId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + await guildCommandFromGlobal?.permissions.add({ + // @ts-expect-error + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + // @ts-expect-error + await guildCommandFromGlobal?.permissions.has({ guild: testGuildId, permissionId: testGuildId }); + await guildCommandFromGlobal?.permissions.remove({ + // @ts-expect-error + guild: testGuildId, + roles: [testGuildId], + token: 'VeryRealToken', + }); + // @ts-expect-error + await guildCommandFromGlobal?.permissions.remove({ guild: testGuildId, users: [testUserId], token: 'VeryRealToken' }); + await guildCommandFromGlobal?.permissions.remove({ + // @ts-expect-error + guild: testGuildId, + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + await guildCommandFromGlobal?.permissions.set({ + // @ts-expect-error + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + await guildCommandFromGuild?.permissions.add({ + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + await guildCommandFromGuild?.permissions.has({ permissionId: testGuildId }); + await guildCommandFromGuild?.permissions.fetch({}); + await guildCommandFromGuild?.permissions.remove({ roles: [testGuildId], token: 'VeryRealToken' }); + await guildCommandFromGuild?.permissions.remove({ users: [testUserId], token: 'VeryRealToken' }); + await guildCommandFromGuild?.permissions.remove({ + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + await guildCommandFromGuild?.permissions.set({ + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + await guildCommandFromGuild?.permissions.add({ + // @ts-expect-error + command: globalCommandId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + // @ts-expect-error + await guildCommandFromGuild?.permissions.has({ command: guildCommandId, permissionId: testGuildId }); + await guildCommandFromGuild?.permissions.remove({ + // @ts-expect-error + command: guildCommandId, + roles: [testGuildId], + token: 'VeryRealToken', + }); + await guildCommandFromGuild?.permissions.remove({ + // @ts-expect-error + command: guildCommandId, + users: [testUserId], + token: 'VeryRealToken', + }); + await guildCommandFromGuild?.permissions.remove({ + // @ts-expect-error + command: guildCommandId, + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + await guildCommandFromGuild?.permissions.set({ + // @ts-expect-error + command: guildCommandId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + + await guildCommandFromGuild?.permissions.add({ + // @ts-expect-error + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); + // @ts-expect-error + await guildCommandFromGuild?.permissions.has({ guild: testGuildId, permissionId: testGuildId }); + // @ts-expect-error + await guildCommandFromGuild?.permissions.remove({ guild: testGuildId, roles: [testGuildId], token: 'VeryRealToken' }); + // @ts-expect-error + await guildCommandFromGuild?.permissions.remove({ guild: testGuildId, users: [testUserId], token: 'VeryRealToken' }); + await guildCommandFromGuild?.permissions.remove({ + // @ts-expect-error + guild: testGuildId, + roles: [testGuildId], + users: [testUserId], + token: 'VeryRealToken', + }); + await guildCommandFromGuild?.permissions.set({ + // @ts-expect-error + guild: testGuildId, + permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }], + token: 'VeryRealToken', + }); +}); + +client.on('roleCreate', ({ client }) => expectType<Client<true>>(client)); +client.on('roleDelete', ({ client }) => expectType<Client<true>>(client)); + +client.on('roleUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('stageInstanceCreate', ({ client }) => expectType<Client<true>>(client)); +client.on('stageInstanceDelete', ({ client }) => expectType<Client<true>>(client)); + +client.on('stageInstanceUpdate', (oldStageInstance, { client }) => { + expectType<Client<true>>(oldStageInstance!.client); + expectType<Client<true>>(client); +}); + +client.on('stickerCreate', ({ client }) => expectType<Client<true>>(client)); +client.on('stickerDelete', ({ client }) => expectType<Client<true>>(client)); + +client.on('stickerUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('threadCreate', thread => { + expectType<Client<true>>(thread.client); + + if (thread.type === ChannelType.PrivateThread) { + expectType<number>(thread.createdTimestamp); + expectType<Date>(thread.createdAt); + } else { + expectType<number | null>(thread.createdTimestamp); + expectType<Date | null>(thread.createdAt); + } +}); + +client.on('threadDelete', ({ client }) => expectType<Client<true>>(client)); + +client.on('threadListSync', (threads, { client }) => { + expectType<Client<true>>(threads.first()!.client); + expectType<Client<true>>(client); +}); + +client.on('threadMembersUpdate', (addedMembers, removedMembers, thread) => { + expectType<Client<true>>(addedMembers.first()!.client); + expectType<Client<true>>(removedMembers.first()!.client); + expectType<Client<true>>(thread.client); + expectType<Collection<Snowflake, ThreadMember>>(addedMembers); + expectType<Collection<Snowflake, ThreadMember | PartialThreadMember>>(removedMembers); + expectType<AnyThreadChannel>(thread); + const left = removedMembers.first(); + if (!left) return; + + if (left.partial) { + expectType<PartialThreadMember>(left); + expectType<null>(left.flags); + } else { + expectType<ThreadMember>(left); + expectType<ThreadMemberFlagsBitField>(left.flags); + } +}); + +client.on('threadMemberUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('threadUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('typingStart', ({ client }) => expectType<Client<true>>(client)); + +client.on('userUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('voiceStateUpdate', ({ client: oldClient }, { client: newClient }) => { + expectType<Client<true>>(oldClient); + expectType<Client<true>>(newClient); +}); + +client.on('webhooksUpdate', ({ client }) => expectType<Client<true>>(client)); + +client.on('guildCreate', async g => { + expectType<Client<true>>(g.client); + const channel = g.channels.cache.random(); + if (!channel) return; + + if (channel.type === ChannelType.GuildText) { + const row: ActionRowData<MessageActionRowComponentData> = { + type: ComponentType.ActionRow, + components: [ + new ButtonBuilder(), + { type: ComponentType.Button, style: ButtonStyle.Primary, label: 'string', customId: 'foo' }, + { type: ComponentType.Button, style: ButtonStyle.Link, label: 'test', url: 'test' }, + { type: ComponentType.StringSelect, customId: 'foo', options: [{ label: 'label', value: 'value' }] }, + new StringSelectMenuBuilder(), + // @ts-expect-error + { type: ComponentType.TextInput, style: TextInputStyle.Paragraph, customId: 'foo', label: 'test' }, + // @ts-expect-error + new TextInputBuilder(), + ], + }; + + const row2 = new ActionRowBuilder<MessageActionRowComponentBuilder>({ + type: ComponentType.ActionRow, + components: [ + { type: ComponentType.Button, style: ButtonStyle.Primary, label: 'string', customId: 'foo' }, + { type: ComponentType.Button, style: ButtonStyle.Link, label: 'test', url: 'test' }, + { type: ComponentType.StringSelect, customId: 'foo', options: [{ label: 'label', value: 'value' }] }, + ], + }); + + channel.send({ components: [row, row2] }); + } + + channel.setName('foo').then(updatedChannel => { + console.log(`New channel name: ${updatedChannel.name}`); + }); + + // @ts-expect-error no options + expectNotType<Promise<GuildMember>>(g.members.add(testUserId)); + + // @ts-expect-error no access token + expectNotType<Promise<GuildMember>>(g.members.add(testUserId, {})); + + expectNotType<Promise<GuildMember>>( + // @ts-expect-error invalid role resolvable + g.members.add(testUserId, { accessToken: 'totallyRealAccessToken', roles: [g.roles.cache] }), + ); + + expectType<Promise<GuildMember | null>>( + g.members.add(testUserId, { accessToken: 'totallyRealAccessToken', fetchWhenExisting: false }), + ); + + expectType<Promise<GuildMember>>(g.members.add(testUserId, { accessToken: 'totallyRealAccessToken' })); + + expectType<Promise<GuildMember>>( + g.members.add(testUserId, { + accessToken: 'totallyRealAccessToken', + mute: true, + deaf: false, + roles: [g.roles.cache.first()!], + force: true, + fetchWhenExisting: true, + }), + ); +}); + +client.login('absolutely-valid-token'); + +declare const loggedInClient: Client<true>; +expectType<ClientApplication>(loggedInClient.application); +expectType<Date>(loggedInClient.readyAt); +expectType<number>(loggedInClient.readyTimestamp); +expectType<string>(loggedInClient.token); +expectType<number>(loggedInClient.uptime); +expectType<ClientUser>(loggedInClient.user); + +declare const loggedOutClient: Client<false>; +expectType<null>(loggedOutClient.application); +expectType<null>(loggedOutClient.readyAt); +expectType<null>(loggedOutClient.readyTimestamp); +expectType<string | null>(loggedOutClient.token); +expectType<null>(loggedOutClient.uptime); +expectType<null>(loggedOutClient.user); + +expectType<undefined>(serialize(undefined)); +expectType<null>(serialize(null)); +expectType<number[]>(serialize([1, 2, 3])); +expectType<{}>(serialize(new Set([1, 2, 3]))); +expectType<{}>( + serialize( + new Map([ + [1, '2'], + [2, '4'], + ]), + ), +); +expectType<string>(serialize(new PermissionsBitField(PermissionFlagsBits.AttachFiles))); +expectType<number>(serialize(new IntentsBitField(GatewayIntentBits.Guilds))); +expectAssignable<unknown>( + serialize( + new Collection([ + [1, '2'], + [2, '4'], + ]), + ), +); +expectType<never>(serialize(Symbol('a'))); +expectType<never>(serialize(() => {})); +expectType<never>(serialize(BigInt(42))); + +// Test type return of broadcastEval: +declare const shardClientUtil: ShardClientUtil; +declare const shardingManager: ShardingManager; + +expectType<Promise<number[]>>(shardingManager.broadcastEval(() => 1)); +expectType<Promise<number[]>>(shardClientUtil.broadcastEval(() => 1)); +expectType<Promise<number[]>>(shardingManager.broadcastEval(async () => 1)); +expectType<Promise<number[]>>(shardClientUtil.broadcastEval(async () => 1)); + +declare const dmChannel: DMChannel; +declare const threadChannel: ThreadChannel; +declare const threadChannelFromForum: ThreadChannel<true>; +declare const threadChannelNotFromForum: ThreadChannel<false>; +declare const newsChannel: NewsChannel; +declare const textChannel: TextChannel; +declare const voiceChannel: VoiceChannel; +declare const guild: Guild; +declare const user: User; +declare const guildMember: GuildMember; + +// Test thread channels' parent inference +expectType<TextChannel | NewsChannel | ForumChannel | null>(threadChannel.parent); +expectType<ForumChannel | null>(threadChannelFromForum.parent); +expectType<TextChannel | NewsChannel | null>(threadChannelNotFromForum.parent); + +// Test whether the structures implement send +expectType<TextBasedChannelFields<false>['send']>(dmChannel.send); +expectType<TextBasedChannelFields<true>['send']>(threadChannel.send); +expectType<TextBasedChannelFields<true>['send']>(newsChannel.send); +expectType<TextBasedChannelFields<true>['send']>(textChannel.send); +expectType<TextBasedChannelFields<true>['send']>(voiceChannel.send); +expectAssignable<PartialTextBasedChannelFields>(user); +expectAssignable<PartialTextBasedChannelFields>(guildMember); + +expectType<Promise<NewsChannel>>(textChannel.setType(ChannelType.GuildAnnouncement)); +expectType<Promise<TextChannel>>(newsChannel.setType(ChannelType.GuildText)); + +expectType<Message | null>(dmChannel.lastMessage); +expectType<Message | null>(threadChannel.lastMessage); +expectType<Message | null>(newsChannel.lastMessage); +expectType<Message | null>(textChannel.lastMessage); +expectType<Message | null>(voiceChannel.lastMessage); + +notPropertyOf(user, 'lastMessage'); +notPropertyOf(user, 'lastMessageId'); +notPropertyOf(guildMember, 'lastMessage'); +notPropertyOf(guildMember, 'lastMessageId'); + +// Test collector event parameters +declare const messageCollector: MessageCollector; +messageCollector.on('collect', (...args) => { + expectType<[Message, Collection<Snowflake, Message>]>(args); +}); + +(async () => { + for await (const value of messageCollector) { + expectType<[Message<boolean>, Collection<Snowflake, Message>]>(value); + } +})(); + +declare const reactionCollector: ReactionCollector; +reactionCollector.on('dispose', (...args) => { + expectType<[MessageReaction, User]>(args); +}); + +(async () => { + for await (const value of reactionCollector) { + expectType<[MessageReaction, User]>(value); + } +})(); + +// Make sure the properties are typed correctly, and that no backwards properties +// (K -> V and V -> K) exist: +expectAssignable<'messageCreate'>(Events.MessageCreate); +expectAssignable<'close'>(WebSocketShardEvents.Close); +expectAssignable<'death'>(ShardEvents.Death); +expectAssignable<1>(Status.Connecting); + +declare const applicationCommandData: ApplicationCommandData; +declare const applicationCommandOptionData: ApplicationCommandOptionData; +declare const applicationCommandResolvable: ApplicationCommandResolvable; +declare const applicationCommandManager: ApplicationCommandManager; +{ + type ApplicationCommandScope = ApplicationCommand<{ guild: GuildResolvable }>; + + expectType<Promise<ApplicationCommandScope>>(applicationCommandManager.create(applicationCommandData)); + expectAssignable<Promise<ApplicationCommand>>(applicationCommandManager.create(applicationCommandData, '0')); + expectType<Promise<ApplicationCommandScope>>( + applicationCommandManager.edit(applicationCommandResolvable, applicationCommandData), + ); + expectType<Promise<ApplicationCommand>>( + applicationCommandManager.edit(applicationCommandResolvable, applicationCommandData, '0'), + ); + expectType<Promise<Collection<Snowflake, ApplicationCommandScope>>>( + applicationCommandManager.set([applicationCommandData]), + ); + expectType<Promise<Collection<Snowflake, ApplicationCommand>>>( + applicationCommandManager.set([applicationCommandData] as const, '0'), + ); + + // Test inference of choice values. + if ('choices' in applicationCommandOptionData) { + if (applicationCommandOptionData.type === ApplicationCommandOptionType.String) { + expectType<string>(applicationCommandOptionData.choices[0]!.value); + expectNotType<number>(applicationCommandOptionData.choices[0]!.value); + } + + if (applicationCommandOptionData.type === ApplicationCommandOptionType.Integer) { + expectType<number>(applicationCommandOptionData.choices[0]!.value); + expectNotType<string>(applicationCommandOptionData.choices[0]!.value); + } + + if (applicationCommandOptionData.type === ApplicationCommandOptionType.Number) { + expectType<number>(applicationCommandOptionData.choices[0]!.value); + expectNotType<string>(applicationCommandOptionData.choices[0]!.value); + } + } +} + +declare const applicationCommandPermissionsManager: ApplicationCommandPermissionsManager< + {}, + {}, + Guild | null, + Snowflake +>; +{ + applicationCommandPermissionsManager.add({ permissions: [], token: '' }); + applicationCommandPermissionsManager.add({ permissions: [] as const, token: '' }); + applicationCommandPermissionsManager.set({ permissions: [], token: '' }); + applicationCommandPermissionsManager.set({ permissions: [] as const, token: '' }); + applicationCommandPermissionsManager.remove({ channels: [], roles: [], users: [], token: '' }); + + applicationCommandPermissionsManager.remove({ + channels: [] as const, + roles: [] as const, + users: [] as const, + token: '', + }); +} + +declare const chatInputApplicationCommandData: ChatInputApplicationCommandData; +{ + chatInputApplicationCommandData.options = []; + chatInputApplicationCommandData.options = [] as const; +} + +declare const applicationCommandChannelOptionData: ApplicationCommandChannelOptionData; +declare const applicationCommandChannelOption: ApplicationCommandChannelOption; +{ + applicationCommandChannelOptionData.channelTypes = [] as const; + applicationCommandChannelOptionData.channel_types = [] as const; + applicationCommandChannelOption.channelTypes = [] as const; +} + +declare const applicationNonChoiceOptionData: ApplicationCommandOptionData & { + type: CommandOptionNonChoiceResolvableType; +}; +{ + // Options aren't allowed on this command type. + + // @ts-expect-error + applicationNonChoiceOptionData.choices; +} + +declare const applicationCommandChoicesData: ApplicationCommandChoicesData; +declare const applicationCommandChoicesOption: ApplicationCommandChoicesOption; +{ + applicationCommandChoicesData.choices = []; + applicationCommandChoicesData.choices = [] as const; + applicationCommandChoicesOption.choices = []; + applicationCommandChoicesOption.choices = [] as const; +} + +declare const applicationCommandSubCommandData: ApplicationCommandSubCommandData; +declare const applicationCommandSubCommand: ApplicationCommandSubCommand; +{ + applicationCommandSubCommandData.options = []; + applicationCommandSubCommandData.options = [] as const; + applicationCommandSubCommand.options = []; + applicationCommandSubCommand.options = [] as const; +} + +declare const applicationSubGroupCommandData: ApplicationCommandSubGroupData; +declare const applicationCommandSubGroup: ApplicationCommandSubGroup; +{ + expectType<ApplicationCommandOptionType.SubcommandGroup>(applicationSubGroupCommandData.type); + applicationSubGroupCommandData.options = []; + applicationSubGroupCommandData.options = [] as const; + applicationCommandSubGroup.options = []; + applicationCommandSubGroup.options = [] as const; +} + +declare const autoModerationRuleManager: AutoModerationRuleManager; +{ + expectType<Promise<AutoModerationRule>>(autoModerationRuleManager.fetch('1234567890')); + expectType<Promise<AutoModerationRule>>(autoModerationRuleManager.fetch({ autoModerationRule: '1234567890' })); + expectType<Promise<AutoModerationRule>>( + autoModerationRuleManager.fetch({ autoModerationRule: '1234567890', cache: false }), + ); + expectType<Promise<AutoModerationRule>>( + autoModerationRuleManager.fetch({ autoModerationRule: '1234567890', force: true }), + ); + expectType<Promise<AutoModerationRule>>( + autoModerationRuleManager.fetch({ autoModerationRule: '1234567890', cache: false, force: true }), + ); + expectType<Promise<Collection<Snowflake, AutoModerationRule>>>(autoModerationRuleManager.fetch()); + expectType<Promise<Collection<Snowflake, AutoModerationRule>>>(autoModerationRuleManager.fetch({})); + expectType<Promise<Collection<Snowflake, AutoModerationRule>>>(autoModerationRuleManager.fetch({ cache: false })); + // @ts-expect-error The `force` option cannot be used alongside fetching all auto moderation rules. + autoModerationRuleManager.fetch({ force: false }); +} + +declare const guildApplicationCommandManager: GuildApplicationCommandManager; +expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(guildApplicationCommandManager.fetch()); +expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(guildApplicationCommandManager.fetch(undefined, {})); +expectType<Promise<ApplicationCommand>>(guildApplicationCommandManager.fetch('0')); + +declare const categoryChannelChildManager: CategoryChannelChildManager; +{ + expectType<Promise<VoiceChannel>>(categoryChannelChildManager.create({ name: 'name', type: ChannelType.GuildVoice })); + expectType<Promise<TextChannel>>(categoryChannelChildManager.create({ name: 'name', type: ChannelType.GuildText })); + expectType<Promise<NewsChannel>>( + categoryChannelChildManager.create({ name: 'name', type: ChannelType.GuildAnnouncement }), + ); + expectType<Promise<StageChannel>>( + categoryChannelChildManager.create({ name: 'name', type: ChannelType.GuildStageVoice }), + ); + expectType<Promise<TextChannel>>(categoryChannelChildManager.create({ name: 'name' })); + expectType<Promise<TextChannel>>(categoryChannelChildManager.create({ name: 'name' })); +} + +declare const guildChannelManager: GuildChannelManager; +{ + expectType<Promise<TextChannel>>(guildChannelManager.create({ name: 'name' })); + expectType<Promise<TextChannel>>(guildChannelManager.create({ name: 'name' })); + expectType<Promise<VoiceChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildVoice })); + expectType<Promise<CategoryChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildCategory })); + expectType<Promise<TextChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildText })); + expectType<Promise<NewsChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildAnnouncement })); + expectType<Promise<StageChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildStageVoice })); + expectType<Promise<ForumChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildForum })); + + expectType<Promise<Collection<Snowflake, NonThreadGuildBasedChannel | null>>>(guildChannelManager.fetch()); + expectType<Promise<Collection<Snowflake, NonThreadGuildBasedChannel | null>>>( + guildChannelManager.fetch(undefined, {}), + ); + expectType<Promise<GuildBasedChannel | null>>(guildChannelManager.fetch('0')); + + const channel = guildChannelManager.cache.first()!; + + if (channel.isTextBased()) { + const { messages } = channel; + const message = await messages.fetch('123'); + expectType<GuildMessageManager>(messages); + expectType<Promise<Message<true>>>(messages.crosspost('1234567890')); + expectType<Promise<Message<true>>>(messages.edit('1234567890', 'text')); + expectType<Promise<Message<true>>>(messages.fetch('1234567890')); + expectType<Promise<Collection<Snowflake, Message<true>>>>(messages.fetchPinned()); + expectType<Guild>(message.guild); + expectType<Snowflake>(message.guildId); + expectType<GuildTextBasedChannel>(message.channel.messages.channel); + } +} + +{ + const { messages } = dmChannel; + const message = await messages.fetch('123'); + expectType<DMMessageManager>(messages); + expectType<Promise<Message>>(messages.edit('1234567890', 'text')); + expectType<Promise<Message>>(messages.fetch('1234567890')); + expectType<Promise<Collection<Snowflake, Message>>>(messages.fetchPinned()); + expectType<Guild | null>(message.guild); + expectType<Snowflake | null>(message.guildId); + expectType<DMChannel | GuildTextBasedChannel>(message.channel.messages.channel); + expectType<MessageMentions>(message.mentions); + expectType<Guild | null>(message.mentions.guild); + expectType<Collection<Snowflake, GuildMember> | null>(message.mentions.members); + + if (messages.channel.isDMBased()) { + expectType<DMChannel>(messages.channel); + expectType<DMChannel>(messages.channel.messages.channel); + } + + // @ts-expect-error Crossposting is not possible in direct messages. + messages.crosspost('1234567890'); +} + +declare const threadManager: ThreadManager; +{ + expectType<Promise<AnyThreadChannel | null>>(threadManager.fetch('12345678901234567')); + expectType<Promise<AnyThreadChannel | null>>(threadManager.fetch('12345678901234567', { cache: true, force: false })); + expectType<Promise<FetchedThreads>>(threadManager.fetch()); + expectType<Promise<FetchedThreads>>(threadManager.fetch({})); + expectType<Promise<FetchedThreadsMore>>(threadManager.fetch({ archived: { limit: 4 } })); + + // @ts-expect-error The force option has no effect here. + threadManager.fetch({ archived: {} }, { force: true }); +} + +declare const guildForumThreadManager: GuildForumThreadManager; +expectType<ForumChannel>(guildForumThreadManager.channel); + +declare const guildTextThreadManager: GuildTextThreadManager< + ChannelType.PublicThread | ChannelType.PrivateThread | ChannelType.AnnouncementThread +>; +expectType<TextChannel | NewsChannel>(guildTextThreadManager.channel); + +declare const guildMemberManager: GuildMemberManager; +{ + expectType<Promise<GuildMember>>(guildMemberManager.fetch('12345678901234567')); + expectType<Promise<GuildMember>>(guildMemberManager.fetch({ user: '12345678901234567' })); + expectType<Promise<GuildMember>>(guildMemberManager.fetch({ user: '12345678901234567', cache: true, force: false })); + expectType<Promise<GuildMember>>(guildMemberManager.fetch({ user: '12345678901234567', cache: true, force: false })); + expectType<Promise<Collection<Snowflake, GuildMember>>>(guildMemberManager.fetch()); + expectType<Promise<Collection<Snowflake, GuildMember>>>(guildMemberManager.fetch({})); + expectType<Promise<Collection<Snowflake, GuildMember>>>(guildMemberManager.fetch({ user: ['12345678901234567'] })); + expectType<Promise<Collection<Snowflake, GuildMember>>>(guildMemberManager.fetch({ withPresences: false })); + expectType<Promise<GuildMember>>(guildMemberManager.fetch({ user: '12345678901234567', withPresences: true })); + + expectType<Promise<Collection<Snowflake, GuildMember>>>( + guildMemberManager.fetch({ query: 'test', user: ['12345678901234567'], nonce: 'test' }), + ); + + // @ts-expect-error The cache & force options have no effect here. + guildMemberManager.fetch({ cache: true, force: false }); + // @ts-expect-error The force option has no effect here. + guildMemberManager.fetch({ user: ['12345678901234567'], cache: true, force: false }); +} + +declare const messageManager: MessageManager; +{ + expectType<Promise<Message>>(messageManager.fetch('1234567890')); + expectType<Promise<Message>>(messageManager.fetch({ message: '1234567890' })); + expectType<Promise<Message>>(messageManager.fetch({ message: '1234567890', cache: true, force: false })); + expectType<Promise<Collection<Snowflake, Message>>>(messageManager.fetch()); + expectType<Promise<Collection<Snowflake, Message>>>(messageManager.fetch({})); + expectType<Promise<Collection<Snowflake, Message>>>( + messageManager.fetch({ limit: 100, before: '1234567890', cache: false }), + ); + // @ts-expect-error + messageManager.fetch({ cache: true, force: false }); + // @ts-expect-error + messageManager.fetch({ message: '1234567890', after: '1234567890', cache: true, force: false }); +} + +declare const roleManager: RoleManager; +expectType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch()); +expectType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch(undefined, {})); +expectType<Promise<Role | null>>(roleManager.fetch('0')); + +declare const guildEmojiManager: GuildEmojiManager; +expectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch()); +expectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch(undefined, {})); +expectType<Promise<GuildEmoji>>(guildEmojiManager.fetch('0')); + +declare const guildBanManager: GuildBanManager; +{ + expectType<Promise<GuildBan>>(guildBanManager.fetch('1234567890')); + expectType<Promise<GuildBan>>(guildBanManager.fetch({ user: '1234567890' })); + expectType<Promise<GuildBan>>(guildBanManager.fetch({ user: '1234567890', cache: true, force: false })); + expectType<Promise<Collection<Snowflake, GuildBan>>>(guildBanManager.fetch()); + expectType<Promise<Collection<Snowflake, GuildBan>>>(guildBanManager.fetch({})); + expectType<Promise<Collection<Snowflake, GuildBan>>>(guildBanManager.fetch({ limit: 100, before: '1234567890' })); + // @ts-expect-error + guildBanManager.fetch({ cache: true, force: false }); + // @ts-expect-error + guildBanManager.fetch({ user: '1234567890', after: '1234567890', cache: true, force: false }); +} + +declare const threadMemberWithGuildMember: ThreadMember<true>; +declare const threadMemberManager: ThreadMemberManager; +{ + expectType<Promise<ThreadMember>>(threadMemberManager.fetch('12345678')); + expectType<Promise<ThreadMember>>(threadMemberManager.fetch({ member: '12345678', cache: false })); + expectType<Promise<ThreadMember>>(threadMemberManager.fetch({ member: '12345678', force: true })); + expectType<Promise<ThreadMember<true>>>(threadMemberManager.fetch({ member: threadMemberWithGuildMember })); + expectType<Promise<ThreadMember<true>>>(threadMemberManager.fetch({ member: '12345678901234567', withMember: true })); + expectType<Promise<Collection<Snowflake, ThreadMember>>>(threadMemberManager.fetch()); + expectType<Promise<Collection<Snowflake, ThreadMember>>>(threadMemberManager.fetch({})); + + expectType<Promise<Collection<Snowflake, ThreadMember<true>>>>( + threadMemberManager.fetch({ cache: true, limit: 50, withMember: true, after: '12345678901234567' }), + ); + + expectType<Promise<Collection<Snowflake, ThreadMember>>>( + threadMemberManager.fetch({ cache: true, withMember: false }), + ); + + // @ts-expect-error The `force` option cannot be used alongside fetching all thread members. + threadMemberManager.fetch({ cache: true, force: false }); + // @ts-expect-error `withMember` needs to be `true` to receive paginated results. + threadMemberManager.fetch({ withMember: false, limit: 5, after: '12345678901234567' }); +} + +declare const typing: Typing; +expectType<User | PartialUser>(typing.user); +if (typing.user.partial) expectType<null>(typing.user.username); +if (!typing.user.partial) expectType<string>(typing.user.tag); + +expectType<TextBasedChannel>(typing.channel); +if (typing.channel.partial) expectType<undefined>(typing.channel.lastMessageId); + +expectType<GuildMember | null>(typing.member); +expectType<Guild | null>(typing.guild); + +if (typing.inGuild()) { + expectType<Guild>(typing.channel.guild); + expectType<Guild>(typing.guild); +} + +// Test interactions +declare const interaction: Interaction; +declare const booleanValue: boolean; +if (interaction.inGuild()) { + expectType<Snowflake>(interaction.guildId); +} else { + expectType<Snowflake | null>(interaction.guildId); +} + +client.on('interactionCreate', async interaction => { + if (interaction.type === InteractionType.MessageComponent) { + expectType<AnySelectMenuInteraction | ButtonInteraction>(interaction); + expectType<MessageActionRowComponent | APIButtonComponent | APISelectMenuComponent>(interaction.component); + expectType<Message>(interaction.message); + if (interaction.inCachedGuild()) { + expectAssignable<MessageComponentInteraction>(interaction); + expectType<MessageActionRowComponent>(interaction.component); + expectType<Message<true>>(interaction.message); + expectType<Guild>(interaction.guild); + expectType<Promise<Message<true>>>(interaction.reply({ content: 'a', fetchReply: true })); + expectType<Promise<Message<true>>>(interaction.deferReply({ fetchReply: true })); + expectType<Promise<Message<true>>>(interaction.editReply({ content: 'a' })); + expectType<Promise<Message<true>>>(interaction.fetchReply()); + expectType<Promise<Message<true>>>(interaction.update({ content: 'a', fetchReply: true })); + expectType<Promise<Message<true>>>(interaction.deferUpdate({ fetchReply: true })); + expectType<Promise<Message<true>>>(interaction.followUp({ content: 'a' })); + } else if (interaction.inRawGuild()) { + expectAssignable<MessageComponentInteraction>(interaction); + expectType<APIButtonComponent | APISelectMenuComponent>(interaction.component); + expectType<Message<false>>(interaction.message); + expectType<null>(interaction.guild); + expectType<Promise<Message<false>>>(interaction.reply({ content: 'a', fetchReply: true })); + expectType<Promise<Message<false>>>(interaction.deferReply({ fetchReply: true })); + expectType<Promise<Message<false>>>(interaction.editReply({ content: 'a' })); + expectType<Promise<Message<false>>>(interaction.fetchReply()); + expectType<Promise<Message<false>>>(interaction.update({ content: 'a', fetchReply: true })); + expectType<Promise<Message<false>>>(interaction.deferUpdate({ fetchReply: true })); + expectType<Promise<Message<false>>>(interaction.followUp({ content: 'a' })); + } else if (interaction.inGuild()) { + expectAssignable<MessageComponentInteraction>(interaction); + expectType<MessageActionRowComponent | APIButtonComponent | APISelectMenuComponent>(interaction.component); + expectType<Message>(interaction.message); + expectType<Guild | null>(interaction.guild); + expectType<Promise<Message>>(interaction.reply({ content: 'a', fetchReply: true })); + expectType<Promise<Message>>(interaction.deferReply({ fetchReply: true })); + expectType<Promise<Message>>(interaction.editReply({ content: 'a' })); + expectType<Promise<Message>>(interaction.fetchReply()); + expectType<Promise<Message>>(interaction.update({ content: 'a', fetchReply: true })); + expectType<Promise<Message>>(interaction.deferUpdate({ fetchReply: true })); + expectType<Promise<Message>>(interaction.followUp({ content: 'a' })); + } + } + + if (interaction.inCachedGuild()) { + expectAssignable<GuildMember>(interaction.member); + expectNotType<ChatInputCommandInteraction<'cached'>>(interaction); + expectAssignable<Interaction>(interaction); + expectType<Locale>(interaction.guildLocale); + } else if (interaction.inRawGuild()) { + expectAssignable<APIInteractionGuildMember>(interaction.member); + expectNotAssignable<Interaction<'cached'>>(interaction); + expectType<Locale>(interaction.guildLocale); + } else if (interaction.inGuild()) { + expectType<Locale>(interaction.guildLocale); + } else { + expectType<APIInteractionGuildMember | GuildMember | null>(interaction.member); + expectNotAssignable<Interaction<'cached'>>(interaction); + expectType<string | null>(interaction.guildId); + } + + if ( + interaction.type === InteractionType.ApplicationCommand && + (interaction.commandType === ApplicationCommandType.User || + interaction.commandType === ApplicationCommandType.Message) + ) { + expectType<MessageContextMenuCommandInteraction | UserContextMenuCommandInteraction>(interaction); + if (interaction.inCachedGuild()) { + expectAssignable<ContextMenuCommandInteraction>(interaction); + expectAssignable<Guild>(interaction.guild); + expectAssignable<CommandInteraction<'cached'>>(interaction); + expectType<Promise<Message<true>>>(interaction.reply({ content: 'a', fetchReply: true })); + expectType<Promise<Message<true>>>(interaction.deferReply({ fetchReply: true })); + expectType<Promise<Message<true>>>(interaction.editReply({ content: 'a' })); + expectType<Promise<Message<true>>>(interaction.fetchReply()); + expectType<Promise<Message<true>>>(interaction.followUp({ content: 'a' })); + } else if (interaction.inRawGuild()) { + expectAssignable<ContextMenuCommandInteraction>(interaction); + expectType<null>(interaction.guild); + expectType<Promise<Message<false>>>(interaction.reply({ content: 'a', fetchReply: true })); + expectType<Promise<Message<false>>>(interaction.deferReply({ fetchReply: true })); + expectType<Promise<Message<false>>>(interaction.editReply({ content: 'a' })); + expectType<Promise<Message<false>>>(interaction.fetchReply()); + expectType<Promise<Message<false>>>(interaction.followUp({ content: 'a' })); + } else if (interaction.inGuild()) { + expectAssignable<ContextMenuCommandInteraction>(interaction); + expectType<Guild | null>(interaction.guild); + expectType<Promise<Message>>(interaction.reply({ content: 'a', fetchReply: true })); + expectType<Promise<Message>>(interaction.deferReply({ fetchReply: true })); + expectType<Promise<Message>>(interaction.editReply({ content: 'a' })); + expectType<Promise<Message>>(interaction.fetchReply()); + expectType<Promise<Message>>(interaction.followUp({ content: 'a' })); + } + } + + if ( + interaction.type === InteractionType.ApplicationCommand && + interaction.commandType === ApplicationCommandType.Message + ) { + expectType<Message>(interaction.targetMessage); + if (interaction.inCachedGuild()) { + expectType<Message<true>>(interaction.targetMessage); + } else if (interaction.inRawGuild()) { + expectType<Message<false>>(interaction.targetMessage); + } else if (interaction.inGuild()) { + expectType<Message>(interaction.targetMessage); + } + } + + if (interaction.type === InteractionType.MessageComponent && interaction.componentType === ComponentType.Button) { + expectType<ButtonInteraction>(interaction); + expectType<ButtonComponent | APIButtonComponent>(interaction.component); + expectType<Message>(interaction.message); + if (interaction.inCachedGuild()) { + expectAssignable<ButtonInteraction>(interaction); + expectType<ButtonComponent>(interaction.component); + expectType<Message<true>>(interaction.message); + expectType<Guild>(interaction.guild); + expectType<Promise<Message<true>>>(interaction.reply({ fetchReply: true })); + } else if (interaction.inRawGuild()) { + expectAssignable<ButtonInteraction>(interaction); + expectType<APIButtonComponent>(interaction.component); + expectType<Message<false>>(interaction.message); + expectType<null>(interaction.guild); + expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true })); + } else if (interaction.inGuild()) { + expectAssignable<ButtonInteraction>(interaction); + expectType<ButtonComponent | APIButtonComponent>(interaction.component); + expectType<Message>(interaction.message); + expectAssignable<Guild | null>(interaction.guild); + expectType<Promise<Message>>(interaction.reply({ fetchReply: true })); + } + } + + if ( + interaction.type === InteractionType.MessageComponent && + interaction.componentType === ComponentType.StringSelect + ) { + expectType<StringSelectMenuInteraction>(interaction); + expectType<StringSelectMenuComponent | APIStringSelectComponent>(interaction.component); + expectType<Message>(interaction.message); + if (interaction.inCachedGuild()) { + expectAssignable<StringSelectMenuInteraction>(interaction); + expectType<SelectMenuComponent>(interaction.component); + expectType<Message<true>>(interaction.message); + expectType<Guild>(interaction.guild); + expectType<Promise<Message<true>>>(interaction.reply({ fetchReply: true })); + } else if (interaction.inRawGuild()) { + expectAssignable<StringSelectMenuInteraction>(interaction); + expectType<APIStringSelectComponent>(interaction.component); + expectType<Message<false>>(interaction.message); + expectType<null>(interaction.guild); + expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true })); + } else if (interaction.inGuild()) { + expectAssignable<StringSelectMenuInteraction>(interaction); + expectType<SelectMenuComponent | APIStringSelectComponent>(interaction.component); + expectType<Message>(interaction.message); + expectType<Guild | null>(interaction.guild); + expectType<Promise<Message>>(interaction.reply({ fetchReply: true })); + } + } + + if ( + interaction.type === InteractionType.ApplicationCommand && + interaction.commandType === ApplicationCommandType.ChatInput + ) { + if (interaction.inRawGuild()) { + expectNotAssignable<Interaction<'cached'>>(interaction); + expectAssignable<ChatInputCommandInteraction>(interaction); + expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true })); + expectType<APIInteractionDataResolvedGuildMember | null>(interaction.options.getMember('test')); + + expectType<APIInteractionDataResolvedChannel>(interaction.options.getChannel('test', true)); + expectType<APIRole>(interaction.options.getRole('test', true)); + } else if (interaction.inCachedGuild()) { + const msg = await interaction.reply({ fetchReply: true }); + const btn = await msg.awaitMessageComponent({ componentType: ComponentType.Button }); + + expectType<Message<true>>(msg); + expectType<ButtonInteraction<'cached'>>(btn); + + expectType<GuildMember | null>(interaction.options.getMember('test')); + expectAssignable<ChatInputCommandInteraction>(interaction); + expectType<Promise<Message<true>>>(interaction.reply({ fetchReply: true })); + + expectType<GuildBasedChannel>(interaction.options.getChannel('test', true)); + expectType<Role>(interaction.options.getRole('test', true)); + + expectType<PublicThreadChannel>(interaction.options.getChannel('test', true, [ChannelType.PublicThread])); + expectType<PublicThreadChannel>(interaction.options.getChannel('test', true, [ChannelType.AnnouncementThread])); + expectType<PublicThreadChannel>( + interaction.options.getChannel('test', true, [ChannelType.PublicThread, ChannelType.AnnouncementThread]), + ); + expectType<PrivateThreadChannel>(interaction.options.getChannel('test', true, [ChannelType.PrivateThread])); + + expectType<TextChannel>(interaction.options.getChannel('test', true, [ChannelType.GuildText])); + expectType<TextChannel | null>(interaction.options.getChannel('test', false, [ChannelType.GuildText])); + expectType<ForumChannel | VoiceChannel>( + interaction.options.getChannel('test', true, [ChannelType.GuildForum, ChannelType.GuildVoice]), + ); + expectType<TextChannel>(interaction.options.getChannel('test', true, [ChannelType.GuildText] as const)); + expectType<ForumChannel | VoiceChannel | null>( + interaction.options.getChannel('test', false, [ChannelType.GuildForum, ChannelType.GuildVoice]), + ); + } else { + // @ts-expect-error + consumeCachedCommand(interaction); + expectType<ChatInputCommandInteraction>(interaction); + expectType<Promise<Message>>(interaction.reply({ fetchReply: true })); + expectType<APIInteractionDataResolvedGuildMember | GuildMember | null>(interaction.options.getMember('test')); + + expectType<GuildBasedChannel | APIInteractionDataResolvedChannel>(interaction.options.getChannel('test', true)); + expectType<APIRole | Role>(interaction.options.getRole('test', true)); + } + + expectType<ChatInputCommandInteraction>(interaction); + expectType<Omit<CommandInteractionOptionResolver<CacheType>, 'getFocused' | 'getMessage'>>(interaction.options); + expectType<readonly CommandInteractionOption[]>(interaction.options.data); + + const optionalOption = interaction.options.get('name'); + const requiredOption = interaction.options.get('name', true); + expectType<CommandInteractionOption | null>(optionalOption); + expectType<CommandInteractionOption>(requiredOption); + expectType<CommandInteractionOption[] | undefined>(requiredOption.options); + + expectType<string | null>(interaction.options.getString('name', booleanValue)); + expectType<string | null>(interaction.options.getString('name', false)); + expectType<string>(interaction.options.getString('name', true)); + + expectType<string>(interaction.options.getSubcommand()); + expectType<string>(interaction.options.getSubcommand(true)); + expectType<string | null>(interaction.options.getSubcommand(booleanValue)); + expectType<string | null>(interaction.options.getSubcommand(false)); + + expectType<string>(interaction.options.getSubcommandGroup(true)); + expectType<string | null>(interaction.options.getSubcommandGroup()); + expectType<string | null>(interaction.options.getSubcommandGroup(booleanValue)); + expectType<string | null>(interaction.options.getSubcommandGroup(false)); + } + + if (interaction.isRepliable()) { + expectAssignable<RepliableInteraction>(interaction); + interaction.reply('test'); + } + + if ( + interaction.type === InteractionType.ApplicationCommand && + interaction.commandType === ApplicationCommandType.ChatInput && + interaction.isRepliable() + ) { + expectAssignable<CommandInteraction>(interaction); + expectAssignable<RepliableInteraction>(interaction); + } + + if (interaction.type === InteractionType.ModalSubmit && interaction.isRepliable()) { + expectType<ModalSubmitInteraction>(interaction); + if (interaction.inCachedGuild()) { + expectAssignable<ModalSubmitInteraction>(interaction); + expectType<Guild>(interaction.guild); + expectType<Promise<Message<true>>>(interaction.reply({ content: 'a', fetchReply: true })); + expectType<Promise<Message<true>>>(interaction.deferReply({ fetchReply: true })); + expectType<Promise<Message<true>>>(interaction.editReply({ content: 'a' })); + expectType<Promise<Message<true>>>(interaction.fetchReply()); + expectType<Promise<Message<true>>>(interaction.deferUpdate({ fetchReply: true })); + expectType<Promise<Message<true>>>(interaction.followUp({ content: 'a' })); + } else if (interaction.inRawGuild()) { + expectAssignable<ModalSubmitInteraction>(interaction); + expectType<null>(interaction.guild); + expectType<Promise<Message<false>>>(interaction.reply({ content: 'a', fetchReply: true })); + expectType<Promise<Message<false>>>(interaction.deferReply({ fetchReply: true })); + expectType<Promise<Message<false>>>(interaction.editReply({ content: 'a' })); + expectType<Promise<Message<false>>>(interaction.fetchReply()); + expectType<Promise<Message<false>>>(interaction.deferUpdate({ fetchReply: true })); + expectType<Promise<Message<false>>>(interaction.followUp({ content: 'a' })); + } else if (interaction.inGuild()) { + expectAssignable<ModalSubmitInteraction>(interaction); + expectType<Guild | null>(interaction.guild); + expectType<Promise<Message>>(interaction.reply({ content: 'a', fetchReply: true })); + expectType<Promise<Message>>(interaction.deferReply({ fetchReply: true })); + expectType<Promise<Message>>(interaction.editReply({ content: 'a' })); + expectType<Promise<Message>>(interaction.fetchReply()); + expectType<Promise<Message>>(interaction.deferUpdate({ fetchReply: true })); + expectType<Promise<Message>>(interaction.followUp({ content: 'a' })); + } + } +}); + +declare const shard: Shard; + +shard.on('death', process => { + expectType<ChildProcess | Worker>(process); +}); + +declare const webSocketShard: WebSocketShard; + +webSocketShard.on('close', event => { + expectType<CloseEvent>(event); +}); + +declare const collector: Collector<string, Interaction, string[]>; + +collector.on('collect', (collected, ...other) => { + expectType<Interaction>(collected); + expectType<string[]>(other); +}); + +collector.on('dispose', (vals, ...other) => { + expectType<Interaction>(vals); + expectType<string[]>(other); +}); + +collector.on('end', (collection, reason) => { + expectType<Collection<string, Interaction>>(collection); + expectType<string>(reason); +}); + +(async () => { + for await (const value of collector) { + expectType<[Interaction, ...string[]]>(value); + } +})(); + +expectType<Promise<number | null>>(shard.eval(c => c.readyTimestamp)); + +// Test audit logs +expectType<Promise<GuildAuditLogs<AuditLogEvent.MemberKick>>>(guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick })); + +expectType<Promise<GuildAuditLogs<AuditLogEvent.ChannelCreate>>>( + guild.fetchAuditLogs({ type: AuditLogEvent.ChannelCreate }), +); + +expectType<Promise<GuildAuditLogs<AuditLogEvent.IntegrationUpdate>>>( + guild.fetchAuditLogs({ type: AuditLogEvent.IntegrationUpdate }), +); + +expectType<Promise<GuildAuditLogs<null>>>(guild.fetchAuditLogs({ type: null })); +expectType<Promise<GuildAuditLogs<AuditLogEvent>>>(guild.fetchAuditLogs()); + +expectType<Promise<GuildAuditLogsEntry<AuditLogEvent.MemberKick, 'Delete', 'User'> | undefined>>( + guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }).then(al => al.entries.first()), +); +expectAssignable<Promise<GuildAuditLogsEntry<AuditLogEvent.MemberKick, 'Delete', 'User'> | undefined>>( + guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }).then(al => al.entries.first()), +); + +expectType<Promise<GuildAuditLogsEntry<null, GuildAuditLogsActionType, GuildAuditLogsTargetType> | undefined>>( + guild.fetchAuditLogs({ type: null }).then(al => al.entries.first()), +); +expectType<Promise<GuildAuditLogsEntry<null, GuildAuditLogsActionType, GuildAuditLogsTargetType> | undefined>>( + guild.fetchAuditLogs().then(al => al.entries.first()), +); + +expectType<Promise<null | undefined>>( + guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }).then(al => al.entries.first()?.extra), +); +expectType<Promise<StageChannel | { id: Snowflake } | undefined>>( + guild.fetchAuditLogs({ type: AuditLogEvent.StageInstanceCreate }).then(al => al.entries.first()?.extra), +); +expectType<Promise<{ channel: GuildTextBasedChannel | { id: Snowflake }; count: number } | undefined>>( + guild.fetchAuditLogs({ type: AuditLogEvent.MessageDelete }).then(al => al.entries.first()?.extra), +); + +expectType<Promise<User | null | undefined>>( + guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }).then(al => al.entries.first()?.target), +); +expectType<Promise<StageInstance | undefined>>( + guild.fetchAuditLogs({ type: AuditLogEvent.StageInstanceCreate }).then(al => al.entries.first()?.target), +); +expectType<Promise<User | undefined>>( + guild.fetchAuditLogs({ type: AuditLogEvent.MessageDelete }).then(al => al.entries.first()?.target), +); + +declare const TextBasedChannel: TextBasedChannel; +declare const TextBasedChannelTypes: TextBasedChannelTypes; +declare const VoiceBasedChannel: VoiceBasedChannel; +declare const GuildBasedChannel: GuildBasedChannel; +declare const NonThreadGuildBasedChannel: NonThreadGuildBasedChannel; +declare const GuildTextBasedChannel: GuildTextBasedChannel; + +expectType<TextBasedChannel>(TextBasedChannel); +expectType< + | ChannelType.GuildText + | ChannelType.DM + | ChannelType.GuildAnnouncement + | ChannelType.GuildVoice + | ChannelType.GuildStageVoice + | ThreadChannelType +>(TextBasedChannelTypes); +expectType<StageChannel | VoiceChannel>(VoiceBasedChannel); +expectType<GuildBasedChannel>(GuildBasedChannel); +expectType<CategoryChannel | NewsChannel | StageChannel | TextChannel | VoiceChannel | ForumChannel>( + NonThreadGuildBasedChannel, +); +expectType<GuildTextBasedChannel>(GuildTextBasedChannel); + +const button = new ButtonBuilder({ + label: 'test', + style: ButtonStyle.Primary, + customId: 'test', +}); + +const selectMenu = new StringSelectMenuBuilder({ + maxValues: 10, + minValues: 2, + customId: 'test', +}); + +new ActionRowBuilder({ + components: [selectMenu.toJSON(), button.toJSON()], +}); + +new StringSelectMenuBuilder({ + customId: 'foo', +}); + +new ButtonBuilder({ + style: ButtonStyle.Danger, +}) + .setEmoji('<a:foo:123>') + .setEmoji('<:foo:123>') + .setEmoji('foobar:123') + .setEmoji('😏') + .setEmoji({ + name: 'test', + id: '123', + animated: false, + }); + +// @ts-expect-error +new EmbedBuilder().setColor('abc'); + +new EmbedBuilder().setColor('#ffffff'); + +expectNotAssignable<ActionRowData<MessageActionRowComponentData>>({ + type: ComponentType.ActionRow, + components: [ + { + type: ComponentType.Button, + }, + ], +}); + +declare const chatInputInteraction: ChatInputCommandInteraction; + +expectType<Attachment>(chatInputInteraction.options.getAttachment('attachment', true)); +expectType<Attachment | null>(chatInputInteraction.options.getAttachment('attachment')); + +declare const modal: ModalBuilder; + +chatInputInteraction.showModal(modal); + +chatInputInteraction.showModal({ + title: 'abc', + custom_id: 'abc', + components: [ + { + components: [ + { + custom_id: 'aa', + label: 'label', + style: TextInputStyle.Short, + type: ComponentType.TextInput, + }, + ], + type: ComponentType.ActionRow, + }, + ], +}); + +declare const selectMenuData: APISelectMenuComponent; +StringSelectMenuBuilder.from(selectMenuData); + +declare const selectMenuComp: SelectMenuComponent; +StringSelectMenuBuilder.from(selectMenuComp); + +declare const buttonData: APIButtonComponent; +ButtonBuilder.from(buttonData); + +declare const buttonComp: ButtonComponent; +ButtonBuilder.from(buttonComp); + +declare const textInputData: APITextInputComponent; +TextInputBuilder.from(textInputData); + +declare const textInputComp: TextInputComponent; +TextInputBuilder.from(textInputComp); + +declare const embedData: APIEmbed; +EmbedBuilder.from(embedData); + +declare const embedComp: Embed; +EmbedBuilder.from(embedComp); + +declare const actionRowData: APIActionRowComponent<APIActionRowComponentTypes>; +ActionRowBuilder.from(actionRowData); + +declare const actionRowComp: ActionRow<ActionRowComponent>; +ActionRowBuilder.from(actionRowComp); + +declare const buttonsActionRowData: APIActionRowComponent<APIButtonComponent>; +declare const buttonsActionRowComp: ActionRow<ButtonComponent>; + +expectType<ActionRowBuilder<ButtonBuilder>>(ActionRowBuilder.from<ButtonBuilder>(buttonsActionRowData)); +expectType<ActionRowBuilder<ButtonBuilder>>(ActionRowBuilder.from<ButtonBuilder>(buttonsActionRowComp)); + +declare const anyComponentsActionRowData: APIActionRowComponent<APIActionRowComponentTypes>; +declare const anyComponentsActionRowComp: ActionRow<ActionRowComponent>; + +expectType<ActionRowBuilder>(ActionRowBuilder.from(anyComponentsActionRowData)); +expectType<ActionRowBuilder>(ActionRowBuilder.from(anyComponentsActionRowComp)); + +declare const stageChannel: StageChannel; +declare const partialGroupDMChannel: PartialGroupDMChannel; + +expectType<ChannelMention>(textChannel.toString()); +expectType<ChannelMention>(voiceChannel.toString()); +expectType<ChannelMention>(newsChannel.toString()); +expectType<ChannelMention>(threadChannel.toString()); +expectType<ChannelMention>(stageChannel.toString()); +expectType<ChannelMention>(partialGroupDMChannel.toString()); +expectType<UserMention>(dmChannel.toString()); +expectType<UserMention>(user.toString()); +expectType<UserMention>(guildMember.toString()); + +declare const webhook: Webhook; +declare const webhookClient: WebhookClient; +declare const interactionWebhook: InteractionWebhook; +declare const snowflake: Snowflake; + +expectType<Promise<Message>>(webhook.send('content')); +expectType<Promise<Message>>(webhook.editMessage(snowflake, 'content')); +expectType<Promise<Message>>(webhook.fetchMessage(snowflake)); + +expectType<Promise<APIMessage>>(webhookClient.send('content')); +expectType<Promise<APIMessage>>(webhookClient.editMessage(snowflake, 'content')); +expectType<Promise<APIMessage>>(webhookClient.fetchMessage(snowflake)); + +expectType<Promise<Message>>(interactionWebhook.send('content')); +expectType<Promise<Message>>(interactionWebhook.editMessage(snowflake, 'content')); +expectType<Promise<Message>>(interactionWebhook.fetchMessage(snowflake)); + +declare const categoryChannel: CategoryChannel; +declare const forumChannel: ForumChannel; + +await forumChannel.edit({ + availableTags: [...forumChannel.availableTags, { name: 'tag' }], +}); + +await forumChannel.setAvailableTags([{ ...forumChannel.availableTags, name: 'tag' }]); +await forumChannel.setAvailableTags([{ name: 'tag' }]); + +expectType<Readonly<ChannelFlagsBitField>>(textChannel.flags); +expectType<Readonly<ChannelFlagsBitField>>(voiceChannel.flags); +expectType<Readonly<ChannelFlagsBitField>>(stageChannel.flags); +expectType<Readonly<ChannelFlagsBitField>>(forumChannel.flags); +expectType<Readonly<ChannelFlagsBitField>>(dmChannel.flags); +expectType<Readonly<ChannelFlagsBitField>>(categoryChannel.flags); +expectType<Readonly<ChannelFlagsBitField>>(newsChannel.flags); +expectType<Readonly<ChannelFlagsBitField>>(categoryChannel.flags); +expectType<Readonly<ChannelFlagsBitField>>(threadChannel.flags); + +expectType<null>(partialGroupDMChannel.flags); + +// Select menu type narrowing +if (interaction.isAnySelectMenu()) { + expectType<AnySelectMenuInteraction>(interaction); +} + +declare const anySelectMenu: AnySelectMenuInteraction; + +if (anySelectMenu.isStringSelectMenu()) { + expectType<StringSelectMenuInteraction>(anySelectMenu); +} else if (anySelectMenu.isUserSelectMenu()) { + expectType<UserSelectMenuInteraction>(anySelectMenu); +} else if (anySelectMenu.isRoleSelectMenu()) { + expectType<RoleSelectMenuInteraction>(anySelectMenu); +} else if (anySelectMenu.isChannelSelectMenu()) { + expectType<ChannelSelectMenuInteraction>(anySelectMenu); +} else if (anySelectMenu.isMentionableSelectMenu()) { + expectType<MentionableSelectMenuInteraction>(anySelectMenu); +} + +client.on('guildAuditLogEntryCreate', (auditLogEntry, guild) => { + expectType<GuildAuditLogsEntry>(auditLogEntry); + expectType<Guild>(guild); +}); + +expectType<Readonly<GuildMemberFlagsBitField>>(guildMember.flags); + +{ + const onboarding = await guild.fetchOnboarding(); + expectType<GuildOnboarding>(onboarding); +} diff --git a/node_modules/discord.js/typings/rawDataTypes.d.ts b/node_modules/discord.js/typings/rawDataTypes.d.ts new file mode 100644 index 0000000..d1075e2 --- /dev/null +++ b/node_modules/discord.js/typings/rawDataTypes.d.ts @@ -0,0 +1,210 @@ +// These are aggregate types that are used in the typings file but do not exist as actual exported values. +// To prevent them from showing up in an editor, they are imported from here instead of exporting them there directly. + +import { + APIApplication, + APIApplicationCommand, + APIApplicationCommandInteraction, + APIAttachment, + APIAuditLog, + APIAuditLogEntry, + APIBan, + APIChannel, + APIEmoji, + APIExtendedInvite, + APIGuild, + APIGuildIntegration, + APIGuildIntegrationApplication, + APIGuildMember, + APIGuildPreview, + APIGuildWelcomeScreen, + APIGuildWelcomeScreenChannel, + APIGuildWidget, + APIGuildWidgetMember, + APIInteractionDataResolvedChannel, + APIInteractionDataResolvedGuildMember, + APIInteractionGuildMember, + APIInvite, + APIInviteStageInstance, + APIMessage, + APIMessageButtonInteractionData, + APIMessageComponentInteraction, + APIMessageSelectMenuInteractionData, + APIOverwrite, + APIPartialChannel, + APIPartialEmoji, + APIPartialGuild, + APIReaction, + APIRole, + APIStageInstance, + APISticker, + APIStickerItem, + APIStickerPack, + APITeam, + APITeamMember, + APITemplate, + APIThreadMember, + APIUnavailableGuild, + APIUser, + APIVoiceRegion, + APIWebhook, + GatewayActivity, + GatewayActivityAssets, + GatewayActivityEmoji, + GatewayGuildBanAddDispatchData, + GatewayGuildMemberAddDispatchData, + GatewayGuildMemberUpdateDispatchData, + GatewayInteractionCreateDispatchData, + GatewayInviteCreateDispatchData, + GatewayInviteDeleteDispatchData, + GatewayMessageReactionAddDispatchData, + GatewayMessageUpdateDispatchData, + GatewayPresenceUpdate, + GatewayReadyDispatchData, + GatewayTypingStartDispatchData, + GatewayVoiceState, + RESTAPIPartialCurrentUserGuild, + RESTGetAPIWebhookWithTokenResult, + RESTPatchAPIChannelMessageJSONBody, + RESTPatchAPICurrentGuildMemberNicknameJSONBody, + RESTPatchAPIInteractionFollowupJSONBody, + RESTPatchAPIInteractionOriginalResponseJSONBody, + RESTPatchAPIWebhookWithTokenJSONBody, + RESTPostAPIChannelMessageJSONBody, + RESTPostAPIInteractionCallbackFormDataBody, + RESTPostAPIInteractionFollowupJSONBody, + RESTPostAPIWebhookWithTokenJSONBody, + Snowflake, + APIGuildScheduledEvent, +} from 'discord-api-types/v10'; +import { GuildChannel, Guild, PermissionOverwrites } from '.'; + +export type RawActivityData = GatewayActivity; + +export type RawApplicationData = RawClientApplicationData | RawIntegrationApplicationData; +export type RawClientApplicationData = GatewayReadyDispatchData['application'] | APIMessage['application']; +export type RawIntegrationApplicationData = APIGuildIntegrationApplication | Partial<APIApplication>; + +export type RawApplicationCommandData = APIApplicationCommand; + +export type RawChannelData = + | RawGuildChannelData + | RawThreadChannelData + | RawDMChannelData + | RawPartialGroupDMChannelData; +export type RawDMChannelData = APIChannel | APIInteractionDataResolvedChannel; +export type RawGuildChannelData = APIChannel | APIInteractionDataResolvedChannel | Required<APIPartialChannel>; +export type RawPartialGroupDMChannelData = APIChannel | Required<APIPartialChannel>; +export type RawThreadChannelData = APIChannel | APIInteractionDataResolvedChannel; + +export type RawEmojiData = + | RawGuildEmojiData + | RawReactionEmojiData + | GatewayActivityEmoji + | Omit<Partial<APIPartialEmoji>, 'animated'>; +export type RawGuildEmojiData = APIEmoji; +export type RawReactionEmojiData = APIEmoji | APIPartialEmoji; + +export type RawGuildAuditLogData = APIAuditLog; + +export type RawGuildAuditLogEntryData = APIAuditLogEntry; + +export type RawGuildBanData = GatewayGuildBanAddDispatchData | APIBan; + +export type RawGuildData = APIGuild | APIUnavailableGuild; +export type RawAnonymousGuildData = RawGuildData | RawInviteGuildData; +export type RawBaseGuildData = RawAnonymousGuildData | RawOAuth2GuildData; +export type RawInviteGuildData = APIPartialGuild; +export type RawOAuth2GuildData = RESTAPIPartialCurrentUserGuild; + +export type RawGuildMemberData = + | APIGuildMember + | APIInteractionGuildMember + | APIInteractionDataResolvedGuildMember + | GatewayGuildMemberAddDispatchData + | GatewayGuildMemberUpdateDispatchData + | Required<RESTPatchAPICurrentGuildMemberNicknameJSONBody> + | { user: { id: Snowflake } }; +export type RawThreadMemberData = APIThreadMember; + +export type RawGuildPreviewData = APIGuildPreview; + +export type RawGuildScheduledEventData = APIGuildScheduledEvent; + +export type RawGuildTemplateData = APITemplate; + +export type RawIntegrationData = APIGuildIntegration; + +export type RawInteractionData = GatewayInteractionCreateDispatchData; +export type RawCommandInteractionData = APIApplicationCommandInteraction; +export type RawMessageComponentInteractionData = APIMessageComponentInteraction; +export type RawMessageButtonInteractionData = APIMessageButtonInteractionData; +export type RawMessageSelectMenuInteractionData = APIMessageSelectMenuInteractionData; + +export type RawInviteData = + | APIExtendedInvite + | APIInvite + | (GatewayInviteCreateDispatchData & { channel: GuildChannel; guild: Guild }) + | (GatewayInviteDeleteDispatchData & { channel: GuildChannel; guild: Guild }); + +export type RawInviteStageInstance = APIInviteStageInstance; + +export type RawMessageData = APIMessage; +export type RawPartialMessageData = GatewayMessageUpdateDispatchData; + +export type RawAttachmentData = APIAttachment; + +export type RawMessagePayloadData = + | RESTPostAPIChannelMessageJSONBody + | RESTPatchAPIChannelMessageJSONBody + | RESTPostAPIWebhookWithTokenJSONBody + | RESTPatchAPIWebhookWithTokenJSONBody + | RESTPostAPIInteractionCallbackFormDataBody + | RESTPatchAPIInteractionOriginalResponseJSONBody + | RESTPostAPIInteractionFollowupJSONBody + | RESTPatchAPIInteractionFollowupJSONBody; + +export type RawMessageReactionData = APIReaction | GatewayMessageReactionAddDispatchData; + +export type RawPermissionOverwriteData = APIOverwrite | PermissionOverwrites; + +export type RawPresenceData = GatewayPresenceUpdate; + +export type RawRoleData = APIRole; + +export type RawRichPresenceAssets = GatewayActivityAssets; + +export type RawStageInstanceData = + | APIStageInstance + | (Partial<APIStageInstance> & Pick<APIStageInstance, 'id' | 'channel_id' | 'guild_id'>); + +export type RawStickerData = APISticker | APIStickerItem; + +export type RawStickerPackData = APIStickerPack; + +export type RawTeamData = APITeam; + +export type RawTeamMemberData = APITeamMember; + +export type RawTypingData = GatewayTypingStartDispatchData; + +export type RawUserData = + | (APIUser & { member?: Omit<APIGuildMember, 'user'> }) + | (GatewayPresenceUpdate['user'] & Pick<APIUser, 'username'>); + +export type RawVoiceRegionData = APIVoiceRegion; + +export type RawVoiceStateData = GatewayVoiceState | Omit<GatewayVoiceState, 'guild_id'>; + +export type RawWebhookData = + | APIWebhook + | RESTGetAPIWebhookWithTokenResult + | (Partial<APIWebhook> & Required<Pick<APIWebhook, 'id' | 'guild_id'>>); + +export type RawWelcomeChannelData = APIGuildWelcomeScreenChannel; + +export type RawWelcomeScreenData = APIGuildWelcomeScreen; + +export type RawWidgetData = APIGuildWidget; + +export type RawWidgetMemberData = APIGuildWidgetMember; |