djs-selfbot-v13 3.1.8 → 3.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (364) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +48 -37
  3. package/package.json +44 -26
  4. package/src/WebSocket.js +39 -39
  5. package/src/client/BaseClient.js +86 -86
  6. package/src/client/Client.js +934 -765
  7. package/src/client/WebhookClient.js +61 -61
  8. package/src/client/actions/Action.js +116 -120
  9. package/src/client/actions/ActionsManager.js +80 -78
  10. package/src/client/actions/ApplicationCommandPermissionsUpdate.js +34 -34
  11. package/src/client/actions/AutoModerationActionExecution.js +27 -27
  12. package/src/client/actions/AutoModerationRuleCreate.js +28 -28
  13. package/src/client/actions/AutoModerationRuleDelete.js +32 -32
  14. package/src/client/actions/AutoModerationRuleUpdate.js +30 -30
  15. package/src/client/actions/ChannelCreate.js +23 -23
  16. package/src/client/actions/ChannelDelete.js +39 -39
  17. package/src/client/actions/ChannelUpdate.js +43 -43
  18. package/src/client/actions/GuildAuditLogEntryCreate.js +29 -29
  19. package/src/client/actions/GuildBanAdd.js +20 -20
  20. package/src/client/actions/GuildBanRemove.js +25 -25
  21. package/src/client/actions/GuildChannelsPositionUpdate.js +21 -21
  22. package/src/client/actions/GuildDelete.js +65 -65
  23. package/src/client/actions/GuildEmojiCreate.js +20 -20
  24. package/src/client/actions/GuildEmojiDelete.js +21 -21
  25. package/src/client/actions/GuildEmojiUpdate.js +20 -20
  26. package/src/client/actions/GuildEmojisUpdate.js +34 -34
  27. package/src/client/actions/GuildIntegrationsUpdate.js +19 -19
  28. package/src/client/actions/GuildMemberRemove.js +33 -33
  29. package/src/client/actions/GuildMemberUpdate.js +44 -44
  30. package/src/client/actions/GuildRoleCreate.js +25 -25
  31. package/src/client/actions/GuildRoleDelete.js +31 -31
  32. package/src/client/actions/GuildRoleUpdate.js +39 -39
  33. package/src/client/actions/GuildRolesPositionUpdate.js +21 -21
  34. package/src/client/actions/GuildScheduledEventCreate.js +27 -27
  35. package/src/client/actions/GuildScheduledEventDelete.js +31 -31
  36. package/src/client/actions/GuildScheduledEventUpdate.js +30 -30
  37. package/src/client/actions/GuildScheduledEventUserAdd.js +32 -32
  38. package/src/client/actions/GuildScheduledEventUserRemove.js +32 -32
  39. package/src/client/actions/GuildStickerCreate.js +20 -20
  40. package/src/client/actions/GuildStickerDelete.js +21 -21
  41. package/src/client/actions/GuildStickerUpdate.js +20 -20
  42. package/src/client/actions/GuildStickersUpdate.js +34 -34
  43. package/src/client/actions/GuildUpdate.js +33 -33
  44. package/src/client/actions/InviteCreate.js +28 -28
  45. package/src/client/actions/InviteDelete.js +30 -30
  46. package/src/client/actions/MessageCreate.js +50 -46
  47. package/src/client/actions/MessageDelete.js +32 -32
  48. package/src/client/actions/MessageDeleteBulk.js +46 -46
  49. package/src/client/actions/MessagePollVoteAdd.js +33 -0
  50. package/src/client/actions/MessagePollVoteRemove.js +33 -0
  51. package/src/client/actions/MessageReactionAdd.js +68 -56
  52. package/src/client/actions/MessageReactionRemove.js +50 -45
  53. package/src/client/actions/MessageReactionRemoveAll.js +33 -33
  54. package/src/client/actions/MessageReactionRemoveEmoji.js +28 -28
  55. package/src/client/actions/MessageUpdate.js +26 -26
  56. package/src/client/actions/PresenceUpdate.js +50 -46
  57. package/src/client/actions/StageInstanceCreate.js +28 -28
  58. package/src/client/actions/StageInstanceDelete.js +33 -33
  59. package/src/client/actions/StageInstanceUpdate.js +30 -30
  60. package/src/client/actions/ThreadCreate.js +24 -24
  61. package/src/client/actions/ThreadDelete.js +32 -32
  62. package/src/client/actions/ThreadListSync.js +59 -59
  63. package/src/client/actions/ThreadMemberUpdate.js +30 -30
  64. package/src/client/actions/ThreadMembersUpdate.js +34 -34
  65. package/src/client/actions/TypingStart.js +29 -29
  66. package/src/client/actions/UserUpdate.js +35 -35
  67. package/src/client/actions/VoiceStateUpdate.js +50 -57
  68. package/src/client/actions/WebhooksUpdate.js +20 -20
  69. package/src/client/voice/ClientVoiceManager.js +151 -51
  70. package/src/client/voice/VoiceConnection.js +1249 -0
  71. package/src/client/voice/dispatcher/AnnexBDispatcher.js +120 -0
  72. package/src/client/voice/dispatcher/AudioDispatcher.js +145 -0
  73. package/src/client/voice/dispatcher/BaseDispatcher.js +459 -0
  74. package/src/client/voice/dispatcher/VPxDispatcher.js +54 -0
  75. package/src/client/voice/dispatcher/VideoDispatcher.js +68 -0
  76. package/src/client/voice/networking/VoiceUDPClient.js +173 -0
  77. package/src/client/voice/networking/VoiceWebSocket.js +286 -0
  78. package/src/client/voice/player/MediaPlayer.js +321 -0
  79. package/src/client/voice/player/processing/AnnexBNalSplitter.js +244 -0
  80. package/src/client/voice/player/processing/IvfSplitter.js +106 -0
  81. package/src/client/voice/player/processing/PCMInsertSilence.js +37 -0
  82. package/src/client/voice/receiver/PacketHandler.js +260 -0
  83. package/src/client/voice/receiver/Receiver.js +96 -0
  84. package/src/client/voice/receiver/Recorder.js +173 -0
  85. package/src/client/voice/util/Function.js +116 -0
  86. package/src/client/voice/util/PlayInterface.js +122 -0
  87. package/src/client/voice/util/Secretbox.js +64 -0
  88. package/src/client/voice/util/Silence.js +16 -0
  89. package/src/client/voice/util/Socket.js +62 -0
  90. package/src/client/voice/util/VolumeInterface.js +104 -0
  91. package/src/client/websocket/WebSocketManager.js +392 -392
  92. package/src/client/websocket/WebSocketShard.js +907 -906
  93. package/src/client/websocket/handlers/APPLICATION_COMMAND_CREATE.js +18 -18
  94. package/src/client/websocket/handlers/APPLICATION_COMMAND_DELETE.js +20 -20
  95. package/src/client/websocket/handlers/APPLICATION_COMMAND_PERMISSIONS_UPDATE.js +5 -5
  96. package/src/client/websocket/handlers/APPLICATION_COMMAND_UPDATE.js +20 -20
  97. package/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js +5 -5
  98. package/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js +5 -5
  99. package/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js +5 -5
  100. package/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js +5 -5
  101. package/src/client/websocket/handlers/CALL_CREATE.js +14 -14
  102. package/src/client/websocket/handlers/CALL_DELETE.js +11 -11
  103. package/src/client/websocket/handlers/CALL_UPDATE.js +11 -11
  104. package/src/client/websocket/handlers/CHANNEL_CREATE.js +5 -5
  105. package/src/client/websocket/handlers/CHANNEL_DELETE.js +5 -5
  106. package/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js +22 -22
  107. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +19 -19
  108. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +16 -16
  109. package/src/client/websocket/handlers/CHANNEL_UPDATE.js +16 -16
  110. package/src/client/websocket/handlers/GUILD_AUDIT_LOG_ENTRY_CREATE.js +5 -5
  111. package/src/client/websocket/handlers/GUILD_BAN_ADD.js +5 -5
  112. package/src/client/websocket/handlers/GUILD_BAN_REMOVE.js +5 -5
  113. package/src/client/websocket/handlers/GUILD_CREATE.js +52 -53
  114. package/src/client/websocket/handlers/GUILD_DELETE.js +5 -5
  115. package/src/client/websocket/handlers/GUILD_EMOJIS_UPDATE.js +5 -5
  116. package/src/client/websocket/handlers/GUILD_INTEGRATIONS_UPDATE.js +5 -5
  117. package/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js +39 -39
  118. package/src/client/websocket/handlers/GUILD_MEMBER_ADD.js +20 -20
  119. package/src/client/websocket/handlers/GUILD_MEMBER_REMOVE.js +5 -5
  120. package/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js +5 -5
  121. package/src/client/websocket/handlers/GUILD_ROLE_CREATE.js +5 -5
  122. package/src/client/websocket/handlers/GUILD_ROLE_DELETE.js +5 -5
  123. package/src/client/websocket/handlers/GUILD_ROLE_UPDATE.js +5 -5
  124. package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_CREATE.js +5 -5
  125. package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_DELETE.js +5 -5
  126. package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_UPDATE.js +5 -5
  127. package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_ADD.js +5 -5
  128. package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_REMOVE.js +5 -5
  129. package/src/client/websocket/handlers/GUILD_STICKERS_UPDATE.js +5 -5
  130. package/src/client/websocket/handlers/GUILD_UPDATE.js +5 -5
  131. package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +12 -12
  132. package/src/client/websocket/handlers/INVITE_CREATE.js +5 -5
  133. package/src/client/websocket/handlers/INVITE_DELETE.js +5 -5
  134. package/src/client/websocket/handlers/MESSAGE_CREATE.js +5 -5
  135. package/src/client/websocket/handlers/MESSAGE_DELETE.js +5 -5
  136. package/src/client/websocket/handlers/MESSAGE_DELETE_BULK.js +5 -5
  137. package/src/client/websocket/handlers/MESSAGE_POLL_VOTE_ADD.js +5 -0
  138. package/src/client/websocket/handlers/MESSAGE_POLL_VOTE_REMOVE.js +5 -0
  139. package/src/client/websocket/handlers/MESSAGE_REACTION_ADD.js +5 -5
  140. package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE.js +5 -5
  141. package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_ALL.js +5 -5
  142. package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_EMOJI.js +5 -5
  143. package/src/client/websocket/handlers/MESSAGE_UPDATE.js +16 -16
  144. package/src/client/websocket/handlers/PRESENCE_UPDATE.js +5 -5
  145. package/src/client/websocket/handlers/READY.js +121 -80
  146. package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +19 -19
  147. package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +17 -17
  148. package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +41 -41
  149. package/src/client/websocket/handlers/RESUMED.js +14 -14
  150. package/src/client/websocket/handlers/STAGE_INSTANCE_CREATE.js +5 -5
  151. package/src/client/websocket/handlers/STAGE_INSTANCE_DELETE.js +5 -5
  152. package/src/client/websocket/handlers/STAGE_INSTANCE_UPDATE.js +5 -5
  153. package/src/client/websocket/handlers/THREAD_CREATE.js +5 -5
  154. package/src/client/websocket/handlers/THREAD_DELETE.js +5 -5
  155. package/src/client/websocket/handlers/THREAD_LIST_SYNC.js +5 -5
  156. package/src/client/websocket/handlers/THREAD_MEMBERS_UPDATE.js +5 -5
  157. package/src/client/websocket/handlers/THREAD_MEMBER_UPDATE.js +5 -5
  158. package/src/client/websocket/handlers/THREAD_UPDATE.js +16 -16
  159. package/src/client/websocket/handlers/TYPING_START.js +5 -5
  160. package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +6 -6
  161. package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +5 -5
  162. package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +78 -78
  163. package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +5 -5
  164. package/src/client/websocket/handlers/USER_UPDATE.js +5 -5
  165. package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +16 -0
  166. package/src/client/websocket/handlers/VOICE_CHANNEL_STATUS_UPDATE.js +12 -12
  167. package/src/client/websocket/handlers/VOICE_SERVER_UPDATE.js +6 -6
  168. package/src/client/websocket/handlers/VOICE_STATE_UPDATE.js +5 -5
  169. package/src/client/websocket/handlers/WEBHOOKS_UPDATE.js +5 -5
  170. package/src/client/websocket/handlers/index.js +84 -81
  171. package/src/errors/DJSError.js +61 -61
  172. package/src/errors/Messages.js +217 -182
  173. package/src/errors/index.js +4 -4
  174. package/src/index.js +172 -158
  175. package/src/managers/ApplicationCommandManager.js +264 -264
  176. package/src/managers/ApplicationCommandPermissionsManager.js +417 -417
  177. package/src/managers/AutoModerationRuleManager.js +296 -296
  178. package/src/managers/BaseGuildEmojiManager.js +80 -80
  179. package/src/managers/BaseManager.js +19 -19
  180. package/src/managers/BillingManager.js +66 -66
  181. package/src/managers/CachedManager.js +71 -71
  182. package/src/managers/ChannelManager.js +148 -138
  183. package/src/managers/ClientUserSettingManager.js +372 -372
  184. package/src/managers/DataManager.js +61 -61
  185. package/src/managers/GuildBanManager.js +250 -204
  186. package/src/managers/GuildChannelManager.js +488 -504
  187. package/src/managers/GuildEmojiManager.js +171 -171
  188. package/src/managers/GuildEmojiRoleManager.js +118 -118
  189. package/src/managers/GuildForumThreadManager.js +108 -108
  190. package/src/managers/GuildInviteManager.js +213 -213
  191. package/src/managers/GuildManager.js +338 -304
  192. package/src/managers/GuildMemberManager.js +599 -593
  193. package/src/managers/GuildMemberRoleManager.js +195 -191
  194. package/src/managers/GuildScheduledEventManager.js +314 -296
  195. package/src/managers/GuildSettingManager.js +155 -155
  196. package/src/managers/GuildStickerManager.js +179 -179
  197. package/src/managers/GuildTextThreadManager.js +98 -98
  198. package/src/managers/InteractionManager.js +39 -39
  199. package/src/managers/MessageManager.js +423 -391
  200. package/src/managers/PermissionOverwriteManager.js +164 -166
  201. package/src/managers/PresenceManager.js +71 -58
  202. package/src/managers/ReactionManager.js +67 -67
  203. package/src/managers/ReactionUserManager.js +73 -71
  204. package/src/managers/RelationshipManager.js +278 -265
  205. package/src/managers/RoleManager.js +448 -352
  206. package/src/managers/SessionManager.js +66 -0
  207. package/src/managers/StageInstanceManager.js +162 -162
  208. package/src/managers/ThreadManager.js +175 -174
  209. package/src/managers/ThreadMemberManager.js +186 -186
  210. package/src/managers/UserManager.js +136 -146
  211. package/src/managers/UserNoteManager.js +53 -53
  212. package/src/managers/VoiceStateManager.js +59 -37
  213. package/src/rest/APIRequest.js +154 -154
  214. package/src/rest/APIRouter.js +53 -53
  215. package/src/rest/DiscordAPIError.js +119 -104
  216. package/src/rest/HTTPError.js +62 -62
  217. package/src/rest/RESTManager.js +67 -62
  218. package/src/rest/RateLimitError.js +55 -55
  219. package/src/rest/RequestHandler.js +466 -444
  220. package/src/sharding/Shard.js +444 -443
  221. package/src/sharding/ShardClientUtil.js +279 -275
  222. package/src/sharding/ShardingManager.js +319 -318
  223. package/src/structures/AnonymousGuild.js +98 -98
  224. package/src/structures/ApplicationCommand.js +593 -593
  225. package/src/structures/ApplicationRoleConnectionMetadata.js +48 -48
  226. package/src/structures/AutoModerationActionExecution.js +89 -89
  227. package/src/structures/AutoModerationRule.js +294 -294
  228. package/src/structures/AutocompleteInteraction.js +107 -107
  229. package/src/structures/Base.js +43 -43
  230. package/src/structures/BaseCommandInteraction.js +211 -211
  231. package/src/structures/BaseGuild.js +116 -116
  232. package/src/structures/BaseGuildEmoji.js +56 -56
  233. package/src/structures/BaseGuildTextChannel.js +191 -191
  234. package/src/structures/BaseGuildVoiceChannel.js +241 -241
  235. package/src/structures/BaseMessageComponent.js +181 -114
  236. package/src/structures/ButtonInteraction.js +11 -11
  237. package/src/structures/CallState.js +63 -63
  238. package/src/structures/CategoryChannel.js +85 -85
  239. package/src/structures/Channel.js +284 -270
  240. package/src/structures/ClientPresence.js +77 -88
  241. package/src/structures/ClientUser.js +479 -450
  242. package/src/structures/CommandInteraction.js +41 -41
  243. package/src/structures/CommandInteractionOptionResolver.js +276 -276
  244. package/src/structures/ContainerComponent.js +68 -0
  245. package/src/structures/ContextMenuInteraction.js +65 -65
  246. package/src/structures/DMChannel.js +219 -217
  247. package/src/structures/DirectoryChannel.js +20 -20
  248. package/src/structures/Emoji.js +148 -148
  249. package/src/structures/FileComponent.js +49 -0
  250. package/src/structures/ForumChannel.js +31 -261
  251. package/src/structures/GroupDMChannel.js +394 -387
  252. package/src/structures/Guild.js +1643 -1608
  253. package/src/structures/GuildAuditLogs.js +746 -729
  254. package/src/structures/GuildBan.js +59 -59
  255. package/src/structures/GuildBoost.js +108 -108
  256. package/src/structures/GuildChannel.js +470 -468
  257. package/src/structures/GuildEmoji.js +161 -161
  258. package/src/structures/GuildMember.js +636 -568
  259. package/src/structures/GuildPreview.js +191 -191
  260. package/src/structures/GuildPreviewEmoji.js +27 -27
  261. package/src/structures/GuildScheduledEvent.js +536 -441
  262. package/src/structures/GuildTemplate.js +236 -236
  263. package/src/structures/Integration.js +188 -188
  264. package/src/structures/IntegrationApplication.js +96 -96
  265. package/src/structures/Interaction.js +290 -290
  266. package/src/structures/InteractionCollector.js +248 -248
  267. package/src/structures/InteractionWebhook.js +43 -43
  268. package/src/structures/Invite.js +358 -358
  269. package/src/structures/InviteGuild.js +23 -23
  270. package/src/structures/InviteStageInstance.js +86 -86
  271. package/src/structures/MediaChannel.js +11 -0
  272. package/src/structures/MediaGalleryComponent.js +41 -0
  273. package/src/structures/MediaGalleryItem.js +47 -0
  274. package/src/structures/Message.js +1252 -1236
  275. package/src/structures/MessageActionRow.js +105 -103
  276. package/src/structures/MessageAttachment.js +216 -204
  277. package/src/structures/MessageButton.js +166 -165
  278. package/src/structures/MessageCollector.js +146 -146
  279. package/src/structures/MessageComponentInteraction.js +120 -120
  280. package/src/structures/MessageContextMenuInteraction.js +20 -20
  281. package/src/structures/MessageEmbed.js +596 -586
  282. package/src/structures/MessageMentions.js +273 -273
  283. package/src/structures/MessagePayload.js +354 -316
  284. package/src/structures/MessageReaction.js +181 -171
  285. package/src/structures/MessageSelectMenu.js +141 -140
  286. package/src/structures/Modal.js +161 -174
  287. package/src/structures/ModalSubmitFieldsResolver.js +53 -53
  288. package/src/structures/ModalSubmitInteraction.js +119 -119
  289. package/src/structures/NewsChannel.js +32 -32
  290. package/src/structures/OAuth2Guild.js +28 -28
  291. package/src/structures/PermissionOverwrites.js +198 -196
  292. package/src/structures/Poll.js +108 -0
  293. package/src/structures/PollAnswer.js +88 -0
  294. package/src/structures/Presence.js +1105 -443
  295. package/src/structures/ReactionCollector.js +229 -229
  296. package/src/structures/ReactionEmoji.js +31 -31
  297. package/src/structures/Role.js +590 -531
  298. package/src/structures/SectionComponent.js +48 -0
  299. package/src/structures/SelectMenuInteraction.js +21 -21
  300. package/src/structures/SeparatorComponent.js +48 -0
  301. package/src/structures/Session.js +81 -0
  302. package/src/structures/StageChannel.js +104 -104
  303. package/src/structures/StageInstance.js +208 -208
  304. package/src/structures/Sticker.js +310 -310
  305. package/src/structures/StickerPack.js +95 -95
  306. package/src/structures/StoreChannel.js +56 -56
  307. package/src/structures/Team.js +118 -118
  308. package/src/structures/TeamMember.js +80 -71
  309. package/src/structures/TextChannel.js +33 -33
  310. package/src/structures/TextDisplayComponent.js +40 -0
  311. package/src/structures/TextInputComponent.js +132 -131
  312. package/src/structures/ThreadChannel.js +605 -607
  313. package/src/structures/ThreadMember.js +105 -105
  314. package/src/structures/ThreadOnlyChannel.js +249 -0
  315. package/src/structures/ThumbnailComponent.js +57 -0
  316. package/src/structures/Typing.js +74 -74
  317. package/src/structures/UnfurledMediaItem.js +29 -0
  318. package/src/structures/User.js +640 -509
  319. package/src/structures/UserContextMenuInteraction.js +29 -29
  320. package/src/structures/VoiceChannel.js +110 -110
  321. package/src/structures/VoiceChannelEffect.js +69 -0
  322. package/src/structures/VoiceRegion.js +53 -53
  323. package/src/structures/VoiceState.js +354 -341
  324. package/src/structures/WebEmbed.js +373 -373
  325. package/src/structures/Webhook.js +478 -467
  326. package/src/structures/WelcomeChannel.js +60 -60
  327. package/src/structures/WelcomeScreen.js +48 -48
  328. package/src/structures/Widget.js +87 -87
  329. package/src/structures/WidgetMember.js +99 -99
  330. package/src/structures/interfaces/Application.js +825 -313
  331. package/src/structures/interfaces/Collector.js +300 -300
  332. package/src/structures/interfaces/InteractionResponses.js +313 -313
  333. package/src/structures/interfaces/TextBasedChannel.js +759 -721
  334. package/src/util/APITypes.js +59 -0
  335. package/src/util/ActivityFlags.js +44 -44
  336. package/src/util/ApplicationFlags.js +76 -76
  337. package/src/util/AttachmentFlags.js +38 -38
  338. package/src/util/BitField.js +170 -170
  339. package/src/util/ChannelFlags.js +45 -45
  340. package/src/util/Constants.js +1914 -1760
  341. package/src/util/DataResolver.js +146 -145
  342. package/src/util/Formatters.js +228 -228
  343. package/src/util/GuildMemberFlags.js +43 -43
  344. package/src/util/Intents.js +74 -74
  345. package/src/util/InviteFlags.js +34 -29
  346. package/src/util/LimitedCollection.js +131 -131
  347. package/src/util/MessageFlags.js +63 -54
  348. package/src/util/Options.js +358 -342
  349. package/src/util/Permissions.js +202 -192
  350. package/src/util/PremiumUsageFlags.js +31 -31
  351. package/src/util/PurchasedFlags.js +33 -33
  352. package/src/util/RemoteAuth.js +382 -379
  353. package/src/util/RoleFlags.js +37 -37
  354. package/src/util/SnowflakeUtil.js +92 -92
  355. package/src/util/Speaking.js +33 -0
  356. package/src/util/Sweepers.js +466 -466
  357. package/src/util/SystemChannelFlags.js +55 -55
  358. package/src/util/ThreadMemberFlags.js +30 -30
  359. package/src/util/UserFlags.js +104 -104
  360. package/src/util/Util.js +1048 -803
  361. package/typings/enums.d.ts +439 -291
  362. package/typings/index.d.ts +8247 -7390
  363. package/typings/rawDataTypes.d.ts +403 -342
  364. package/src/structures/RichPresence.js +0 -702
@@ -1,1236 +1,1252 @@
1
- 'use strict';
2
-
3
- const process = require('node:process');
4
- const { setTimeout } = require('node:timers');
5
- const { Collection } = require('@discordjs/collection');
6
- const Base = require('./Base');
7
- const BaseMessageComponent = require('./BaseMessageComponent');
8
- const MessageAttachment = require('./MessageAttachment');
9
- const Embed = require('./MessageEmbed');
10
- const Mentions = require('./MessageMentions');
11
- const MessagePayload = require('./MessagePayload');
12
- const ReactionCollector = require('./ReactionCollector');
13
- const { Sticker } = require('./Sticker');
14
- const Application = require('./interfaces/Application');
15
- const { Error } = require('../errors');
16
- const ReactionManager = require('../managers/ReactionManager');
17
- const {
18
- InteractionTypes,
19
- MessageTypes,
20
- SystemMessageTypes,
21
- MessageComponentTypes,
22
- Events,
23
- } = require('../util/Constants');
24
- const MessageFlags = require('../util/MessageFlags');
25
- const Permissions = require('../util/Permissions');
26
- const SnowflakeUtil = require('../util/SnowflakeUtil');
27
- const Util = require('../util/Util');
28
-
29
- /**
30
- * @type {WeakSet<Message>}
31
- * @private
32
- * @internal
33
- */
34
- const deletedMessages = new WeakSet();
35
- let deprecationEmittedForDeleted = false;
36
-
37
- /**
38
- * Represents a message on Discord.
39
- * @extends {Base}
40
- */
41
- class Message extends Base {
42
- constructor(client, data) {
43
- super(client);
44
-
45
- /**
46
- * The id of the channel the message was sent in
47
- * @type {Snowflake}
48
- */
49
- this.channelId = data.channel_id;
50
-
51
- /**
52
- * The id of the guild the message was sent in, if any
53
- * @type {?Snowflake}
54
- */
55
- this.guildId = data.guild_id ?? this.channel?.guild?.id ?? null;
56
-
57
- this._patch(data);
58
- }
59
-
60
- _patch(data) {
61
- /**
62
- * The message's id
63
- * @type {Snowflake}
64
- */
65
- this.id = data.id;
66
-
67
- if ('position' in data) {
68
- /**
69
- * A generally increasing integer (there may be gaps or duplicates) that represents
70
- * the approximate position of the message in a thread.
71
- * @type {?number}
72
- */
73
- this.position = data.position;
74
- } else {
75
- this.position ??= null;
76
- }
77
-
78
- /**
79
- * The timestamp the message was sent at
80
- * @type {number}
81
- */
82
- this.createdTimestamp = SnowflakeUtil.timestampFrom(this.id);
83
-
84
- if ('type' in data) {
85
- /**
86
- * The type of the message
87
- * @type {?MessageType}
88
- */
89
- this.type = MessageTypes[data.type];
90
-
91
- /**
92
- * Whether or not this message was sent by Discord, not actually a user (e.g. pin notifications)
93
- * @type {?boolean}
94
- */
95
- this.system = SystemMessageTypes.includes(this.type);
96
- } else {
97
- this.system ??= null;
98
- this.type ??= null;
99
- }
100
-
101
- if ('content' in data) {
102
- /**
103
- * The content of the message
104
- * @type {?string}
105
- */
106
- this.content = data.content;
107
- } else {
108
- this.content ??= null;
109
- }
110
-
111
- if ('author' in data) {
112
- /**
113
- * The author of the message
114
- * @type {?User}
115
- */
116
- this.author = this.client.users._add(data.author, !data.webhook_id);
117
- } else {
118
- this.author ??= null;
119
- }
120
-
121
- if ('pinned' in data) {
122
- /**
123
- * Whether or not this message is pinned
124
- * @type {?boolean}
125
- */
126
- this.pinned = Boolean(data.pinned);
127
- } else {
128
- this.pinned ??= null;
129
- }
130
-
131
- if ('tts' in data) {
132
- /**
133
- * Whether or not the message was Text-To-Speech
134
- * @type {?boolean}
135
- */
136
- this.tts = data.tts;
137
- } else {
138
- this.tts ??= null;
139
- }
140
-
141
- if ('nonce' in data) {
142
- /**
143
- * A random number or string used for checking message delivery
144
- * <warn>This is only received after the message was sent successfully, and
145
- * lost if re-fetched</warn>
146
- * @type {?string}
147
- */
148
- this.nonce = data.nonce;
149
- } else {
150
- this.nonce ??= null;
151
- }
152
-
153
- if ('embeds' in data) {
154
- /**
155
- * A list of embeds in the message - e.g. YouTube Player
156
- * @type {MessageEmbed[]}
157
- */
158
- this.embeds = data.embeds.map(e => new Embed(e, true));
159
- } else {
160
- this.embeds = this.embeds?.slice() ?? [];
161
- }
162
-
163
- if ('components' in data) {
164
- /**
165
- * A list of MessageActionRows in the message
166
- * @type {MessageActionRow[]}
167
- */
168
- this.components = data.components.map(c => BaseMessageComponent.create(c, this.client));
169
- } else {
170
- this.components = this.components?.slice() ?? [];
171
- }
172
-
173
- if ('attachments' in data) {
174
- /**
175
- * A collection of attachments in the message - e.g. Pictures - mapped by their ids
176
- * @type {Collection<Snowflake, MessageAttachment>}
177
- */
178
- this.attachments = new Collection();
179
- if (data.attachments) {
180
- for (const attachment of data.attachments) {
181
- this.attachments.set(attachment.id, new MessageAttachment(attachment.url, attachment.filename, attachment));
182
- }
183
- }
184
- } else {
185
- this.attachments = new Collection(this.attachments);
186
- }
187
-
188
- if ('sticker_items' in data || 'stickers' in data) {
189
- /**
190
- * A collection of stickers in the message
191
- * @type {Collection<Snowflake, Sticker>}
192
- */
193
- this.stickers = new Collection(
194
- (data.sticker_items ?? data.stickers)?.map(s => [s.id, new Sticker(this.client, s)]),
195
- );
196
- } else {
197
- this.stickers = new Collection(this.stickers);
198
- }
199
-
200
- // Discord sends null if the message has not been edited
201
- if (data.edited_timestamp) {
202
- /**
203
- * The timestamp the message was last edited at (if applicable)
204
- * @type {?number}
205
- */
206
- this.editedTimestamp = new Date(data.edited_timestamp).getTime();
207
- } else {
208
- this.editedTimestamp ??= null;
209
- }
210
-
211
- if ('reactions' in data) {
212
- /**
213
- * A manager of the reactions belonging to this message
214
- * @type {ReactionManager}
215
- */
216
- this.reactions = new ReactionManager(this);
217
- if (data.reactions?.length > 0) {
218
- for (const reaction of data.reactions) {
219
- this.reactions._add(reaction);
220
- }
221
- }
222
- } else {
223
- this.reactions ??= new ReactionManager(this);
224
- }
225
-
226
- if (!this.mentions) {
227
- /**
228
- * All valid mentions that the message contains
229
- * @type {MessageMentions}
230
- */
231
- this.mentions = new Mentions(
232
- this,
233
- data.mentions,
234
- data.mention_roles,
235
- data.mention_everyone,
236
- data.mention_channels,
237
- data.referenced_message?.author,
238
- );
239
- } else {
240
- this.mentions = new Mentions(
241
- this,
242
- data.mentions ?? this.mentions.users,
243
- data.mention_roles ?? this.mentions.roles,
244
- data.mention_everyone ?? this.mentions.everyone,
245
- data.mention_channels ?? this.mentions.crosspostedChannels,
246
- data.referenced_message?.author ?? this.mentions.repliedUser,
247
- );
248
- }
249
-
250
- if ('webhook_id' in data) {
251
- /**
252
- * The id of the webhook that sent the message, if applicable
253
- * @type {?Snowflake}
254
- */
255
- this.webhookId = data.webhook_id;
256
- } else {
257
- this.webhookId ??= null;
258
- }
259
-
260
- if ('application' in data) {
261
- /**
262
- * Supplemental application information for group activities
263
- * @type {?Application}
264
- */
265
- this.groupActivityApplication = new Application(this.client, data.application);
266
- } else {
267
- this.groupActivityApplication ??= null;
268
- }
269
-
270
- if ('application_id' in data) {
271
- /**
272
- * The id of the application of the interaction that sent this message, if any
273
- * @type {?Snowflake}
274
- */
275
- this.applicationId = data.application_id;
276
- } else {
277
- this.applicationId ??= null;
278
- }
279
-
280
- if ('activity' in data) {
281
- /**
282
- * Group activity
283
- * @type {?MessageActivity}
284
- */
285
- this.activity = {
286
- partyId: data.activity.party_id,
287
- type: data.activity.type,
288
- };
289
- } else {
290
- this.activity ??= null;
291
- }
292
-
293
- if ('thread' in data) {
294
- this.client.channels._add(data.thread, this.guild);
295
- }
296
-
297
- if (this.member && data.member) {
298
- this.member._patch(data.member);
299
- } else if (data.member && this.guild && this.author) {
300
- this.guild.members._add(Object.assign(data.member, { user: this.author }));
301
- }
302
-
303
- if ('flags' in data) {
304
- /**
305
- * Flags that are applied to the message
306
- * @type {Readonly<MessageFlags>}
307
- */
308
- this.flags = new MessageFlags(data.flags).freeze();
309
- } else {
310
- this.flags = new MessageFlags(this.flags).freeze();
311
- }
312
-
313
- /**
314
- * Reference data sent in a message that contains ids identifying the referenced message.
315
- * This can be present in the following types of message:
316
- * * Crossposted messages (IS_CROSSPOST {@link MessageFlags.FLAGS message flag})
317
- * * CHANNEL_FOLLOW_ADD
318
- * * CHANNEL_PINNED_MESSAGE
319
- * * REPLY
320
- * * THREAD_STARTER_MESSAGE
321
- * @see {@link https://discord.com/developers/docs/resources/channel#message-types}
322
- * @typedef {Object} MessageReference
323
- * @property {Snowflake} channelId The channel's id the message was referenced
324
- * @property {?Snowflake} guildId The guild's id the message was referenced
325
- * @property {?Snowflake} messageId The message's id that was referenced
326
- */
327
-
328
- if ('message_reference' in data) {
329
- /**
330
- * Message reference data
331
- * @type {?MessageReference}
332
- */
333
- this.reference = {
334
- channelId: data.message_reference.channel_id,
335
- guildId: data.message_reference.guild_id,
336
- messageId: data.message_reference.message_id,
337
- };
338
- } else {
339
- this.reference ??= null;
340
- }
341
-
342
- if (data.referenced_message) {
343
- this.channel?.messages._add({ guild_id: data.message_reference?.guild_id, ...data.referenced_message });
344
- }
345
-
346
- /**
347
- * Partial data of the interaction that a message is a reply to
348
- * @typedef {Object} MessageInteraction
349
- * @property {Snowflake} id The interaction's id
350
- * @property {InteractionType} type The type of the interaction
351
- * @property {string} commandName The name of the interaction's application command,
352
- * as well as the subcommand and subcommand group, where applicable
353
- * @property {User} user The user that invoked the interaction
354
- */
355
-
356
- if (data.interaction) {
357
- /**
358
- * Partial data of the interaction that this message is a reply to
359
- * @type {?MessageInteraction}
360
- */
361
- this.interaction = {
362
- id: data.interaction.id,
363
- type: InteractionTypes[data.interaction.type],
364
- commandName: data.interaction.name,
365
- user: this.client.users._add(data.interaction.user),
366
- };
367
- } else {
368
- this.interaction ??= null;
369
- }
370
- }
371
-
372
- /**
373
- * Whether or not the structure has been deleted
374
- * @type {boolean}
375
- * @deprecated This will be removed in the next major version, see https://github.com/discordjs/discord.js/issues/7091
376
- */
377
- get deleted() {
378
- if (!deprecationEmittedForDeleted) {
379
- deprecationEmittedForDeleted = true;
380
- process.emitWarning(
381
- 'Message#deleted is deprecated, see https://github.com/discordjs/discord.js/issues/7091.',
382
- 'DeprecationWarning',
383
- );
384
- }
385
-
386
- return deletedMessages.has(this);
387
- }
388
-
389
- set deleted(value) {
390
- if (!deprecationEmittedForDeleted) {
391
- deprecationEmittedForDeleted = true;
392
- process.emitWarning(
393
- 'Message#deleted is deprecated, see https://github.com/discordjs/discord.js/issues/7091.',
394
- 'DeprecationWarning',
395
- );
396
- }
397
-
398
- if (value) deletedMessages.add(this);
399
- else deletedMessages.delete(this);
400
- }
401
-
402
- /**
403
- * The channel that the message was sent in
404
- * @type {TextBasedChannels}
405
- * @readonly
406
- */
407
- get channel() {
408
- return this.client.channels.resolve(this.channelId);
409
- }
410
-
411
- /**
412
- * Whether or not this message is a partial
413
- * @type {boolean}
414
- * @readonly
415
- */
416
- get partial() {
417
- return typeof this.content !== 'string' || !this.author;
418
- }
419
-
420
- /**
421
- * Represents the author of the message as a guild member.
422
- * Only available if the message comes from a guild where the author is still a member
423
- * @type {?GuildMember}
424
- * @readonly
425
- */
426
- get member() {
427
- return this.guild?.members.resolve(this.author) ?? null;
428
- }
429
-
430
- /**
431
- * The time the message was sent at
432
- * @type {Date}
433
- * @readonly
434
- */
435
- get createdAt() {
436
- return new Date(this.createdTimestamp);
437
- }
438
-
439
- /**
440
- * The time the message was last edited at (if applicable)
441
- * @type {?Date}
442
- * @readonly
443
- */
444
- get editedAt() {
445
- return this.editedTimestamp ? new Date(this.editedTimestamp) : null;
446
- }
447
-
448
- /**
449
- * The guild the message was sent in (if in a guild channel)
450
- * @type {?Guild}
451
- * @readonly
452
- */
453
- get guild() {
454
- return this.client.guilds.resolve(this.guildId) ?? this.channel?.guild ?? null;
455
- }
456
-
457
- /**
458
- * Whether this message has a thread associated with it
459
- * @type {boolean}
460
- * @readonly
461
- */
462
- get hasThread() {
463
- return this.flags.has(MessageFlags.FLAGS.HAS_THREAD);
464
- }
465
-
466
- /**
467
- * The thread started by this message
468
- * <info>This property is not suitable for checking whether a message has a thread,
469
- * use {@link Message#hasThread} instead.</info>
470
- * @type {?ThreadChannel}
471
- * @readonly
472
- */
473
- get thread() {
474
- return this.channel?.threads?.resolve(this.id) ?? null;
475
- }
476
-
477
- /**
478
- * The URL to jump to this message
479
- * @type {string}
480
- * @readonly
481
- */
482
- get url() {
483
- return `https://discord.com/channels/${this.guildId ?? '@me'}/${this.channelId}/${this.id}`;
484
- }
485
-
486
- /**
487
- * The message contents with all mentions replaced by the equivalent text.
488
- * If mentions cannot be resolved to a name, the relevant mention in the message content will not be converted.
489
- * @type {?string}
490
- * @readonly
491
- */
492
- get cleanContent() {
493
- // eslint-disable-next-line eqeqeq
494
- return this.content != null ? Util.cleanContent(this.content, this.channel) : null;
495
- }
496
-
497
- /**
498
- * Creates a reaction collector.
499
- * @param {ReactionCollectorOptions} [options={}] Options to send to the collector
500
- * @returns {ReactionCollector}
501
- * @example
502
- * // Create a reaction collector
503
- * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId';
504
- * const collector = message.createReactionCollector({ filter, time: 15_000 });
505
- * collector.on('collect', r => console.log(`Collected ${r.emoji.name}`));
506
- * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
507
- */
508
- createReactionCollector(options = {}) {
509
- return new ReactionCollector(this, options);
510
- }
511
-
512
- /**
513
- * An object containing the same properties as CollectorOptions, but a few more:
514
- * @typedef {ReactionCollectorOptions} AwaitReactionsOptions
515
- * @property {string[]} [errors] Stop/end reasons that cause the promise to reject
516
- */
517
-
518
- /**
519
- * Similar to createReactionCollector but in promise form.
520
- * Resolves with a collection of reactions that pass the specified filter.
521
- * @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
522
- * @returns {Promise<Collection<string | Snowflake, MessageReaction>>}
523
- * @example
524
- * // Create a reaction collector
525
- * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId'
526
- * message.awaitReactions({ filter, time: 15_000 })
527
- * .then(collected => console.log(`Collected ${collected.size} reactions`))
528
- * .catch(console.error);
529
- */
530
- awaitReactions(options = {}) {
531
- return new Promise((resolve, reject) => {
532
- const collector = this.createReactionCollector(options);
533
- collector.once('end', (reactions, reason) => {
534
- if (options.errors?.includes(reason)) reject(reactions);
535
- else resolve(reactions);
536
- });
537
- });
538
- }
539
-
540
- /**
541
- * Whether the message is editable by the client user
542
- * @type {boolean}
543
- * @readonly
544
- */
545
- get editable() {
546
- const precheck = Boolean(
547
- this.author.id === this.client.user.id && !deletedMessages.has(this) && (!this.guild || this.channel?.viewable),
548
- );
549
-
550
- // Regardless of permissions thread messages cannot be edited if
551
- // the thread is archived or the thread is locked and the bot does not have permission to manage threads.
552
- if (this.channel?.isThread()) {
553
- if (this.channel.archived) return false;
554
- if (this.channel.locked) {
555
- const permissions = this.channel.permissionsFor(this.client.user);
556
- if (!permissions?.has(Permissions.FLAGS.MANAGE_THREADS, true)) return false;
557
- }
558
- }
559
-
560
- return precheck;
561
- }
562
-
563
- /**
564
- * Whether the message is deletable by the client user
565
- * @type {boolean}
566
- * @readonly
567
- */
568
- get deletable() {
569
- if (deletedMessages.has(this)) {
570
- return false;
571
- }
572
- if (!this.guild) {
573
- return this.author.id === this.client.user.id;
574
- }
575
- // DMChannel does not have viewable property, so check viewable after proved that message is on a guild.
576
- if (!this.channel?.viewable) {
577
- return false;
578
- }
579
-
580
- const permissions = this.channel?.permissionsFor(this.client.user);
581
- if (!permissions) return false;
582
- // This flag allows deleting even if timed out
583
- if (permissions.has(Permissions.FLAGS.ADMINISTRATOR, false)) return true;
584
-
585
- return Boolean(
586
- this.author.id === this.client.user.id ||
587
- (permissions.has(Permissions.FLAGS.MANAGE_MESSAGES, false) &&
588
- this.guild.members.me.communicationDisabledUntilTimestamp < Date.now()),
589
- );
590
- }
591
-
592
- /**
593
- * Whether the message is bulk deletable by the client user
594
- * @type {boolean}
595
- * @readonly
596
- * @example
597
- * // Filter for bulk deletable messages
598
- * channel.bulkDelete(messages.filter(message => message.bulkDeletable));
599
- */
600
- get bulkDeletable() {
601
- return false;
602
- }
603
-
604
- /**
605
- * Whether the message is pinnable by the client user
606
- * @type {boolean}
607
- * @readonly
608
- */
609
- get pinnable() {
610
- const { channel } = this;
611
- return Boolean(
612
- !this.system &&
613
- !deletedMessages.has(this) &&
614
- (!this.guild ||
615
- (channel?.viewable &&
616
- channel?.permissionsFor(this.client.user)?.has(Permissions.FLAGS.MANAGE_MESSAGES, false))),
617
- );
618
- }
619
-
620
- /**
621
- * Fetches the Message this crosspost/reply/pin-add references, if available to the client
622
- * @returns {Promise<Message>}
623
- */
624
- async fetchReference() {
625
- if (!this.reference) throw new Error('MESSAGE_REFERENCE_MISSING');
626
- const { channelId, messageId } = this.reference;
627
- const channel = this.client.channels.resolve(channelId);
628
- if (!channel) throw new Error('GUILD_CHANNEL_RESOLVE');
629
- const message = await channel.messages.fetch(messageId);
630
- return message;
631
- }
632
-
633
- /**
634
- * Whether the message is crosspostable by the client user
635
- * @type {boolean}
636
- * @readonly
637
- */
638
- get crosspostable() {
639
- const bitfield =
640
- Permissions.FLAGS.SEND_MESSAGES |
641
- (this.author.id === this.client.user.id ? Permissions.defaultBit : Permissions.FLAGS.MANAGE_MESSAGES);
642
- const { channel } = this;
643
- return Boolean(
644
- channel?.type === 'GUILD_NEWS' &&
645
- !this.flags.has(MessageFlags.FLAGS.CROSSPOSTED) &&
646
- this.type === 'DEFAULT' &&
647
- channel.viewable &&
648
- channel.permissionsFor(this.client.user)?.has(bitfield, false) &&
649
- !deletedMessages.has(this),
650
- );
651
- }
652
-
653
- /**
654
- * Options that can be passed into {@link Message#edit}.
655
- * @typedef {Object} MessageEditOptions
656
- * @property {?string} [content] Content to be edited
657
- * @property {MessageEmbed[]|APIEmbed[]} [embeds] Embeds to be added/edited
658
- * @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content
659
- * @property {MessageFlags} [flags] Which flags to set for the message. Only `SUPPRESS_EMBEDS` can be edited.
660
- * @property {MessageAttachment[]} [attachments] An array of attachments to keep,
661
- * all attachments will be kept if omitted
662
- * @property {FileOptions[]|BufferResolvable[]|MessageAttachment[]} [files] Files to add to the message
663
- * @property {MessageActionRow[]|MessageActionRowOptions[]} [components]
664
- * Action rows containing interactive components for the message (buttons, select menus)
665
- */
666
-
667
- /**
668
- * Edits the content of the message.
669
- * @param {string|MessagePayload|MessageEditOptions} options The options to provide
670
- * @returns {Promise<Message>}
671
- * @example
672
- * // Update the content of a message
673
- * message.edit('This is my new content!')
674
- * .then(msg => console.log(`Updated the content of a message to ${msg.content}`))
675
- * .catch(console.error);
676
- */
677
- edit(options) {
678
- if (!this.channel) return Promise.reject(new Error('CHANNEL_NOT_CACHED'));
679
- return this.channel.messages.edit(this, options);
680
- }
681
-
682
- /**
683
- * Publishes a message in an announcement channel to all channels following it.
684
- * @returns {Promise<Message>}
685
- * @example
686
- * // Crosspost a message
687
- * if (message.channel.type === 'GUILD_NEWS') {
688
- * message.crosspost()
689
- * .then(() => console.log('Crossposted message'))
690
- * .catch(console.error);
691
- * }
692
- */
693
- crosspost() {
694
- if (!this.channel) return Promise.reject(new Error('CHANNEL_NOT_CACHED'));
695
- return this.channel.messages.crosspost(this.id);
696
- }
697
-
698
- /**
699
- * Pins this message to the channel's pinned messages.
700
- * @param {string} [reason] Reason for pinning
701
- * @returns {Promise<Message>}
702
- * @example
703
- * // Pin a message
704
- * message.pin()
705
- * .then(console.log)
706
- * .catch(console.error)
707
- */
708
- async pin(reason) {
709
- if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
710
- await this.channel.messages.pin(this.id, reason);
711
- return this;
712
- }
713
-
714
- /**
715
- * Unpins this message from the channel's pinned messages.
716
- * @param {string} [reason] Reason for unpinning
717
- * @returns {Promise<Message>}
718
- * @example
719
- * // Unpin a message
720
- * message.unpin()
721
- * .then(console.log)
722
- * .catch(console.error)
723
- */
724
- async unpin(reason) {
725
- if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
726
- await this.channel.messages.unpin(this.id, reason);
727
- return this;
728
- }
729
-
730
- /**
731
- * Adds a reaction to the message.
732
- * @param {EmojiIdentifierResolvable} emoji The emoji to react with
733
- * @param {boolean} [burst=false] Super Reactions
734
- * @returns {Promise<MessageReaction>}
735
- * @example
736
- * // React to a message with a unicode emoji
737
- * message.react('🤔')
738
- * .then(console.log)
739
- * .catch(console.error);
740
- * @example
741
- * // React to a message with a custom emoji
742
- * message.react(message.guild.emojis.cache.get('123456789012345678'))
743
- * .then(console.log)
744
- * .catch(console.error);
745
- */
746
- async react(emoji, burst = false) {
747
- if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
748
- await this.channel.messages.react(this.id, emoji, burst);
749
-
750
- return this.client.actions.MessageReactionAdd.handle(
751
- {
752
- [this.client.actions.injectedUser]: this.client.user,
753
- [this.client.actions.injectedChannel]: this.channel,
754
- [this.client.actions.injectedMessage]: this,
755
- emoji: Util.resolvePartialEmoji(emoji),
756
- me_burst: burst,
757
- },
758
- true,
759
- ).reaction;
760
- }
761
-
762
- /**
763
- * Deletes the message.
764
- * @returns {Promise<Message>}
765
- * @example
766
- * // Delete a message
767
- * message.delete()
768
- * .then(msg => console.log(`Deleted message from ${msg.author.username}`))
769
- * .catch(console.error);
770
- */
771
- async delete() {
772
- if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
773
- await this.channel.messages.delete(this.id);
774
- return this;
775
- }
776
-
777
- /**
778
- * Options provided when sending a message as an inline reply.
779
- * @typedef {BaseMessageOptions} ReplyMessageOptions
780
- * @property {boolean} [failIfNotExists=true] Whether to error if the referenced message
781
- * does not exist (creates a standard message in this case when false)
782
- * @property {StickerResolvable[]} [stickers=[]] Stickers to send in the message
783
- */
784
-
785
- /**
786
- * Send an inline reply to this message.
787
- * @param {string|MessagePayload|ReplyMessageOptions} options The options to provide
788
- * @returns {Promise<Message>}
789
- * @example
790
- * // Reply to a message
791
- * message.reply('This is a reply!')
792
- * .then(() => console.log(`Replied to message "${message.content}"`))
793
- * .catch(console.error);
794
- */
795
- reply(options) {
796
- if (!this.channel) return Promise.reject(new Error('CHANNEL_NOT_CACHED'));
797
- let data;
798
-
799
- if (options instanceof MessagePayload) {
800
- data = options;
801
- } else {
802
- data = MessagePayload.create(this, options, {
803
- reply: {
804
- messageReference: this,
805
- failIfNotExists: options?.failIfNotExists ?? this.client.options.failIfNotExists,
806
- },
807
- });
808
- }
809
- return this.channel.send(data);
810
- }
811
-
812
- /**
813
- * A number that is allowed to be the duration (in minutes) of inactivity after which a thread is automatically
814
- * archived. This can be:
815
- * * `60` (1 hour)
816
- * * `1440` (1 day)
817
- * * `4320` (3 days)
818
- * * `10080` (7 days)
819
- * * `'MAX'` (7 days)
820
- * <warn>This option is deprecated and will be removed in the next major version.</warn>
821
- * @typedef {number|string} ThreadAutoArchiveDuration
822
- */
823
-
824
- /**
825
- * Options for starting a thread on a message.
826
- * @typedef {Object} StartThreadOptions
827
- * @property {string} name The name of the new thread
828
- * @property {ThreadAutoArchiveDuration} [autoArchiveDuration=this.channel.defaultAutoArchiveDuration] The amount of
829
- * time (in minutes) after which the thread should automatically archive in case of no recent activity
830
- * @property {string} [reason] Reason for creating the thread
831
- * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the thread in seconds
832
- */
833
-
834
- /**
835
- * Create a new public thread from this message
836
- * @see GuildTextThreadManager#create
837
- * @param {StartThreadOptions} [options] Options for starting a thread on this message
838
- * @returns {Promise<ThreadChannel>}
839
- */
840
- startThread(options = {}) {
841
- if (!this.channel) return Promise.reject(new Error('CHANNEL_NOT_CACHED'));
842
- if (!['GUILD_TEXT', 'GUILD_NEWS'].includes(this.channel.type)) {
843
- return Promise.reject(new Error('MESSAGE_THREAD_PARENT'));
844
- }
845
- if (this.hasThread) return Promise.reject(new Error('MESSAGE_EXISTING_THREAD'));
846
- return this.channel.threads.create({ ...options, startMessage: this });
847
- }
848
-
849
- /**
850
- * Fetch this message.
851
- * @param {boolean} [force=true] Whether to skip the cache check and request the API
852
- * @returns {Promise<Message>}
853
- */
854
- fetch(force = true) {
855
- if (!this.channel) return Promise.reject(new Error('CHANNEL_NOT_CACHED'));
856
- return this.channel.messages.fetch(this.id, { force });
857
- }
858
-
859
- /**
860
- * Fetches the webhook used to create this message.
861
- * @returns {Promise<?Webhook>}
862
- */
863
- fetchWebhook() {
864
- if (!this.webhookId) return Promise.reject(new Error('WEBHOOK_MESSAGE'));
865
- if (this.webhookId === this.applicationId) return Promise.reject(new Error('WEBHOOK_APPLICATION'));
866
- return this.client.fetchWebhook(this.webhookId);
867
- }
868
-
869
- /**
870
- * Suppresses or unsuppresses embeds on a message.
871
- * @param {boolean} [suppress=true] If the embeds should be suppressed or not
872
- * @returns {Promise<Message>}
873
- */
874
- suppressEmbeds(suppress = true) {
875
- const flags = new MessageFlags(this.flags.bitfield);
876
-
877
- if (suppress) {
878
- flags.add(MessageFlags.FLAGS.SUPPRESS_EMBEDS);
879
- } else {
880
- flags.remove(MessageFlags.FLAGS.SUPPRESS_EMBEDS);
881
- }
882
-
883
- return this.edit({ flags });
884
- }
885
-
886
- /**
887
- * Removes the attachments from this message.
888
- * @returns {Promise<Message>}
889
- */
890
- removeAttachments() {
891
- return this.edit({ attachments: [] });
892
- }
893
-
894
- /**
895
- * Resolves a component by a custom id.
896
- * @param {string} customId The custom id to resolve against
897
- * @returns {?MessageActionRowComponent}
898
- */
899
- resolveComponent(customId) {
900
- return this.components.flatMap(row => row.components).find(component => component.customId === customId) ?? null;
901
- }
902
-
903
- /**
904
- * Used mainly internally. Whether two messages are identical in properties. If you want to compare messages
905
- * without checking all the properties, use `message.id === message2.id`, which is much more efficient. This
906
- * method allows you to see if there are differences in content, embeds, attachments, nonce and tts properties.
907
- * @param {Message} message The message to compare it to
908
- * @param {APIMessage} rawData Raw data passed through the WebSocket about this message
909
- * @returns {boolean}
910
- */
911
- equals(message, rawData) {
912
- if (!message) return false;
913
- const embedUpdate = !message.author && !message.attachments;
914
- if (embedUpdate) return this.id === message.id && this.embeds.length === message.embeds.length;
915
-
916
- let equal =
917
- this.id === message.id &&
918
- this.author.id === message.author.id &&
919
- this.content === message.content &&
920
- this.tts === message.tts &&
921
- this.nonce === message.nonce &&
922
- this.embeds.length === message.embeds.length &&
923
- this.attachments.length === message.attachments.length;
924
-
925
- if (equal && rawData) {
926
- equal =
927
- this.mentions.everyone === message.mentions.everyone &&
928
- this.createdTimestamp === new Date(rawData.timestamp).getTime() &&
929
- this.editedTimestamp === new Date(rawData.edited_timestamp).getTime();
930
- }
931
-
932
- return equal;
933
- }
934
-
935
- /**
936
- * Whether this message is from a guild.
937
- * @returns {boolean}
938
- */
939
- inGuild() {
940
- return Boolean(this.guildId);
941
- }
942
-
943
- /**
944
- * When concatenated with a string, this automatically concatenates the message's content instead of the object.
945
- * @returns {string}
946
- * @example
947
- * // Logs: Message: This is a message!
948
- * console.log(`Message: ${message}`);
949
- */
950
- toString() {
951
- return this.content;
952
- }
953
-
954
- toJSON() {
955
- return super.toJSON({
956
- channel: 'channelId',
957
- author: 'authorId',
958
- groupActivityApplication: 'groupActivityApplicationId',
959
- guild: 'guildId',
960
- cleanContent: true,
961
- member: false,
962
- reactions: false,
963
- });
964
- }
965
-
966
- // TypeScript
967
- /**
968
- * Check data
969
- * @type {boolean}
970
- * @readonly
971
- */
972
- get isMessage() {
973
- return true;
974
- }
975
-
976
- /**
977
- * Click specific button with X and Y
978
- * @typedef {Object} MessageButtonLocation
979
- * @property {number} X Index of the row
980
- * @property {number} Y Index of the column
981
- */
982
-
983
- /**
984
- * Click specific button or automatically click first button if no button is specified.
985
- * @param {MessageButtonLocation|string|undefined} button button
986
- * @returns {Promise<Message|Modal>}
987
- * @example
988
- * // Demo msg
989
- * Some content
990
- * ――――――――――――――――――――――――――――――――> X from 0
991
- * │ [button1] [button2] [button3]
992
- * │ [button4] [button5] [button6]
993
- *
994
- * Y from 0
995
- * // Click button6 with X and Y
996
- * [0,0] [1,0] [2,0]
997
- * [0,1] [1,1] [2,1]
998
- * // Code
999
- * message.clickButton({
1000
- * X: 2, Y: 1,
1001
- * });
1002
- * // Click button with customId (Ex button 5)
1003
- * message.clickButton('button5');
1004
- * // Click button 1
1005
- * message.clickButton();
1006
- */
1007
- clickButton(button) {
1008
- if (typeof button == 'undefined') {
1009
- button = this.components
1010
- .flatMap(row => row.components)
1011
- .find(b => b.type === 'BUTTON' && b.customId && !b.disabled);
1012
- } else if (typeof button == 'string') {
1013
- button = this.components.flatMap(row => row.components).find(b => b.type === 'BUTTON' && b.customId == button);
1014
- } else {
1015
- button = this.components[button.Y]?.components[button.X];
1016
- }
1017
- button = button.toJSON();
1018
- if (!button) throw new TypeError('BUTTON_NOT_FOUND');
1019
- if (!button.custom_id || button.disabled) throw new TypeError('BUTTON_CANNOT_CLICK');
1020
- const nonce = SnowflakeUtil.generate();
1021
- const data = {
1022
- type: InteractionTypes.MESSAGE_COMPONENT,
1023
- nonce,
1024
- guild_id: this.guildId,
1025
- channel_id: this.channelId,
1026
- message_id: this.id,
1027
- application_id: this.applicationId ?? this.author.id,
1028
- session_id: this.client.sessionId,
1029
- message_flags: this.flags.bitfield,
1030
- data: {
1031
- component_type: MessageComponentTypes.BUTTON,
1032
- custom_id: button.custom_id,
1033
- },
1034
- };
1035
- this.client.api.interactions.post({
1036
- data,
1037
- });
1038
- return new Promise((resolve, reject) => {
1039
- const timeoutMs = 5_000;
1040
- // Waiting for MsgCreate / ModalCreate
1041
- const handler = data => {
1042
- // UnhandledPacket
1043
- if (data.d?.nonce == nonce && data.t == 'INTERACTION_SUCCESS') {
1044
- // Interaction#deferUpdate
1045
- this.client.removeListener(Events.MESSAGE_CREATE, handler);
1046
- this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1047
- this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1048
- resolve(this);
1049
- }
1050
- if (data.nonce !== nonce) return;
1051
- clearTimeout(timeout);
1052
- this.client.removeListener(Events.MESSAGE_CREATE, handler);
1053
- this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1054
- this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1055
- this.client.decrementMaxListeners();
1056
- resolve(data);
1057
- };
1058
- const timeout = setTimeout(() => {
1059
- this.client.removeListener(Events.MESSAGE_CREATE, handler);
1060
- this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1061
- this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1062
- this.client.decrementMaxListeners();
1063
- reject(new Error('INTERACTION_FAILED'));
1064
- }, timeoutMs).unref();
1065
- this.client.incrementMaxListeners();
1066
- this.client.on(Events.MESSAGE_CREATE, handler);
1067
- this.client.on(Events.UNHANDLED_PACKET, handler);
1068
- this.client.on(Events.INTERACTION_MODAL_CREATE, handler);
1069
- });
1070
- }
1071
-
1072
- /**
1073
- * Select specific menu
1074
- * @param {number|string} menu Target
1075
- * @param {Array<UserResolvable | RoleResolvable | ChannelResolvable | string>} values Any value
1076
- * @returns {Promise<Message|Modal>}
1077
- */
1078
- selectMenu(menu, values = []) {
1079
- let selectMenu;
1080
- if (/[0-4]/.test(menu)) {
1081
- selectMenu = this.components[menu]?.components[0];
1082
- } else {
1083
- selectMenu = this.components
1084
- .flatMap(row => row.components)
1085
- .find(
1086
- b =>
1087
- ['STRING_SELECT', 'USER_SELECT', 'ROLE_SELECT', 'MENTIONABLE_SELECT', 'CHANNEL_SELECT'].includes(b.type) &&
1088
- b.customId == menu &&
1089
- !b.disabled,
1090
- );
1091
- }
1092
- if (values.length < selectMenu.minValues) {
1093
- throw new RangeError(`[SELECT_MENU_MIN_VALUES] The minimum number of values is ${selectMenu.minValues}`);
1094
- }
1095
- if (values.length > selectMenu.maxValues) {
1096
- throw new RangeError(`[SELECT_MENU_MAX_VALUES] The maximum number of values is ${selectMenu.maxValues}`);
1097
- }
1098
- values = values.map(value => {
1099
- switch (selectMenu.type) {
1100
- case 'STRING_SELECT': {
1101
- return selectMenu.options.find(obj => obj.value === value || obj.label === value).value;
1102
- }
1103
- case 'USER_SELECT': {
1104
- return this.client.users.resolveId(value);
1105
- }
1106
- case 'ROLE_SELECT': {
1107
- return this.guild.roles.resolveId(value);
1108
- }
1109
- case 'MENTIONABLE_SELECT': {
1110
- return this.client.users.resolveId(value) || this.guild.roles.resolveId(value);
1111
- }
1112
- case 'CHANNEL_SELECT': {
1113
- return this.client.channels.resolveId(value);
1114
- }
1115
- default: {
1116
- return value;
1117
- }
1118
- }
1119
- });
1120
- const nonce = SnowflakeUtil.generate();
1121
- const data = {
1122
- type: InteractionTypes.MESSAGE_COMPONENT,
1123
- guild_id: this.guildId,
1124
- channel_id: this.channelId,
1125
- message_id: this.id,
1126
- application_id: this.applicationId ?? this.author.id,
1127
- session_id: this.client.sessionId,
1128
- message_flags: this.flags.bitfield,
1129
- data: {
1130
- component_type: MessageComponentTypes[selectMenu.type],
1131
- custom_id: selectMenu.customId,
1132
- type: MessageComponentTypes[selectMenu.type],
1133
- values,
1134
- },
1135
- nonce,
1136
- };
1137
- this.client.api.interactions.post({
1138
- data,
1139
- });
1140
- return new Promise((resolve, reject) => {
1141
- const timeoutMs = 5_000;
1142
- // Waiting for MsgCreate / ModalCreate
1143
- const handler = data => {
1144
- // UnhandledPacket
1145
- if (data.d?.nonce == nonce && data.t == 'INTERACTION_SUCCESS') {
1146
- // Interaction#deferUpdate
1147
- this.client.removeListener(Events.MESSAGE_CREATE, handler);
1148
- this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1149
- this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1150
- resolve(this);
1151
- }
1152
- if (data.nonce !== nonce) return;
1153
- clearTimeout(timeout);
1154
- this.client.removeListener(Events.MESSAGE_CREATE, handler);
1155
- this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1156
- this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1157
- this.client.decrementMaxListeners();
1158
- resolve(data);
1159
- };
1160
- const timeout = setTimeout(() => {
1161
- this.client.removeListener(Events.MESSAGE_CREATE, handler);
1162
- this.client.removeListener(Events.UNHANDLED_PACKET, handler);
1163
- this.client.removeListener(Events.INTERACTION_MODAL_CREATE, handler);
1164
- this.client.decrementMaxListeners();
1165
- reject(new Error('INTERACTION_FAILED'));
1166
- }, timeoutMs).unref();
1167
- this.client.incrementMaxListeners();
1168
- this.client.on(Events.MESSAGE_CREATE, handler);
1169
- this.client.on(Events.UNHANDLED_PACKET, handler);
1170
- this.client.on(Events.INTERACTION_MODAL_CREATE, handler);
1171
- });
1172
- }
1173
-
1174
- /**
1175
- * Marks the message as unread.
1176
- * @returns {Promise<void>}
1177
- */
1178
- markUnread() {
1179
- return this.client.api.channels[this.channelId].messages[this.id].ack.post({
1180
- data: {
1181
- manual: true,
1182
- mention_count:
1183
- this.mentions.everyone ||
1184
- this.mentions.repliedUser?.id === this.client.user.id ||
1185
- this.mentions.users.has(this.client.user.id) ||
1186
- (this.guildId && this.mentions.roles.some(r => this.guild.members.me._roles?.includes(r.id)))
1187
- ? 1
1188
- : 1,
1189
- },
1190
- });
1191
- }
1192
-
1193
- /**
1194
- * Marks the message as read.
1195
- * @returns {Promise<void>}
1196
- */
1197
- markRead() {
1198
- return this.client.api.channels[this.channelId].messages[this.id].ack.post({
1199
- data: {
1200
- token: null,
1201
- },
1202
- });
1203
- }
1204
-
1205
- /**
1206
- * Report Message
1207
- * @param {Arrray<number>} breadcrumbs Options for reporting
1208
- * @param {Object} [elements={}] Metadata
1209
- * @returns {Promise<{ report_id: Snowflake }>}
1210
- * @example
1211
- * // GET https://discord.com/api/v9/reporting/menu/message?variant=4
1212
- * // Report Category
1213
- * // - <hidden>MESSAGE_WELCOME (3)</hidden>
1214
- * // - Something else (28)
1215
- * // - Hacks, cheats, phishing or malicious links (72)
1216
- * message.report([3, 28, 72]).then(console.log);
1217
- * // { "report_id": "1199663489988440124" }
1218
- */
1219
- report(breadcrumbs, elements = {}) {
1220
- return this.client.api.reporting.message.post({
1221
- data: {
1222
- version: '1.0',
1223
- variant: '4',
1224
- language: 'en',
1225
- breadcrumbs,
1226
- elements,
1227
- channel_id: this.channelId,
1228
- message_id: this.id,
1229
- name: 'message',
1230
- },
1231
- });
1232
- }
1233
- }
1234
-
1235
- exports.Message = Message;
1236
- exports.deletedMessages = deletedMessages;
1
+ 'use strict';
2
+
3
+ const process = require('node:process');
4
+ const { Collection } = require('@discordjs/collection');
5
+ const Base = require('./Base');
6
+ const BaseMessageComponent = require('./BaseMessageComponent');
7
+ const MessageAttachment = require('./MessageAttachment');
8
+ const Embed = require('./MessageEmbed');
9
+ const Mentions = require('./MessageMentions');
10
+ const MessagePayload = require('./MessagePayload');
11
+ const { Poll } = require('./Poll');
12
+ const ReactionCollector = require('./ReactionCollector');
13
+ const { Sticker } = require('./Sticker');
14
+ const Application = require('./interfaces/Application');
15
+ const { Error } = require('../errors');
16
+ const ReactionManager = require('../managers/ReactionManager');
17
+ const {
18
+ InteractionTypes,
19
+ MessageTypes,
20
+ SystemMessageTypes,
21
+ MessageComponentTypes,
22
+ MessageReferenceTypes,
23
+ } = require('../util/Constants');
24
+ const MessageFlags = require('../util/MessageFlags');
25
+ const Permissions = require('../util/Permissions');
26
+ const SnowflakeUtil = require('../util/SnowflakeUtil');
27
+ const Util = require('../util/Util');
28
+
29
+ /**
30
+ * @type {WeakSet<Message>}
31
+ * @private
32
+ * @internal
33
+ */
34
+ const deletedMessages = new WeakSet();
35
+ let deprecationEmittedForDeleted = false;
36
+
37
+ /**
38
+ * Represents a message on Discord.
39
+ * @extends {Base}
40
+ */
41
+ class Message extends Base {
42
+ constructor(client, data) {
43
+ super(client);
44
+
45
+ /**
46
+ * The id of the channel the message was sent in
47
+ * @type {Snowflake}
48
+ */
49
+ this.channelId = data.channel_id;
50
+
51
+ /**
52
+ * The id of the guild the message was sent in, if any
53
+ * @type {?Snowflake}
54
+ */
55
+ this.guildId = data.guild_id ?? this.channel?.guild?.id ?? null;
56
+
57
+ this._patch(data);
58
+ }
59
+
60
+ _patch(data) {
61
+ /**
62
+ * The message's id
63
+ * @type {Snowflake}
64
+ */
65
+ this.id = data.id;
66
+
67
+ if ('position' in data) {
68
+ /**
69
+ * A generally increasing integer (there may be gaps or duplicates) that represents
70
+ * the approximate position of the message in a thread.
71
+ * @type {?number}
72
+ */
73
+ this.position = data.position;
74
+ } else {
75
+ this.position ??= null;
76
+ }
77
+
78
+ /**
79
+ * The timestamp the message was sent at
80
+ * @type {number}
81
+ */
82
+ this.createdTimestamp = this.id ? SnowflakeUtil.timestampFrom(this.id) : new Date(data.timestamp).getTime();
83
+
84
+ if ('type' in data) {
85
+ /**
86
+ * The type of the message
87
+ * @type {?MessageType}
88
+ */
89
+ this.type = MessageTypes[data.type];
90
+
91
+ /**
92
+ * Whether or not this message was sent by Discord, not actually a user (e.g. pin notifications)
93
+ * @type {?boolean}
94
+ */
95
+ this.system = SystemMessageTypes.includes(this.type);
96
+ } else {
97
+ this.system ??= null;
98
+ this.type ??= null;
99
+ }
100
+
101
+ if ('content' in data) {
102
+ /**
103
+ * The content of the message
104
+ * @type {?string}
105
+ */
106
+ this.content = data.content;
107
+ } else {
108
+ this.content ??= null;
109
+ }
110
+
111
+ if ('author' in data) {
112
+ /**
113
+ * The author of the message
114
+ * @type {?User}
115
+ */
116
+ this.author = this.client.users._add(data.author, !data.webhook_id);
117
+ } else {
118
+ this.author ??= null;
119
+ }
120
+
121
+ if ('pinned' in data) {
122
+ /**
123
+ * Whether or not this message is pinned
124
+ * @type {?boolean}
125
+ */
126
+ this.pinned = Boolean(data.pinned);
127
+ } else {
128
+ this.pinned ??= null;
129
+ }
130
+
131
+ if ('tts' in data) {
132
+ /**
133
+ * Whether or not the message was Text-To-Speech
134
+ * @type {?boolean}
135
+ */
136
+ this.tts = data.tts;
137
+ } else {
138
+ this.tts ??= null;
139
+ }
140
+
141
+ if ('nonce' in data) {
142
+ /**
143
+ * A random number or string used for checking message delivery
144
+ * <warn>This is only received after the message was sent successfully, and
145
+ * lost if re-fetched</warn>
146
+ * @type {?string}
147
+ */
148
+ this.nonce = data.nonce;
149
+ } else {
150
+ this.nonce ??= null;
151
+ }
152
+
153
+ if ('embeds' in data) {
154
+ /**
155
+ * A list of embeds in the message - e.g. YouTube Player
156
+ * @type {MessageEmbed[]}
157
+ */
158
+ this.embeds = data.embeds.map(e => new Embed(e, true));
159
+ } else {
160
+ this.embeds = this.embeds?.slice() ?? [];
161
+ }
162
+
163
+ /**
164
+ * @typedef {MessageActionRow|ContainerComponent|FileComponent|MediaGalleryComponent|SectionComponent|SeparatorComponent|TextDisplayComponent} TopLevelComponent
165
+ */
166
+
167
+ if ('components' in data) {
168
+ /**
169
+ * An array of components in the message
170
+ * @type {TopLevelComponent[]}
171
+ */
172
+ this.components = data.components.map(c => BaseMessageComponent.create(c, this.client));
173
+ } else {
174
+ this.components = this.components?.slice() ?? [];
175
+ }
176
+
177
+ if ('attachments' in data) {
178
+ /**
179
+ * A collection of attachments in the message - e.g. Pictures - mapped by their ids
180
+ * @type {Collection<Snowflake, MessageAttachment>}
181
+ */
182
+ this.attachments = new Collection();
183
+ if (data.attachments) {
184
+ for (const attachment of data.attachments) {
185
+ this.attachments.set(attachment.id, new MessageAttachment(attachment.url, attachment.filename, attachment));
186
+ }
187
+ }
188
+ } else {
189
+ this.attachments = new Collection(this.attachments);
190
+ }
191
+
192
+ if ('sticker_items' in data || 'stickers' in data) {
193
+ /**
194
+ * A collection of stickers in the message
195
+ * @type {Collection<Snowflake, Sticker>}
196
+ */
197
+ this.stickers = new Collection(
198
+ (data.sticker_items ?? data.stickers)?.map(s => [s.id, new Sticker(this.client, s)]),
199
+ );
200
+ } else {
201
+ this.stickers = new Collection(this.stickers);
202
+ }
203
+
204
+ // Discord sends null if the message has not been edited
205
+ if (data.edited_timestamp) {
206
+ /**
207
+ * The timestamp the message was last edited at (if applicable)
208
+ * @type {?number}
209
+ */
210
+ this.editedTimestamp = data.edited_timestamp ? Date.parse(data.edited_timestamp) : null;
211
+ } else {
212
+ this.editedTimestamp ??= null;
213
+ }
214
+
215
+ if ('reactions' in data) {
216
+ /**
217
+ * A manager of the reactions belonging to this message
218
+ * @type {ReactionManager}
219
+ */
220
+ this.reactions = new ReactionManager(this);
221
+ if (data.reactions?.length > 0) {
222
+ for (const reaction of data.reactions) {
223
+ this.reactions._add(reaction);
224
+ }
225
+ }
226
+ } else {
227
+ this.reactions ??= new ReactionManager(this);
228
+ }
229
+
230
+ if (!this.mentions) {
231
+ /**
232
+ * All valid mentions that the message contains
233
+ * @type {MessageMentions}
234
+ */
235
+ this.mentions = new Mentions(
236
+ this,
237
+ data.mentions,
238
+ data.mention_roles,
239
+ data.mention_everyone,
240
+ data.mention_channels,
241
+ data.referenced_message?.author,
242
+ );
243
+ } else {
244
+ this.mentions = new Mentions(
245
+ this,
246
+ data.mentions ?? this.mentions.users,
247
+ data.mention_roles ?? this.mentions.roles,
248
+ data.mention_everyone ?? this.mentions.everyone,
249
+ data.mention_channels ?? this.mentions.crosspostedChannels,
250
+ data.referenced_message?.author ?? this.mentions.repliedUser,
251
+ );
252
+ }
253
+
254
+ if ('webhook_id' in data) {
255
+ /**
256
+ * The id of the webhook that sent the message, if applicable
257
+ * @type {?Snowflake}
258
+ */
259
+ this.webhookId = data.webhook_id;
260
+ } else {
261
+ this.webhookId ??= null;
262
+ }
263
+
264
+ if (data.poll) {
265
+ /**
266
+ * The poll that was sent with the message
267
+ * @type {?Poll}
268
+ */
269
+ this.poll = new Poll(this.client, data.poll, this);
270
+ } else {
271
+ this.poll ??= null;
272
+ }
273
+
274
+ if ('application' in data) {
275
+ /**
276
+ * Supplemental application information for group activities
277
+ * @type {?Application}
278
+ */
279
+ this.groupActivityApplication = new Application(this.client, data.application);
280
+ } else {
281
+ this.groupActivityApplication ??= null;
282
+ }
283
+
284
+ if ('application_id' in data) {
285
+ /**
286
+ * The id of the application of the interaction that sent this message, if any
287
+ * @type {?Snowflake}
288
+ */
289
+ this.applicationId = data.application_id;
290
+ } else {
291
+ this.applicationId ??= null;
292
+ }
293
+
294
+ if ('activity' in data) {
295
+ /**
296
+ * Group activity
297
+ * @type {?MessageActivity}
298
+ */
299
+ this.activity = {
300
+ partyId: data.activity.party_id,
301
+ type: data.activity.type,
302
+ };
303
+ } else {
304
+ this.activity ??= null;
305
+ }
306
+
307
+ if ('thread' in data) {
308
+ this.client.channels._add(data.thread, this.guild);
309
+ }
310
+
311
+ if (this.member && data.member) {
312
+ this.member._patch(data.member);
313
+ } else if (data.member && this.guild && this.author) {
314
+ this.guild.members._add(Object.assign(data.member, { user: this.author }));
315
+ }
316
+
317
+ if ('flags' in data) {
318
+ /**
319
+ * Flags that are applied to the message
320
+ * @type {Readonly<MessageFlags>}
321
+ */
322
+ this.flags = new MessageFlags(data.flags).freeze();
323
+ } else {
324
+ this.flags = new MessageFlags(this.flags).freeze();
325
+ }
326
+
327
+ /**
328
+ * Reference data sent in a message that contains ids identifying the referenced message.
329
+ * This can be present in the following types of message:
330
+ * * Crossposted messages (IS_CROSSPOST {@link MessageFlags.FLAGS message flag})
331
+ * * CHANNEL_FOLLOW_ADD
332
+ * * CHANNEL_PINNED_MESSAGE
333
+ * * REPLY
334
+ * * THREAD_STARTER_MESSAGE
335
+ * @see {@link https://discord.com/developers/docs/resources/channel#message-types}
336
+ * @typedef {Object} MessageReference
337
+ * @property {Snowflake} channelId The channel's id the message was referenced
338
+ * @property {?Snowflake} guildId The guild's id the message was referenced
339
+ * @property {?Snowflake} messageId The message's id that was referenced
340
+ * @property {MessageReferenceType} type The type of the message reference
341
+ */
342
+
343
+ if ('message_reference' in data) {
344
+ /**
345
+ * Message reference data
346
+ * @type {?MessageReference}
347
+ */
348
+ this.reference = {
349
+ channelId: data.message_reference.channel_id,
350
+ guildId: data.message_reference.guild_id,
351
+ messageId: data.message_reference.message_id,
352
+ type: MessageReferenceTypes[data.message_reference.type ?? 0],
353
+ };
354
+ } else {
355
+ this.reference ??= null;
356
+ }
357
+
358
+ if (data.referenced_message) {
359
+ this.channel?.messages._add({ guild_id: data.message_reference?.guild_id, ...data.referenced_message });
360
+ }
361
+
362
+ /**
363
+ * Partial data of the interaction that a message is a reply to
364
+ * @typedef {Object} MessageInteraction
365
+ * @property {Snowflake} id The interaction's id
366
+ * @property {InteractionType} type The type of the interaction
367
+ * @property {string} commandName The name of the interaction's application command,
368
+ * as well as the subcommand and subcommand group, where applicable
369
+ * @property {User} user The user that invoked the interaction
370
+ */
371
+
372
+ if (data.interaction) {
373
+ /**
374
+ * Partial data of the interaction that this message is a reply to
375
+ * @type {?MessageInteraction}
376
+ */
377
+ this.interaction = {
378
+ id: data.interaction.id,
379
+ type: InteractionTypes[data.interaction.type],
380
+ commandName: data.interaction.name,
381
+ user: this.client.users._add(data.interaction.user),
382
+ };
383
+ } else {
384
+ this.interaction ??= null;
385
+ }
386
+
387
+ if (data.message_snapshots) {
388
+ /**
389
+ * The message snapshots associated with the message reference
390
+ * @type {Collection<Snowflake, Message>}
391
+ */
392
+ this.messageSnapshots = data.message_snapshots.reduce((coll, snapshot) => {
393
+ const channel = this.client.channels.cache.get(this.reference.channelId);
394
+ const snapshotData = {
395
+ ...snapshot.message,
396
+ id: this.reference.messageId,
397
+ channel_id: this.reference.channelId,
398
+ guild_id: this.reference.guildId,
399
+ };
400
+
401
+ return coll.set(
402
+ this.reference.messageId,
403
+ channel ? channel.messages._add(snapshotData) : new this.constructor(this.client, snapshotData),
404
+ );
405
+ }, new Collection());
406
+ } else {
407
+ this.messageSnapshots ??= new Collection();
408
+ }
409
+
410
+ /**
411
+ * A call associated with a message
412
+ * @typedef {Object} MessageCall
413
+ * @property {Readonly<?Date>} endedAt The time the call ended
414
+ * @property {?number} endedTimestamp The timestamp the call ended
415
+ * @property {Snowflake[]} participants The ids of the users that participated in the call
416
+ */
417
+
418
+ if (data.call) {
419
+ /**
420
+ * The call associated with the message
421
+ * @type {?MessageCall}
422
+ */
423
+ this.call = {
424
+ endedTimestamp: data.call.ended_timestamp ? Date.parse(data.call.ended_timestamp) : null,
425
+ participants: data.call.participants,
426
+ get endedAt() {
427
+ return this.endedTimestamp && new Date(this.endedTimestamp);
428
+ },
429
+ };
430
+ } else {
431
+ this.call ??= null;
432
+ }
433
+ }
434
+
435
+ /**
436
+ * Whether or not the structure has been deleted
437
+ * @type {boolean}
438
+ * @deprecated This will be removed in the next major version, see https://github.com/discordjs/discord.js/issues/7091
439
+ */
440
+ get deleted() {
441
+ if (!deprecationEmittedForDeleted) {
442
+ deprecationEmittedForDeleted = true;
443
+ process.emitWarning(
444
+ 'Message#deleted is deprecated, see https://github.com/discordjs/discord.js/issues/7091.',
445
+ 'DeprecationWarning',
446
+ );
447
+ }
448
+
449
+ return deletedMessages.has(this);
450
+ }
451
+
452
+ set deleted(value) {
453
+ if (!deprecationEmittedForDeleted) {
454
+ deprecationEmittedForDeleted = true;
455
+ process.emitWarning(
456
+ 'Message#deleted is deprecated, see https://github.com/discordjs/discord.js/issues/7091.',
457
+ 'DeprecationWarning',
458
+ );
459
+ }
460
+
461
+ if (value) deletedMessages.add(this);
462
+ else deletedMessages.delete(this);
463
+ }
464
+
465
+ /**
466
+ * The channel that the message was sent in
467
+ * @type {TextBasedChannels}
468
+ * @readonly
469
+ */
470
+ get channel() {
471
+ return this.client.channels.cache.get(this.channelId) ?? null;
472
+ }
473
+
474
+ /**
475
+ * Whether or not this message is a partial
476
+ * @type {boolean}
477
+ * @readonly
478
+ */
479
+ get partial() {
480
+ return typeof this.content !== 'string' || !this.author;
481
+ }
482
+
483
+ /**
484
+ * Represents the author of the message as a guild member.
485
+ * Only available if the message comes from a guild where the author is still a member
486
+ * @type {?GuildMember}
487
+ * @readonly
488
+ */
489
+ get member() {
490
+ return this.guild?.members.resolve(this.author) ?? null;
491
+ }
492
+
493
+ /**
494
+ * The time the message was sent at
495
+ * @type {Date}
496
+ * @readonly
497
+ */
498
+ get createdAt() {
499
+ return new Date(this.createdTimestamp);
500
+ }
501
+
502
+ /**
503
+ * The time the message was last edited at (if applicable)
504
+ * @type {?Date}
505
+ * @readonly
506
+ */
507
+ get editedAt() {
508
+ return this.editedTimestamp ? new Date(this.editedTimestamp) : null;
509
+ }
510
+
511
+ /**
512
+ * The guild the message was sent in (if in a guild channel)
513
+ * @type {?Guild}
514
+ * @readonly
515
+ */
516
+ get guild() {
517
+ return this.client.guilds.cache.get(this.guildId) ?? this.channel?.guild ?? null;
518
+ }
519
+
520
+ /**
521
+ * Whether this message has a thread associated with it
522
+ * @type {boolean}
523
+ * @readonly
524
+ */
525
+ get hasThread() {
526
+ return this.flags.has(MessageFlags.FLAGS.HAS_THREAD);
527
+ }
528
+
529
+ /**
530
+ * The thread started by this message
531
+ * <info>This property is not suitable for checking whether a message has a thread,
532
+ * use {@link Message#hasThread} instead.</info>
533
+ * @type {?ThreadChannel}
534
+ * @readonly
535
+ */
536
+ get thread() {
537
+ return this.channel?.threads?.cache.get(this.id) ?? null;
538
+ }
539
+
540
+ /**
541
+ * The URL to jump to this message
542
+ * @type {string}
543
+ * @readonly
544
+ */
545
+ get url() {
546
+ return `https://discord.com/channels/${this.guildId ?? '@me'}/${this.channelId}/${this.id}`;
547
+ }
548
+
549
+ /**
550
+ * The message contents with all mentions replaced by the equivalent text.
551
+ * If mentions cannot be resolved to a name, the relevant mention in the message content will not be converted.
552
+ * @type {?string}
553
+ * @readonly
554
+ */
555
+ get cleanContent() {
556
+ // eslint-disable-next-line eqeqeq
557
+ return this.content != null && this.channel ? Util.cleanContent(this.content, this.channel) : null;
558
+ }
559
+
560
+ /**
561
+ * Creates a reaction collector.
562
+ * @param {ReactionCollectorOptions} [options={}] Options to send to the collector
563
+ * @returns {ReactionCollector}
564
+ * @example
565
+ * // Create a reaction collector
566
+ * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId';
567
+ * const collector = message.createReactionCollector({ filter, time: 15_000 });
568
+ * collector.on('collect', r => console.log(`Collected ${r.emoji.name}`));
569
+ * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
570
+ */
571
+ createReactionCollector(options = {}) {
572
+ return new ReactionCollector(this, options);
573
+ }
574
+
575
+ /**
576
+ * An object containing the same properties as CollectorOptions, but a few more:
577
+ * @typedef {ReactionCollectorOptions} AwaitReactionsOptions
578
+ * @property {string[]} [errors] Stop/end reasons that cause the promise to reject
579
+ */
580
+
581
+ /**
582
+ * Similar to createReactionCollector but in promise form.
583
+ * Resolves with a collection of reactions that pass the specified filter.
584
+ * @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
585
+ * @returns {Promise<Collection<string | Snowflake, MessageReaction>>}
586
+ * @example
587
+ * // Create a reaction collector
588
+ * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId'
589
+ * message.awaitReactions({ filter, time: 15_000 })
590
+ * .then(collected => console.log(`Collected ${collected.size} reactions`))
591
+ * .catch(console.error);
592
+ */
593
+ awaitReactions(options = {}) {
594
+ return new Promise((resolve, reject) => {
595
+ const collector = this.createReactionCollector(options);
596
+ collector.once('end', (reactions, reason) => {
597
+ if (options.errors?.includes(reason)) reject(reactions);
598
+ else resolve(reactions);
599
+ });
600
+ });
601
+ }
602
+
603
+ /**
604
+ * Whether the message is editable by the client user
605
+ * @type {boolean}
606
+ * @readonly
607
+ */
608
+ get editable() {
609
+ const precheck = Boolean(
610
+ this.author.id === this.client.user.id &&
611
+ !deletedMessages.has(this) &&
612
+ (!this.guild || this.channel?.viewable) &&
613
+ this.reference?.type !== 'FORWARD',
614
+ );
615
+
616
+ // Regardless of permissions thread messages cannot be edited if
617
+ // the thread is archived or the thread is locked and the bot does not have permission to manage threads.
618
+ if (this.channel?.isThread()) {
619
+ if (this.channel.archived) return false;
620
+ if (this.channel.locked) {
621
+ const permissions = this.channel.permissionsFor(this.client.user);
622
+ if (!permissions?.has(Permissions.FLAGS.MANAGE_THREADS, true)) return false;
623
+ }
624
+ }
625
+
626
+ return precheck;
627
+ }
628
+
629
+ /**
630
+ * Whether the message is deletable by the client user
631
+ * @type {boolean}
632
+ * @readonly
633
+ */
634
+ get deletable() {
635
+ if (deletedMessages.has(this)) {
636
+ return false;
637
+ }
638
+ if (!this.guild) {
639
+ return this.author.id === this.client.user.id;
640
+ }
641
+ // DMChannel does not have viewable property, so check viewable after proved that message is on a guild.
642
+ if (!this.channel?.viewable) {
643
+ return false;
644
+ }
645
+
646
+ const permissions = this.channel?.permissionsFor(this.client.user);
647
+ if (!permissions) return false;
648
+ // This flag allows deleting even if timed out
649
+ if (permissions.has(Permissions.FLAGS.ADMINISTRATOR, false)) return true;
650
+
651
+ return Boolean(
652
+ this.author.id === this.client.user.id ||
653
+ (permissions.has(Permissions.FLAGS.MANAGE_MESSAGES, false) &&
654
+ this.guild.members.me.communicationDisabledUntilTimestamp < Date.now()),
655
+ );
656
+ }
657
+
658
+ /**
659
+ * Whether the message is bulk deletable by the client user
660
+ * @type {boolean}
661
+ * @readonly
662
+ * @example
663
+ * // Filter for bulk deletable messages
664
+ * channel.bulkDelete(messages.filter(message => message.bulkDeletable));
665
+ */
666
+ get bulkDeletable() {
667
+ return false;
668
+ }
669
+
670
+ /**
671
+ * Whether the message is pinnable by the client user
672
+ * @type {boolean}
673
+ * @readonly
674
+ */
675
+ get pinnable() {
676
+ const { channel } = this;
677
+ return Boolean(
678
+ !this.system &&
679
+ !deletedMessages.has(this) &&
680
+ (!this.guild ||
681
+ (channel?.viewable &&
682
+ channel?.permissionsFor(this.client.user)?.has(Permissions.FLAGS.MANAGE_MESSAGES, false))),
683
+ );
684
+ }
685
+
686
+ /**
687
+ * Fetches the Message this crosspost/reply/pin-add references, if available to the client
688
+ * @returns {Promise<Message>}
689
+ */
690
+ async fetchReference() {
691
+ if (!this.reference) throw new Error('MESSAGE_REFERENCE_MISSING');
692
+ const { channelId, messageId } = this.reference;
693
+ if (!messageId) throw new Error('MESSAGE_REFERENCE_MISSING');
694
+ const channel = this.client.channels.resolve(channelId);
695
+ if (!channel) throw new Error('GUILD_CHANNEL_RESOLVE');
696
+ const message = await channel.messages.fetch(messageId);
697
+ return message;
698
+ }
699
+
700
+ /**
701
+ * Whether the message is crosspostable by the client user
702
+ * @type {boolean}
703
+ * @readonly
704
+ */
705
+ get crosspostable() {
706
+ const bitfield =
707
+ Permissions.FLAGS.SEND_MESSAGES |
708
+ (this.author.id === this.client.user.id ? Permissions.defaultBit : Permissions.FLAGS.MANAGE_MESSAGES);
709
+ const { channel } = this;
710
+ return Boolean(
711
+ channel?.type === 'GUILD_NEWS' &&
712
+ !this.flags.has(MessageFlags.FLAGS.CROSSPOSTED) &&
713
+ this.reference?.type !== 'FORWARD' &&
714
+ this.type === 'DEFAULT' &&
715
+ !this.poll &&
716
+ channel.viewable &&
717
+ channel.permissionsFor(this.client.user)?.has(bitfield, false) &&
718
+ !deletedMessages.has(this),
719
+ );
720
+ }
721
+
722
+ /**
723
+ * Options that can be passed into {@link Message#edit}.
724
+ * @typedef {Object} MessageEditOptions
725
+ * @property {?string} [content] Content to be edited
726
+ * @property {MessageEmbed[]|APIEmbed[]} [embeds] Embeds to be added/edited
727
+ * @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content
728
+ * @property {MessageFlags} [flags] Which flags to set for the message. Only `SUPPRESS_EMBEDS` can be edited.
729
+ * @property {MessageAttachment[]} [attachments] An array of attachments to keep,
730
+ * all attachments will be kept if omitted
731
+ * @property {FileOptions[]|BufferResolvable[]|MessageAttachment[]} [files] Files to add to the message
732
+ * @property {MessageActionRow[]|MessageActionRowOptions[]} [components]
733
+ * Action rows containing interactive components for the message (buttons, select menus)
734
+ */
735
+
736
+ /**
737
+ * Edits the content of the message.
738
+ * @param {string|MessagePayload|MessageEditOptions} options The options to provide
739
+ * @returns {Promise<Message>}
740
+ * @example
741
+ * // Update the content of a message
742
+ * message.edit('This is my new content!')
743
+ * .then(msg => console.log(`Updated the content of a message to ${msg.content}`))
744
+ * .catch(console.error);
745
+ */
746
+ async edit(options) {
747
+ if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
748
+ return this.channel.messages.edit(this, options);
749
+ }
750
+
751
+ /**
752
+ * Publishes a message in an announcement channel to all channels following it.
753
+ * @returns {Promise<Message>}
754
+ * @example
755
+ * // Crosspost a message
756
+ * if (message.channel.type === 'GUILD_NEWS') {
757
+ * message.crosspost()
758
+ * .then(() => console.log('Crossposted message'))
759
+ * .catch(console.error);
760
+ * }
761
+ */
762
+ async crosspost() {
763
+ if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
764
+ return this.channel.messages.crosspost(this.id);
765
+ }
766
+
767
+ /**
768
+ * Pins this message to the channel's pinned messages.
769
+ * @param {string} [reason] Reason for pinning
770
+ * @returns {Promise<Message>}
771
+ * @example
772
+ * // Pin a message
773
+ * message.pin()
774
+ * .then(console.log)
775
+ * .catch(console.error)
776
+ */
777
+ async pin(reason) {
778
+ if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
779
+ await this.channel.messages.pin(this.id, reason);
780
+ return this;
781
+ }
782
+
783
+ /**
784
+ * Unpins this message from the channel's pinned messages.
785
+ * @param {string} [reason] Reason for unpinning
786
+ * @returns {Promise<Message>}
787
+ * @example
788
+ * // Unpin a message
789
+ * message.unpin()
790
+ * .then(console.log)
791
+ * .catch(console.error)
792
+ */
793
+ async unpin(reason) {
794
+ if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
795
+ await this.channel.messages.unpin(this.id, reason);
796
+ return this;
797
+ }
798
+
799
+ /**
800
+ * Adds a reaction to the message.
801
+ * @param {EmojiIdentifierResolvable} emoji The emoji to react with
802
+ * @param {boolean} [burst=false] Super Reactions
803
+ * @returns {Promise<MessageReaction>}
804
+ * @example
805
+ * // React to a message with a unicode emoji
806
+ * message.react('🤔')
807
+ * .then(console.log)
808
+ * .catch(console.error);
809
+ * @example
810
+ * // React to a message with a custom emoji
811
+ * message.react(message.guild.emojis.cache.get('123456789012345678'))
812
+ * .then(console.log)
813
+ * .catch(console.error);
814
+ */
815
+ async react(emoji, burst = false) {
816
+ if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
817
+ await this.channel.messages.react(this.id, emoji, burst);
818
+
819
+ return this.client.actions.MessageReactionAdd.handle(
820
+ {
821
+ [this.client.actions.injectedUser]: this.client.user,
822
+ [this.client.actions.injectedChannel]: this.channel,
823
+ [this.client.actions.injectedMessage]: this,
824
+ emoji: Util.resolvePartialEmoji(emoji),
825
+ me_burst: burst,
826
+ },
827
+ true,
828
+ ).reaction;
829
+ }
830
+
831
+ /**
832
+ * Deletes the message.
833
+ * @returns {Promise<Message>}
834
+ * @example
835
+ * // Delete a message
836
+ * message.delete()
837
+ * .then(msg => console.log(`Deleted message from ${msg.author.username}`))
838
+ * .catch(console.error);
839
+ */
840
+ async delete() {
841
+ if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
842
+ await this.channel.messages.delete(this.id);
843
+ return this;
844
+ }
845
+
846
+ /**
847
+ * Options provided when sending a message as an inline reply.
848
+ * @typedef {BaseMessageOptions} ReplyMessageOptions
849
+ * @property {boolean} [failIfNotExists=true] Whether to error if the referenced message
850
+ * does not exist (creates a standard message in this case when false)
851
+ * @property {StickerResolvable[]} [stickers=[]] Stickers to send in the message
852
+ */
853
+
854
+ /**
855
+ * Send an inline reply to this message.
856
+ * @param {string|MessagePayload|ReplyMessageOptions} options The options to provide
857
+ * @returns {Promise<Message>}
858
+ * @example
859
+ * // Reply to a message
860
+ * message.reply('This is a reply!')
861
+ * .then(() => console.log(`Replied to message "${message.content}"`))
862
+ * .catch(console.error);
863
+ */
864
+ async reply(options) {
865
+ if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
866
+ let data;
867
+
868
+ if (options instanceof MessagePayload) {
869
+ data = options;
870
+ } else {
871
+ data = MessagePayload.create(this, options, {
872
+ reply: {
873
+ messageReference: this,
874
+ failIfNotExists: options?.failIfNotExists ?? this.client.options.failIfNotExists,
875
+ },
876
+ });
877
+ }
878
+ return this.channel.send(data);
879
+ }
880
+
881
+ /**
882
+ * Forwards this message
883
+ * @param {TextBasedChannelResolvable} channel The channel to forward this message to.
884
+ * @returns {Promise<Message>}
885
+ */
886
+ forward(channel) {
887
+ const resolvedChannel = this.client.channels.resolve(channel);
888
+ if (!resolvedChannel) throw new Error('INVALID_TYPE', 'channel', 'TextBasedChannelResolvable');
889
+ return resolvedChannel.send({
890
+ forward: {
891
+ message: this.id,
892
+ channel: this.channelId,
893
+ guild: this.guildId,
894
+ },
895
+ });
896
+ }
897
+
898
+ /**
899
+ * A number that is allowed to be the duration (in minutes) of inactivity after which a thread is automatically
900
+ * archived. This can be:
901
+ * * `60` (1 hour)
902
+ * * `1440` (1 day)
903
+ * * `4320` (3 days)
904
+ * * `10080` (7 days)
905
+ * * `'MAX'` (7 days)
906
+ * <warn>This option is deprecated and will be removed in the next major version.</warn>
907
+ * @typedef {number|string} ThreadAutoArchiveDuration
908
+ */
909
+
910
+ /**
911
+ * Options for starting a thread on a message.
912
+ * @typedef {Object} StartThreadOptions
913
+ * @property {string} name The name of the new thread
914
+ * @property {ThreadAutoArchiveDuration} [autoArchiveDuration=this.channel.defaultAutoArchiveDuration] The amount of
915
+ * time (in minutes) after which the thread should automatically archive in case of no recent activity
916
+ * @property {string} [reason] Reason for creating the thread
917
+ * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the thread in seconds
918
+ */
919
+
920
+ /**
921
+ * Create a new public thread from this message
922
+ * @see GuildTextThreadManager#create
923
+ * @param {StartThreadOptions} [options] Options for starting a thread on this message
924
+ * @returns {Promise<ThreadChannel>}
925
+ */
926
+ async startThread(options = {}) {
927
+ if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
928
+ if (!['GUILD_TEXT', 'GUILD_NEWS'].includes(this.channel.type)) {
929
+ throw new Error('MESSAGE_THREAD_PARENT');
930
+ }
931
+ if (this.hasThread) throw new Error('MESSAGE_EXISTING_THREAD');
932
+ return this.channel.threads.create({ ...options, startMessage: this });
933
+ }
934
+
935
+ /**
936
+ * Submits a poll vote for the current user. Returns a 204 empty response on success.
937
+ * @param {...number[]} ids ID of the answer
938
+ * @returns {Promise<void>}
939
+ * @example
940
+ * // Vote multi choices
941
+ * message.vote(1,2);
942
+ * // Remove vote
943
+ * message.vote();
944
+ */
945
+ vote(...ids) {
946
+ return this.client.api
947
+ .channels(this.channel.id)
948
+ .polls(this.id)
949
+ .answers['@me'].put({
950
+ data: {
951
+ answer_ids: ids.flat(1).map(value => value.toString()),
952
+ },
953
+ });
954
+ }
955
+
956
+ /**
957
+ * Fetch this message.
958
+ * @param {boolean} [force=true] Whether to skip the cache check and request the API
959
+ * @returns {Promise<Message>}
960
+ */
961
+ async fetch(force = true) {
962
+ if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
963
+ return this.channel.messages.fetch(this.id, { force });
964
+ }
965
+
966
+ /**
967
+ * Fetches the webhook used to create this message.
968
+ * @returns {Promise<?Webhook>}
969
+ */
970
+ async fetchWebhook() {
971
+ if (!this.webhookId) throw new Error('WEBHOOK_MESSAGE');
972
+ if (this.webhookId === this.applicationId) throw new Error('WEBHOOK_APPLICATION');
973
+ return this.client.fetchWebhook(this.webhookId);
974
+ }
975
+
976
+ /**
977
+ * Suppresses or unsuppresses embeds on a message.
978
+ * @param {boolean} [suppress=true] If the embeds should be suppressed or not
979
+ * @returns {Promise<Message>}
980
+ */
981
+ suppressEmbeds(suppress = true) {
982
+ const flags = new MessageFlags(this.flags.bitfield);
983
+
984
+ if (suppress) {
985
+ flags.add(MessageFlags.FLAGS.SUPPRESS_EMBEDS);
986
+ } else {
987
+ flags.remove(MessageFlags.FLAGS.SUPPRESS_EMBEDS);
988
+ }
989
+
990
+ return this.edit({ flags });
991
+ }
992
+
993
+ /**
994
+ * Removes the attachments from this message.
995
+ * @returns {Promise<Message>}
996
+ */
997
+ removeAttachments() {
998
+ return this.edit({ attachments: [] });
999
+ }
1000
+
1001
+ /**
1002
+ * Resolves a component by a custom id.
1003
+ * @param {string} customId The custom id to resolve against
1004
+ * @returns {?MessageActionRowComponent}
1005
+ */
1006
+ resolveComponent(customId) {
1007
+ return (
1008
+ this.components
1009
+ .flatMap(BaseMessageComponent.extractInteractiveComponents)
1010
+ .find(component => (component.customId ?? component.custom_id) === customId) ?? null
1011
+ );
1012
+ }
1013
+
1014
+ /**
1015
+ * Used mainly internally. Whether two messages are identical in properties. If you want to compare messages
1016
+ * without checking all the properties, use `message.id === message2.id`, which is much more efficient. This
1017
+ * method allows you to see if there are differences in content, embeds, attachments, nonce and tts properties.
1018
+ * @param {Message} message The message to compare it to
1019
+ * @param {APIMessage} rawData Raw data passed through the WebSocket about this message
1020
+ * @returns {boolean}
1021
+ */
1022
+ equals(message, rawData) {
1023
+ if (!message) return false;
1024
+ const embedUpdate = !message.author && !message.attachments;
1025
+ if (embedUpdate) return this.id === message.id && this.embeds.length === message.embeds.length;
1026
+
1027
+ let equal =
1028
+ this.id === message.id &&
1029
+ this.author.id === message.author.id &&
1030
+ this.content === message.content &&
1031
+ this.tts === message.tts &&
1032
+ this.nonce === message.nonce &&
1033
+ this.embeds.length === message.embeds.length &&
1034
+ this.attachments.size === message.attachments.size &&
1035
+ this.attachments.every(attachment => message.attachments.has(attachment.id)) &&
1036
+ this.embeds.every((embed, index) => embed.equals(message.embeds[index]));
1037
+
1038
+ if (equal && rawData) {
1039
+ equal =
1040
+ this.mentions.everyone === message.mentions.everyone &&
1041
+ this.createdTimestamp === new Date(rawData.timestamp).getTime() &&
1042
+ this.editedTimestamp === new Date(rawData.edited_timestamp).getTime();
1043
+ }
1044
+
1045
+ return equal;
1046
+ }
1047
+
1048
+ /**
1049
+ * Whether this message is from a guild.
1050
+ * @returns {boolean}
1051
+ */
1052
+ inGuild() {
1053
+ return Boolean(this.guildId);
1054
+ }
1055
+
1056
+ /**
1057
+ * When concatenated with a string, this automatically concatenates the message's content instead of the object.
1058
+ * @returns {string}
1059
+ * @example
1060
+ * // Logs: Message: This is a message!
1061
+ * console.log(`Message: ${message}`);
1062
+ */
1063
+ toString() {
1064
+ return this.content;
1065
+ }
1066
+
1067
+ toJSON() {
1068
+ return super.toJSON({
1069
+ channel: 'channelId',
1070
+ author: 'authorId',
1071
+ groupActivityApplication: 'groupActivityApplicationId',
1072
+ guild: 'guildId',
1073
+ cleanContent: true,
1074
+ member: false,
1075
+ reactions: false,
1076
+ });
1077
+ }
1078
+
1079
+ // TypeScript
1080
+ /**
1081
+ * Check data
1082
+ * @type {boolean}
1083
+ * @readonly
1084
+ */
1085
+ get isMessage() {
1086
+ return true;
1087
+ }
1088
+
1089
+ /**
1090
+ * Click a specified button in the message based on the button's CustomID
1091
+ * @param {string} buttonid customId of the button to click
1092
+ *
1093
+ * To be compatible with Components V2, the following methods have been removed in this version:
1094
+ * - Clicking by coordinates (using ActionRow)
1095
+ * - Clicking the first button in the message
1096
+ *
1097
+ * Currently, only clicking by CustomID is supported.
1098
+ * @returns {Promise<Message|Modal>}
1099
+ */
1100
+ clickButton(buttonid) {
1101
+ const button = this.resolveComponent(buttonid);
1102
+ if (!button || button.type !== 'BUTTON') throw new TypeError('BUTTON_NOT_FOUND');
1103
+ if (button.disabled) throw new TypeError('BUTTON_CANNOT_CLICK');
1104
+ const nonce = SnowflakeUtil.generate();
1105
+ const data = {
1106
+ type: InteractionTypes.MESSAGE_COMPONENT,
1107
+ nonce,
1108
+ guild_id: this.guildId,
1109
+ channel_id: this.channelId,
1110
+ message_id: this.id,
1111
+ application_id: this.applicationId ?? this.author.id,
1112
+ session_id: this.client.sessionId,
1113
+ message_flags: this.flags.bitfield,
1114
+ data: {
1115
+ component_type: MessageComponentTypes.BUTTON,
1116
+ custom_id: button.customId,
1117
+ },
1118
+ };
1119
+ this.client.api.interactions.post({
1120
+ data,
1121
+ });
1122
+ return Util.createPromiseInteraction(this.client, nonce, 5_000, true, this);
1123
+ }
1124
+
1125
+ /**
1126
+ * Select specific menu
1127
+ * @param {number|string} menu Target
1128
+ * @param {Array<UserResolvable | RoleResolvable | ChannelResolvable | string>} values Any value
1129
+ * @returns {Promise<Message|Modal>}
1130
+ */
1131
+ selectMenu(menu, values = []) {
1132
+ let selectMenu = menu;
1133
+ if (/[0-4]/.test(menu)) {
1134
+ selectMenu = this.components[menu]?.components[0];
1135
+ } else if (typeof menu == 'string') {
1136
+ selectMenu = this.components
1137
+ .flatMap(row => row.components)
1138
+ .find(
1139
+ b =>
1140
+ ['STRING_SELECT', 'USER_SELECT', 'ROLE_SELECT', 'MENTIONABLE_SELECT', 'CHANNEL_SELECT'].includes(b.type) &&
1141
+ b.customId == menu &&
1142
+ !b.disabled,
1143
+ );
1144
+ }
1145
+ if (values.length < selectMenu.minValues) {
1146
+ throw new RangeError(`[SELECT_MENU_MIN_VALUES] The minimum number of values is ${selectMenu.minValues}`);
1147
+ }
1148
+ if (values.length > selectMenu?.maxValues) {
1149
+ throw new RangeError(`[SELECT_MENU_MAX_VALUES] The maximum number of values is ${selectMenu.maxValues}`);
1150
+ }
1151
+ values = values.map(value => {
1152
+ switch (selectMenu.type) {
1153
+ case 'STRING_SELECT': {
1154
+ return selectMenu.options.find(obj => obj.value === value || obj.label === value).value;
1155
+ }
1156
+ case 'USER_SELECT': {
1157
+ return this.client.users.resolveId(value);
1158
+ }
1159
+ case 'ROLE_SELECT': {
1160
+ return this.guild.roles.resolveId(value);
1161
+ }
1162
+ case 'MENTIONABLE_SELECT': {
1163
+ return this.client.users.resolveId(value) || this.guild.roles.resolveId(value);
1164
+ }
1165
+ case 'CHANNEL_SELECT': {
1166
+ return this.client.channels.resolveId(value);
1167
+ }
1168
+ default: {
1169
+ return value;
1170
+ }
1171
+ }
1172
+ });
1173
+ const nonce = SnowflakeUtil.generate();
1174
+ const data = {
1175
+ type: InteractionTypes.MESSAGE_COMPONENT,
1176
+ guild_id: this.guildId,
1177
+ channel_id: this.channelId,
1178
+ message_id: this.id,
1179
+ application_id: this.applicationId ?? this.author.id,
1180
+ session_id: this.client.sessionId,
1181
+ message_flags: this.flags.bitfield,
1182
+ data: {
1183
+ component_type: MessageComponentTypes[selectMenu.type],
1184
+ custom_id: selectMenu.customId,
1185
+ type: MessageComponentTypes[selectMenu.type],
1186
+ values,
1187
+ },
1188
+ nonce,
1189
+ };
1190
+ this.client.api.interactions.post({
1191
+ data,
1192
+ });
1193
+ return Util.createPromiseInteraction(this.client, nonce, 5_000, true, this);
1194
+ }
1195
+
1196
+ /**
1197
+ * Marks the message as unread.
1198
+ * @returns {Promise<void>}
1199
+ */
1200
+ markUnread() {
1201
+ return this.client.api.channels[this.channelId].messages[this.id].ack.post({
1202
+ data: {
1203
+ manual: true,
1204
+ mention_count: 1,
1205
+ },
1206
+ });
1207
+ }
1208
+
1209
+ /**
1210
+ * Marks the message as read.
1211
+ * @returns {Promise<void>}
1212
+ */
1213
+ markRead() {
1214
+ return this.client.api.channels[this.channelId].messages[this.id].ack.post({
1215
+ data: {
1216
+ token: null,
1217
+ },
1218
+ });
1219
+ }
1220
+
1221
+ /**
1222
+ * Report Message
1223
+ * @param {Arrray<number>} breadcrumbs Options for reporting
1224
+ * @param {Object} [elements={}] Metadata
1225
+ * @returns {Promise<{ report_id: Snowflake }>}
1226
+ * @example
1227
+ * // GET https://discord.com/api/v9/reporting/menu/message?variant=4
1228
+ * // Report Category
1229
+ * // - <hidden>MESSAGE_WELCOME (3)</hidden>
1230
+ * // - Something else (28)
1231
+ * // - Hacks, cheats, phishing or malicious links (72)
1232
+ * message.report([3, 28, 72]).then(console.log);
1233
+ * // { "report_id": "1199663489988440124" }
1234
+ */
1235
+ report(breadcrumbs, elements = {}) {
1236
+ return this.client.api.reporting.message.post({
1237
+ data: {
1238
+ version: '1.0',
1239
+ variant: '4',
1240
+ language: 'en',
1241
+ breadcrumbs,
1242
+ elements,
1243
+ channel_id: this.channelId,
1244
+ message_id: this.id,
1245
+ name: 'message',
1246
+ },
1247
+ });
1248
+ }
1249
+ }
1250
+
1251
+ exports.Message = Message;
1252
+ exports.deletedMessages = deletedMessages;