discord.js-selfbott-v13 2.15.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.

Potentially problematic release.


This version of discord.js-selfbott-v13 might be problematic. Click here for more details.

Files changed (351) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +137 -0
  3. package/package.json +100 -0
  4. package/src/WebSocket.js +39 -0
  5. package/src/client/BaseClient.js +87 -0
  6. package/src/client/Client.js +1097 -0
  7. package/src/client/WebhookClient.js +61 -0
  8. package/src/client/actions/Action.js +120 -0
  9. package/src/client/actions/ActionsManager.js +78 -0
  10. package/src/client/actions/ApplicationCommandPermissionsUpdate.js +34 -0
  11. package/src/client/actions/AutoModerationActionExecution.js +26 -0
  12. package/src/client/actions/AutoModerationRuleCreate.js +27 -0
  13. package/src/client/actions/AutoModerationRuleDelete.js +31 -0
  14. package/src/client/actions/AutoModerationRuleUpdate.js +29 -0
  15. package/src/client/actions/ChannelCreate.js +23 -0
  16. package/src/client/actions/ChannelDelete.js +39 -0
  17. package/src/client/actions/ChannelUpdate.js +43 -0
  18. package/src/client/actions/GuildAuditLogEntryCreate.js +29 -0
  19. package/src/client/actions/GuildBanAdd.js +20 -0
  20. package/src/client/actions/GuildBanRemove.js +25 -0
  21. package/src/client/actions/GuildChannelsPositionUpdate.js +21 -0
  22. package/src/client/actions/GuildDelete.js +65 -0
  23. package/src/client/actions/GuildEmojiCreate.js +20 -0
  24. package/src/client/actions/GuildEmojiDelete.js +21 -0
  25. package/src/client/actions/GuildEmojiUpdate.js +20 -0
  26. package/src/client/actions/GuildEmojisUpdate.js +34 -0
  27. package/src/client/actions/GuildIntegrationsUpdate.js +19 -0
  28. package/src/client/actions/GuildMemberRemove.js +33 -0
  29. package/src/client/actions/GuildMemberUpdate.js +44 -0
  30. package/src/client/actions/GuildRoleCreate.js +25 -0
  31. package/src/client/actions/GuildRoleDelete.js +31 -0
  32. package/src/client/actions/GuildRoleUpdate.js +39 -0
  33. package/src/client/actions/GuildRolesPositionUpdate.js +21 -0
  34. package/src/client/actions/GuildScheduledEventCreate.js +27 -0
  35. package/src/client/actions/GuildScheduledEventDelete.js +31 -0
  36. package/src/client/actions/GuildScheduledEventUpdate.js +30 -0
  37. package/src/client/actions/GuildScheduledEventUserAdd.js +32 -0
  38. package/src/client/actions/GuildScheduledEventUserRemove.js +32 -0
  39. package/src/client/actions/GuildStickerCreate.js +20 -0
  40. package/src/client/actions/GuildStickerDelete.js +21 -0
  41. package/src/client/actions/GuildStickerUpdate.js +20 -0
  42. package/src/client/actions/GuildStickersUpdate.js +34 -0
  43. package/src/client/actions/GuildUpdate.js +33 -0
  44. package/src/client/actions/InteractionCreate.js +115 -0
  45. package/src/client/actions/InviteCreate.js +28 -0
  46. package/src/client/actions/InviteDelete.js +30 -0
  47. package/src/client/actions/MessageCreate.js +61 -0
  48. package/src/client/actions/MessageDelete.js +32 -0
  49. package/src/client/actions/MessageDeleteBulk.js +46 -0
  50. package/src/client/actions/MessageReactionAdd.js +56 -0
  51. package/src/client/actions/MessageReactionRemove.js +45 -0
  52. package/src/client/actions/MessageReactionRemoveAll.js +33 -0
  53. package/src/client/actions/MessageReactionRemoveEmoji.js +28 -0
  54. package/src/client/actions/MessageUpdate.js +26 -0
  55. package/src/client/actions/PresenceUpdate.js +45 -0
  56. package/src/client/actions/StageInstanceCreate.js +28 -0
  57. package/src/client/actions/StageInstanceDelete.js +33 -0
  58. package/src/client/actions/StageInstanceUpdate.js +30 -0
  59. package/src/client/actions/ThreadCreate.js +24 -0
  60. package/src/client/actions/ThreadDelete.js +32 -0
  61. package/src/client/actions/ThreadListSync.js +59 -0
  62. package/src/client/actions/ThreadMemberUpdate.js +30 -0
  63. package/src/client/actions/ThreadMembersUpdate.js +34 -0
  64. package/src/client/actions/TypingStart.js +29 -0
  65. package/src/client/actions/UserUpdate.js +35 -0
  66. package/src/client/actions/VoiceStateUpdate.js +57 -0
  67. package/src/client/actions/WebhooksUpdate.js +20 -0
  68. package/src/client/voice/ClientVoiceManager.js +51 -0
  69. package/src/client/websocket/WebSocketManager.js +412 -0
  70. package/src/client/websocket/WebSocketShard.js +905 -0
  71. package/src/client/websocket/handlers/APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE.js +23 -0
  72. package/src/client/websocket/handlers/APPLICATION_COMMAND_CREATE.js +18 -0
  73. package/src/client/websocket/handlers/APPLICATION_COMMAND_DELETE.js +20 -0
  74. package/src/client/websocket/handlers/APPLICATION_COMMAND_PERMISSIONS_UPDATE.js +5 -0
  75. package/src/client/websocket/handlers/APPLICATION_COMMAND_UPDATE.js +20 -0
  76. package/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js +5 -0
  77. package/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js +5 -0
  78. package/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js +5 -0
  79. package/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js +5 -0
  80. package/src/client/websocket/handlers/CALL_CREATE.js +14 -0
  81. package/src/client/websocket/handlers/CALL_DELETE.js +11 -0
  82. package/src/client/websocket/handlers/CALL_UPDATE.js +11 -0
  83. package/src/client/websocket/handlers/CHANNEL_CREATE.js +5 -0
  84. package/src/client/websocket/handlers/CHANNEL_DELETE.js +5 -0
  85. package/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js +22 -0
  86. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +16 -0
  87. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +16 -0
  88. package/src/client/websocket/handlers/CHANNEL_UPDATE.js +16 -0
  89. package/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +11 -0
  90. package/src/client/websocket/handlers/GUILD_AUDIT_LOG_ENTRY_CREATE.js +5 -0
  91. package/src/client/websocket/handlers/GUILD_BAN_ADD.js +5 -0
  92. package/src/client/websocket/handlers/GUILD_BAN_REMOVE.js +5 -0
  93. package/src/client/websocket/handlers/GUILD_CREATE.js +53 -0
  94. package/src/client/websocket/handlers/GUILD_DELETE.js +5 -0
  95. package/src/client/websocket/handlers/GUILD_EMOJIS_UPDATE.js +5 -0
  96. package/src/client/websocket/handlers/GUILD_INTEGRATIONS_UPDATE.js +5 -0
  97. package/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js +39 -0
  98. package/src/client/websocket/handlers/GUILD_MEMBER_ADD.js +20 -0
  99. package/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js +55 -0
  100. package/src/client/websocket/handlers/GUILD_MEMBER_REMOVE.js +5 -0
  101. package/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js +5 -0
  102. package/src/client/websocket/handlers/GUILD_ROLE_CREATE.js +5 -0
  103. package/src/client/websocket/handlers/GUILD_ROLE_DELETE.js +5 -0
  104. package/src/client/websocket/handlers/GUILD_ROLE_UPDATE.js +5 -0
  105. package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_CREATE.js +5 -0
  106. package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_DELETE.js +5 -0
  107. package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_UPDATE.js +5 -0
  108. package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_ADD.js +5 -0
  109. package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_REMOVE.js +5 -0
  110. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +0 -0
  111. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +0 -0
  112. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +0 -0
  113. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +0 -0
  114. package/src/client/websocket/handlers/GUILD_STICKERS_UPDATE.js +5 -0
  115. package/src/client/websocket/handlers/GUILD_UPDATE.js +5 -0
  116. package/src/client/websocket/handlers/INTERACTION_CREATE.js +16 -0
  117. package/src/client/websocket/handlers/INTERACTION_FAILURE.js +18 -0
  118. package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +11 -0
  119. package/src/client/websocket/handlers/INTERACTION_SUCCESS.js +30 -0
  120. package/src/client/websocket/handlers/INVITE_CREATE.js +5 -0
  121. package/src/client/websocket/handlers/INVITE_DELETE.js +5 -0
  122. package/src/client/websocket/handlers/MESSAGE_ACK.js +16 -0
  123. package/src/client/websocket/handlers/MESSAGE_CREATE.js +5 -0
  124. package/src/client/websocket/handlers/MESSAGE_DELETE.js +5 -0
  125. package/src/client/websocket/handlers/MESSAGE_DELETE_BULK.js +5 -0
  126. package/src/client/websocket/handlers/MESSAGE_REACTION_ADD.js +5 -0
  127. package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE.js +5 -0
  128. package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_ALL.js +5 -0
  129. package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_EMOJI.js +5 -0
  130. package/src/client/websocket/handlers/MESSAGE_UPDATE.js +16 -0
  131. package/src/client/websocket/handlers/PRESENCE_UPDATE.js +5 -0
  132. package/src/client/websocket/handlers/READY.js +173 -0
  133. package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +17 -0
  134. package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +15 -0
  135. package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +18 -0
  136. package/src/client/websocket/handlers/RESUMED.js +14 -0
  137. package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +0 -0
  138. package/src/client/websocket/handlers/STAGE_INSTANCE_CREATE.js +5 -0
  139. package/src/client/websocket/handlers/STAGE_INSTANCE_DELETE.js +5 -0
  140. package/src/client/websocket/handlers/STAGE_INSTANCE_UPDATE.js +5 -0
  141. package/src/client/websocket/handlers/THREAD_CREATE.js +5 -0
  142. package/src/client/websocket/handlers/THREAD_DELETE.js +5 -0
  143. package/src/client/websocket/handlers/THREAD_LIST_SYNC.js +5 -0
  144. package/src/client/websocket/handlers/THREAD_MEMBERS_UPDATE.js +5 -0
  145. package/src/client/websocket/handlers/THREAD_MEMBER_UPDATE.js +5 -0
  146. package/src/client/websocket/handlers/THREAD_UPDATE.js +16 -0
  147. package/src/client/websocket/handlers/TYPING_START.js +5 -0
  148. package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +12 -0
  149. package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +5 -0
  150. package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +5 -0
  151. package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +9 -0
  152. package/src/client/websocket/handlers/USER_UPDATE.js +5 -0
  153. package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +0 -0
  154. package/src/client/websocket/handlers/VOICE_SERVER_UPDATE.js +6 -0
  155. package/src/client/websocket/handlers/VOICE_STATE_UPDATE.js +5 -0
  156. package/src/client/websocket/handlers/WEBHOOKS_UPDATE.js +5 -0
  157. package/src/client/websocket/handlers/index.js +87 -0
  158. package/src/errors/DJSError.js +61 -0
  159. package/src/errors/Messages.js +228 -0
  160. package/src/errors/index.js +4 -0
  161. package/src/index.js +194 -0
  162. package/src/managers/ApplicationCommandManager.js +267 -0
  163. package/src/managers/ApplicationCommandPermissionsManager.js +425 -0
  164. package/src/managers/AutoModerationRuleManager.js +296 -0
  165. package/src/managers/BaseGuildEmojiManager.js +80 -0
  166. package/src/managers/BaseManager.js +19 -0
  167. package/src/managers/BillingManager.js +66 -0
  168. package/src/managers/CachedManager.js +71 -0
  169. package/src/managers/ChannelManager.js +139 -0
  170. package/src/managers/ClientUserSettingManager.js +490 -0
  171. package/src/managers/DataManager.js +61 -0
  172. package/src/managers/DeveloperPortalManager.js +104 -0
  173. package/src/managers/GuildApplicationCommandManager.js +28 -0
  174. package/src/managers/GuildBanManager.js +204 -0
  175. package/src/managers/GuildChannelManager.js +504 -0
  176. package/src/managers/GuildEmojiManager.js +171 -0
  177. package/src/managers/GuildEmojiRoleManager.js +118 -0
  178. package/src/managers/GuildFolderManager.js +24 -0
  179. package/src/managers/GuildForumThreadManager.js +114 -0
  180. package/src/managers/GuildInviteManager.js +213 -0
  181. package/src/managers/GuildManager.js +304 -0
  182. package/src/managers/GuildMemberManager.js +772 -0
  183. package/src/managers/GuildMemberRoleManager.js +191 -0
  184. package/src/managers/GuildScheduledEventManager.js +296 -0
  185. package/src/managers/GuildSettingManager.js +148 -0
  186. package/src/managers/GuildStickerManager.js +179 -0
  187. package/src/managers/GuildTextThreadManager.js +98 -0
  188. package/src/managers/InteractionManager.js +39 -0
  189. package/src/managers/MessageManager.js +393 -0
  190. package/src/managers/PermissionOverwriteManager.js +166 -0
  191. package/src/managers/PresenceManager.js +58 -0
  192. package/src/managers/ReactionManager.js +67 -0
  193. package/src/managers/ReactionUserManager.js +71 -0
  194. package/src/managers/RelationshipManager.js +258 -0
  195. package/src/managers/RoleManager.js +352 -0
  196. package/src/managers/SessionManager.js +57 -0
  197. package/src/managers/StageInstanceManager.js +162 -0
  198. package/src/managers/ThreadManager.js +207 -0
  199. package/src/managers/ThreadMemberManager.js +186 -0
  200. package/src/managers/UserManager.js +150 -0
  201. package/src/managers/VoiceStateManager.js +37 -0
  202. package/src/rest/APIRequest.js +133 -0
  203. package/src/rest/APIRouter.js +53 -0
  204. package/src/rest/CaptchaSolver.js +139 -0
  205. package/src/rest/DiscordAPIError.js +103 -0
  206. package/src/rest/HTTPError.js +62 -0
  207. package/src/rest/RESTManager.js +82 -0
  208. package/src/rest/RateLimitError.js +55 -0
  209. package/src/rest/RequestHandler.js +430 -0
  210. package/src/sharding/Shard.js +443 -0
  211. package/src/sharding/ShardClientUtil.js +275 -0
  212. package/src/sharding/ShardingManager.js +318 -0
  213. package/src/structures/AnonymousGuild.js +98 -0
  214. package/src/structures/ApplicationCommand.js +1030 -0
  215. package/src/structures/ApplicationRoleConnectionMetadata.js +45 -0
  216. package/src/structures/AutoModerationActionExecution.js +89 -0
  217. package/src/structures/AutoModerationRule.js +294 -0
  218. package/src/structures/AutocompleteInteraction.js +106 -0
  219. package/src/structures/Base.js +43 -0
  220. package/src/structures/BaseCommandInteraction.js +211 -0
  221. package/src/structures/BaseGuild.js +116 -0
  222. package/src/structures/BaseGuildEmoji.js +56 -0
  223. package/src/structures/BaseGuildTextChannel.js +203 -0
  224. package/src/structures/BaseGuildVoiceChannel.js +243 -0
  225. package/src/structures/BaseMessageComponent.js +114 -0
  226. package/src/structures/ButtonInteraction.js +11 -0
  227. package/src/structures/Call.js +58 -0
  228. package/src/structures/CategoryChannel.js +85 -0
  229. package/src/structures/Channel.js +271 -0
  230. package/src/structures/ClientApplication.js +233 -0
  231. package/src/structures/ClientPresence.js +92 -0
  232. package/src/structures/ClientUser.js +635 -0
  233. package/src/structures/CommandInteraction.js +41 -0
  234. package/src/structures/CommandInteractionOptionResolver.js +276 -0
  235. package/src/structures/ContextMenuInteraction.js +65 -0
  236. package/src/structures/DMChannel.js +289 -0
  237. package/src/structures/DeveloperPortalApplication.js +520 -0
  238. package/src/structures/DirectoryChannel.js +20 -0
  239. package/src/structures/Emoji.js +148 -0
  240. package/src/structures/ForumChannel.js +271 -0
  241. package/src/structures/Guild.js +1744 -0
  242. package/src/structures/GuildAuditLogs.js +734 -0
  243. package/src/structures/GuildBan.js +59 -0
  244. package/src/structures/GuildBoost.js +108 -0
  245. package/src/structures/GuildChannel.js +468 -0
  246. package/src/structures/GuildEmoji.js +161 -0
  247. package/src/structures/GuildFolder.js +75 -0
  248. package/src/structures/GuildMember.js +686 -0
  249. package/src/structures/GuildPreview.js +191 -0
  250. package/src/structures/GuildPreviewEmoji.js +27 -0
  251. package/src/structures/GuildScheduledEvent.js +441 -0
  252. package/src/structures/GuildTemplate.js +236 -0
  253. package/src/structures/Integration.js +188 -0
  254. package/src/structures/IntegrationApplication.js +96 -0
  255. package/src/structures/Interaction.js +351 -0
  256. package/src/structures/InteractionCollector.js +248 -0
  257. package/src/structures/InteractionResponse.js +114 -0
  258. package/src/structures/InteractionWebhook.js +43 -0
  259. package/src/structures/Invite.js +375 -0
  260. package/src/structures/InviteGuild.js +23 -0
  261. package/src/structures/InviteStageInstance.js +86 -0
  262. package/src/structures/Message.js +1188 -0
  263. package/src/structures/MessageActionRow.js +103 -0
  264. package/src/structures/MessageAttachment.js +204 -0
  265. package/src/structures/MessageButton.js +231 -0
  266. package/src/structures/MessageCollector.js +146 -0
  267. package/src/structures/MessageComponentInteraction.js +120 -0
  268. package/src/structures/MessageContextMenuInteraction.js +20 -0
  269. package/src/structures/MessageEmbed.js +586 -0
  270. package/src/structures/MessageMentions.js +272 -0
  271. package/src/structures/MessagePayload.js +358 -0
  272. package/src/structures/MessageReaction.js +171 -0
  273. package/src/structures/MessageSelectMenu.js +391 -0
  274. package/src/structures/Modal.js +279 -0
  275. package/src/structures/ModalSubmitFieldsResolver.js +53 -0
  276. package/src/structures/ModalSubmitInteraction.js +119 -0
  277. package/src/structures/NewsChannel.js +32 -0
  278. package/src/structures/OAuth2Guild.js +28 -0
  279. package/src/structures/PartialGroupDMChannel.js +449 -0
  280. package/src/structures/PermissionOverwrites.js +196 -0
  281. package/src/structures/Presence.js +443 -0
  282. package/src/structures/ReactionCollector.js +229 -0
  283. package/src/structures/ReactionEmoji.js +31 -0
  284. package/src/structures/RichPresence.js +722 -0
  285. package/src/structures/Role.js +531 -0
  286. package/src/structures/SelectMenuInteraction.js +170 -0
  287. package/src/structures/Session.js +81 -0
  288. package/src/structures/StageChannel.js +104 -0
  289. package/src/structures/StageInstance.js +208 -0
  290. package/src/structures/Sticker.js +310 -0
  291. package/src/structures/StickerPack.js +95 -0
  292. package/src/structures/StoreChannel.js +56 -0
  293. package/src/structures/Team.js +167 -0
  294. package/src/structures/TeamMember.js +71 -0
  295. package/src/structures/TextChannel.js +33 -0
  296. package/src/structures/TextInputComponent.js +201 -0
  297. package/src/structures/ThreadChannel.js +626 -0
  298. package/src/structures/ThreadMember.js +105 -0
  299. package/src/structures/Typing.js +74 -0
  300. package/src/structures/User.js +730 -0
  301. package/src/structures/UserContextMenuInteraction.js +29 -0
  302. package/src/structures/VoiceChannel.js +110 -0
  303. package/src/structures/VoiceRegion.js +53 -0
  304. package/src/structures/VoiceState.js +353 -0
  305. package/src/structures/WebEmbed.js +412 -0
  306. package/src/structures/Webhook.js +461 -0
  307. package/src/structures/WelcomeChannel.js +60 -0
  308. package/src/structures/WelcomeScreen.js +48 -0
  309. package/src/structures/Widget.js +87 -0
  310. package/src/structures/WidgetMember.js +99 -0
  311. package/src/structures/interfaces/Application.js +190 -0
  312. package/src/structures/interfaces/Collector.js +300 -0
  313. package/src/structures/interfaces/InteractionResponses.js +313 -0
  314. package/src/structures/interfaces/TextBasedChannel.js +566 -0
  315. package/src/util/ActivityFlags.js +44 -0
  316. package/src/util/ApplicationFlags.js +76 -0
  317. package/src/util/AttachmentFlags.js +38 -0
  318. package/src/util/BitField.js +170 -0
  319. package/src/util/ChannelFlags.js +45 -0
  320. package/src/util/Constants.js +1940 -0
  321. package/src/util/DataResolver.js +145 -0
  322. package/src/util/Formatters.js +214 -0
  323. package/src/util/GuildMemberFlags.js +43 -0
  324. package/src/util/Intents.js +74 -0
  325. package/src/util/LimitedCollection.js +131 -0
  326. package/src/util/MessageFlags.js +54 -0
  327. package/src/util/Options.js +364 -0
  328. package/src/util/Permissions.js +187 -0
  329. package/src/util/PremiumUsageFlags.js +31 -0
  330. package/src/util/PurchasedFlags.js +31 -0
  331. package/src/util/RemoteAuth.js +514 -0
  332. package/src/util/RoleFlags.js +37 -0
  333. package/src/util/SnowflakeUtil.js +92 -0
  334. package/src/util/Sweepers.js +466 -0
  335. package/src/util/SystemChannelFlags.js +55 -0
  336. package/src/util/ThreadMemberFlags.js +30 -0
  337. package/src/util/UserFlags.js +104 -0
  338. package/src/util/Util.js +928 -0
  339. package/src/util/Voice.js +1456 -0
  340. package/src/util/arRPC/index.js +229 -0
  341. package/src/util/arRPC/process/detectable.json +1 -0
  342. package/src/util/arRPC/process/index.js +102 -0
  343. package/src/util/arRPC/process/native/index.js +5 -0
  344. package/src/util/arRPC/process/native/linux.js +37 -0
  345. package/src/util/arRPC/process/native/win32.js +25 -0
  346. package/src/util/arRPC/transports/ipc.js +281 -0
  347. package/src/util/arRPC/transports/websocket.js +128 -0
  348. package/typings/enums.d.ts +346 -0
  349. package/typings/index.d.ts +7776 -0
  350. package/typings/index.test-d.ts +0 -0
  351. package/typings/rawDataTypes.d.ts +283 -0
@@ -0,0 +1,905 @@
1
+ 'use strict';
2
+
3
+ const EventEmitter = require('node:events');
4
+ const { setTimeout, setInterval, clearTimeout } = require('node:timers');
5
+ const WebSocket = require('../../WebSocket');
6
+ const { Status, Events, ShardEvents, Opcodes, WSEvents, WSCodes } = require('../../util/Constants');
7
+ const Intents = require('../../util/Intents');
8
+ const { getProxyObject } = require('../../util/Util');
9
+
10
+ const STATUS_KEYS = Object.keys(Status);
11
+ const CONNECTION_STATE = Object.keys(WebSocket.WebSocket);
12
+
13
+ let zlib;
14
+
15
+ try {
16
+ zlib = require('zlib-sync');
17
+ } catch {} // eslint-disable-line no-empty
18
+
19
+ /**
20
+ * Represents a Shard's WebSocket connection
21
+ */
22
+ class WebSocketShard extends EventEmitter {
23
+ constructor(manager, id) {
24
+ super();
25
+
26
+ /**
27
+ * The WebSocketManager of the shard
28
+ * @type {WebSocketManager}
29
+ */
30
+ this.manager = manager;
31
+
32
+ /**
33
+ * The shard's id
34
+ * @type {number}
35
+ */
36
+ this.id = id;
37
+
38
+ /**
39
+ * The current status of the shard
40
+ * @type {Status}
41
+ */
42
+ this.status = Status.IDLE;
43
+
44
+ /**
45
+ * The current sequence of the shard
46
+ * @type {number}
47
+ * @private
48
+ */
49
+ this.sequence = -1;
50
+
51
+ /**
52
+ * The sequence of the shard after close
53
+ * @type {number}
54
+ * @private
55
+ */
56
+ this.closeSequence = 0;
57
+
58
+ /**
59
+ * The current session id of the shard
60
+ * @type {?string}
61
+ * @private
62
+ */
63
+ this.sessionId = null;
64
+
65
+ /**
66
+ * URL to use when resuming
67
+ * @type {?string}
68
+ * @private
69
+ */
70
+ this.resumeURL = null;
71
+
72
+ /**
73
+ * The previous heartbeat ping of the shard
74
+ * @type {number}
75
+ */
76
+ this.ping = -1;
77
+
78
+ /**
79
+ * The last time a ping was sent (a timestamp)
80
+ * @type {number}
81
+ * @private
82
+ */
83
+ this.lastPingTimestamp = -1;
84
+
85
+ /**
86
+ * If we received a heartbeat ack back. Used to identify zombie connections
87
+ * @type {boolean}
88
+ * @private
89
+ */
90
+ this.lastHeartbeatAcked = true;
91
+
92
+ /**
93
+ * Used to prevent calling {@link WebSocketShard#event:close} twice while closing or terminating the WebSocket.
94
+ * @type {boolean}
95
+ * @private
96
+ */
97
+ this.closeEmitted = false;
98
+
99
+ /**
100
+ * Contains the rate limit queue and metadata
101
+ * @name WebSocketShard#ratelimit
102
+ * @type {Object}
103
+ * @private
104
+ */
105
+ Object.defineProperty(this, 'ratelimit', {
106
+ value: {
107
+ queue: [],
108
+ total: 120,
109
+ remaining: 120,
110
+ time: 60e3,
111
+ timer: null,
112
+ },
113
+ });
114
+
115
+ /**
116
+ * The WebSocket connection for the current shard
117
+ * @name WebSocketShard#connection
118
+ * @type {?WebSocket}
119
+ * @private
120
+ */
121
+ Object.defineProperty(this, 'connection', { value: null, writable: true });
122
+
123
+ /**
124
+ * @external Inflate
125
+ * @see {@link https://www.npmjs.com/package/zlib-sync}
126
+ */
127
+
128
+ /**
129
+ * The compression to use
130
+ * @name WebSocketShard#inflate
131
+ * @type {?Inflate}
132
+ * @private
133
+ */
134
+ Object.defineProperty(this, 'inflate', { value: null, writable: true });
135
+
136
+ /**
137
+ * The HELLO timeout
138
+ * @name WebSocketShard#helloTimeout
139
+ * @type {?NodeJS.Timeout}
140
+ * @private
141
+ */
142
+ Object.defineProperty(this, 'helloTimeout', { value: null, writable: true });
143
+
144
+ /**
145
+ * The WebSocket timeout.
146
+ * @name WebSocketShard#wsCloseTimeout
147
+ * @type {?NodeJS.Timeout}
148
+ * @private
149
+ */
150
+ Object.defineProperty(this, 'wsCloseTimeout', { value: null, writable: true });
151
+
152
+ /**
153
+ * If the manager attached its event handlers on the shard
154
+ * @name WebSocketShard#eventsAttached
155
+ * @type {boolean}
156
+ * @private
157
+ */
158
+ Object.defineProperty(this, 'eventsAttached', { value: false, writable: true });
159
+
160
+ /**
161
+ * A set of guild ids this shard expects to receive
162
+ * @name WebSocketShard#expectedGuilds
163
+ * @type {?Set<string>}
164
+ * @private
165
+ */
166
+ Object.defineProperty(this, 'expectedGuilds', { value: null, writable: true });
167
+
168
+ /**
169
+ * The ready timeout
170
+ * @name WebSocketShard#readyTimeout
171
+ * @type {?NodeJS.Timeout}
172
+ * @private
173
+ */
174
+ Object.defineProperty(this, 'readyTimeout', { value: null, writable: true });
175
+
176
+ /**
177
+ * Time when the WebSocket connection was opened
178
+ * @name WebSocketShard#connectedAt
179
+ * @type {number}
180
+ * @private
181
+ */
182
+ Object.defineProperty(this, 'connectedAt', { value: 0, writable: true });
183
+ }
184
+
185
+ /**
186
+ * Emits a debug event.
187
+ * @param {string} message The debug message
188
+ * @private
189
+ */
190
+ debug(message) {
191
+ this.manager.debug(message, this);
192
+ }
193
+
194
+ /**
195
+ * Connects the shard to the gateway.
196
+ * @private
197
+ * @returns {Promise<void>} A promise that will resolve if the shard turns ready successfully,
198
+ * or reject if we couldn't connect
199
+ */
200
+ connect() {
201
+ const { client } = this.manager;
202
+
203
+ const gateway = this.resumeURL ?? this.manager.gateway;
204
+
205
+ if (this.connection?.readyState === WebSocket.OPEN && this.status === Status.READY) {
206
+ return Promise.resolve();
207
+ }
208
+
209
+ return new Promise((resolve, reject) => {
210
+ const cleanup = () => {
211
+ this.removeListener(ShardEvents.CLOSE, onClose);
212
+ this.removeListener(ShardEvents.READY, onReady);
213
+ this.removeListener(ShardEvents.RESUMED, onResumed);
214
+ this.removeListener(ShardEvents.INVALID_SESSION, onInvalidOrDestroyed);
215
+ this.removeListener(ShardEvents.DESTROYED, onInvalidOrDestroyed);
216
+ };
217
+
218
+ const onReady = () => {
219
+ cleanup();
220
+ resolve();
221
+ };
222
+
223
+ const onResumed = () => {
224
+ cleanup();
225
+ resolve();
226
+ };
227
+
228
+ const onClose = event => {
229
+ cleanup();
230
+ reject(event);
231
+ };
232
+
233
+ const onInvalidOrDestroyed = () => {
234
+ cleanup();
235
+ // eslint-disable-next-line prefer-promise-reject-errors
236
+ reject();
237
+ };
238
+
239
+ this.once(ShardEvents.READY, onReady);
240
+ this.once(ShardEvents.RESUMED, onResumed);
241
+ this.once(ShardEvents.CLOSE, onClose);
242
+ this.once(ShardEvents.INVALID_SESSION, onInvalidOrDestroyed);
243
+ this.once(ShardEvents.DESTROYED, onInvalidOrDestroyed);
244
+
245
+ if (this.connection?.readyState === WebSocket.OPEN) {
246
+ this.debug('An open connection was found, attempting an immediate identify.');
247
+ this.identify();
248
+ return;
249
+ }
250
+
251
+ if (this.connection) {
252
+ this.debug(`A connection object was found. Cleaning up before continuing.
253
+ State: ${CONNECTION_STATE[this.connection.readyState]}`);
254
+ this.destroy({ emit: false });
255
+ }
256
+
257
+ const wsQuery = { v: client.options.ws.version };
258
+
259
+ if (zlib) {
260
+ this.inflate = new zlib.Inflate({
261
+ chunkSize: 65535,
262
+ flush: zlib.Z_SYNC_FLUSH,
263
+ to: WebSocket.encoding === 'json' ? 'string' : '',
264
+ });
265
+ wsQuery.compress = 'zlib-stream';
266
+ }
267
+
268
+ this.debug(
269
+ `[CONNECT]
270
+ Gateway : ${gateway}
271
+ Version : ${client.options.ws.version}
272
+ Encoding : ${WebSocket.encoding}
273
+ Compression: ${zlib ? 'zlib-stream' : 'none'}
274
+ Proxy : ${client.options.proxy || 'none'}`,
275
+ );
276
+
277
+ this.status = this.status === Status.DISCONNECTED ? Status.RECONNECTING : Status.CONNECTING;
278
+ this.setHelloTimeout();
279
+ this.setWsCloseTimeout(-1);
280
+ this.connectedAt = Date.now();
281
+
282
+ let args = { handshakeTimeout: 30_000 };
283
+ if (client.options.proxy.length > 0) {
284
+ args.agent = getProxyObject(client.options.proxy);
285
+ this.debug(`Using proxy ${client.options.proxy}`, args);
286
+ }
287
+ // Adding a handshake timeout to just make sure no zombie connection appears.
288
+ const ws = (this.connection = WebSocket.create(gateway, wsQuery, args));
289
+ ws.onopen = this.onOpen.bind(this);
290
+ ws.onmessage = this.onMessage.bind(this);
291
+ ws.onerror = this.onError.bind(this);
292
+ ws.onclose = this.onClose.bind(this);
293
+ });
294
+ }
295
+
296
+ /**
297
+ * Called whenever a connection is opened to the gateway.
298
+ * @private
299
+ */
300
+ onOpen() {
301
+ this.debug(`[CONNECTED] Took ${Date.now() - this.connectedAt}ms`);
302
+ this.status = Status.NEARLY;
303
+ }
304
+
305
+ /**
306
+ * Called whenever a message is received.
307
+ * @param {MessageEvent} event Event received
308
+ * @private
309
+ */
310
+ onMessage({ data }) {
311
+ let raw;
312
+ if (data instanceof ArrayBuffer) data = new Uint8Array(data);
313
+ if (zlib) {
314
+ const l = data.length;
315
+ const flush =
316
+ l >= 4 && data[l - 4] === 0x00 && data[l - 3] === 0x00 && data[l - 2] === 0xff && data[l - 1] === 0xff;
317
+
318
+ this.inflate.push(data, flush && zlib.Z_SYNC_FLUSH);
319
+ if (!flush) return;
320
+ raw = this.inflate.result;
321
+ } else {
322
+ raw = data;
323
+ }
324
+ let packet;
325
+ try {
326
+ packet = WebSocket.unpack(raw);
327
+ } catch (err) {
328
+ this.manager.client.emit(Events.SHARD_ERROR, err, this.id);
329
+ return;
330
+ }
331
+ this.manager.client.emit(Events.RAW, packet, this.id);
332
+ if (packet.op === Opcodes.DISPATCH) this.manager.emit(packet.t, packet.d, this.id);
333
+ this.onPacket(packet);
334
+ }
335
+
336
+ /**
337
+ * Called whenever an error occurs with the WebSocket.
338
+ * @param {ErrorEvent} event The error that occurred
339
+ * @private
340
+ */
341
+ onError(event) {
342
+ const error = event?.error ?? event;
343
+ if (!error) return;
344
+
345
+ /**
346
+ * Emitted whenever a shard's WebSocket encounters a connection error.
347
+ * @event Client#shardError
348
+ * @param {Error} error The encountered error
349
+ * @param {number} shardId The shard that encountered this error
350
+ */
351
+ this.manager.client.emit(Events.SHARD_ERROR, error, this.id);
352
+ }
353
+
354
+ /**
355
+ * @external CloseEvent
356
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}
357
+ */
358
+
359
+ /**
360
+ * @external ErrorEvent
361
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent}
362
+ */
363
+
364
+ /**
365
+ * @external MessageEvent
366
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent}
367
+ */
368
+
369
+ /**
370
+ * Called whenever a connection to the gateway is closed.
371
+ * @param {CloseEvent} event Close event that was received
372
+ * @private
373
+ */
374
+ onClose(event) {
375
+ this.closeEmitted = true;
376
+ if (this.sequence !== -1) this.closeSequence = this.sequence;
377
+ this.sequence = -1;
378
+ this.setHeartbeatTimer(-1);
379
+ this.setHelloTimeout(-1);
380
+ // Clearing the WebSocket close timeout as close was emitted.
381
+ this.setWsCloseTimeout(-1);
382
+ // If we still have a connection object, clean up its listeners
383
+ if (this.connection) {
384
+ this._cleanupConnection();
385
+ // Having this after _cleanupConnection to just clean up the connection and not listen to ws.onclose
386
+ this.destroy({ reset: !this.sessionId, emit: false, log: false });
387
+ }
388
+ this.status = Status.DISCONNECTED;
389
+ this.emitClose(event);
390
+ }
391
+
392
+ /**
393
+ * This method is responsible to emit close event for this shard.
394
+ * This method helps the shard reconnect.
395
+ * @param {CloseEvent} [event] Close event that was received
396
+ */
397
+ emitClose(
398
+ event = {
399
+ code: 1011,
400
+ reason: WSCodes[1011],
401
+ wasClean: false,
402
+ },
403
+ ) {
404
+ this.debug(`[CLOSE]
405
+ Event Code: ${event.code}
406
+ Clean : ${event.wasClean}
407
+ Reason : ${event.reason ?? 'No reason received'}`);
408
+ /**
409
+ * Emitted when a shard's WebSocket closes.
410
+ * @private
411
+ * @event WebSocketShard#close
412
+ * @param {CloseEvent} event The received event
413
+ */
414
+ this.emit(ShardEvents.CLOSE, event);
415
+ }
416
+
417
+ /**
418
+ * Called whenever a packet is received.
419
+ * @param {Object} packet The received packet
420
+ * @private
421
+ */
422
+ onPacket(packet) {
423
+ if (!packet) {
424
+ this.debug(`Received broken packet: '${packet}'.`);
425
+ return;
426
+ }
427
+
428
+ switch (packet.t) {
429
+ case WSEvents.READY:
430
+ /**
431
+ * Emitted when the shard receives the READY payload and is now waiting for guilds
432
+ * @event WebSocketShard#ready
433
+ */
434
+ this.emit(ShardEvents.READY);
435
+
436
+ this.sessionId = packet.d.session_id;
437
+ this.resumeURL = packet.d.resume_gateway_url;
438
+ this.expectedGuilds = new Set(packet.d.guilds.filter(d => d?.unavailable == true).map(d => d.id));
439
+ this.status = Status.WAITING_FOR_GUILDS;
440
+ this.debug(`[READY] Session ${this.sessionId} | ResumeURL ${this.resumeURL}`);
441
+ this.lastHeartbeatAcked = true;
442
+ this.sendHeartbeat('ReadyHeartbeat');
443
+ break;
444
+ case WSEvents.RESUMED: {
445
+ /**
446
+ * Emitted when the shard resumes successfully
447
+ * @event WebSocketShard#resumed
448
+ */
449
+ this.emit(ShardEvents.RESUMED);
450
+
451
+ this.status = Status.READY;
452
+ const replayed = packet.s - this.closeSequence;
453
+ this.debug(`[RESUMED] Session ${this.sessionId} | Replayed ${replayed} events.`);
454
+ this.lastHeartbeatAcked = true;
455
+ this.sendHeartbeat('ResumeHeartbeat');
456
+ break;
457
+ }
458
+ }
459
+
460
+ if (packet.s > this.sequence) this.sequence = packet.s;
461
+
462
+ switch (packet.op) {
463
+ case Opcodes.HELLO:
464
+ this.setHelloTimeout(-1);
465
+ this.setHeartbeatTimer(packet.d.heartbeat_interval);
466
+ this.identify();
467
+ break;
468
+ case Opcodes.RECONNECT:
469
+ this.debug('[RECONNECT] Discord asked us to reconnect');
470
+ this.destroy({ closeCode: 4_000 });
471
+ break;
472
+ case Opcodes.INVALID_SESSION:
473
+ this.debug(`[INVALID SESSION] Resumable: ${packet.d}.`);
474
+ // If we can resume the session, do so immediately
475
+ if (packet.d) {
476
+ this.identifyResume();
477
+ return;
478
+ }
479
+ // Reset the sequence
480
+ this.sequence = -1;
481
+ // Reset the session id as it's invalid
482
+ this.sessionId = null;
483
+ // Set the status to reconnecting
484
+ this.status = Status.RECONNECTING;
485
+ // Finally, emit the INVALID_SESSION event
486
+ /**
487
+ * Emitted when the session has been invalidated.
488
+ * @event WebSocketShard#invalidSession
489
+ */
490
+ this.emit(ShardEvents.INVALID_SESSION);
491
+ break;
492
+ case Opcodes.HEARTBEAT_ACK:
493
+ this.ackHeartbeat();
494
+ break;
495
+ case Opcodes.HEARTBEAT:
496
+ this.sendHeartbeat('HeartbeatRequest', true);
497
+ break;
498
+ default:
499
+ this.manager.handlePacket(packet, this);
500
+ if (this.status === Status.WAITING_FOR_GUILDS && packet.t === WSEvents.GUILD_CREATE) {
501
+ this.expectedGuilds.delete(packet.d.id);
502
+ this.checkReady();
503
+ }
504
+ }
505
+ }
506
+
507
+ /**
508
+ * Checks if the shard can be marked as ready
509
+ * @private
510
+ */
511
+ checkReady() {
512
+ // Step 0. Clear the ready timeout, if it exists
513
+ if (this.readyTimeout) {
514
+ clearTimeout(this.readyTimeout);
515
+ this.readyTimeout = null;
516
+ }
517
+ // Step 1. If we don't have any other guilds pending, we are ready
518
+ if (!this.expectedGuilds.size) {
519
+ this.debug('Shard received all its guilds. Marking as fully ready.');
520
+ this.status = Status.READY;
521
+
522
+ /**
523
+ * Emitted when the shard is fully ready.
524
+ * This event is emitted if:
525
+ * * all guilds were received by this shard
526
+ * * the ready timeout expired, and some guilds are unavailable
527
+ * @event WebSocketShard#allReady
528
+ * @param {?Set<string>} unavailableGuilds Set of unavailable guilds, if any
529
+ */
530
+ this.emit(ShardEvents.ALL_READY);
531
+ return;
532
+ }
533
+ const hasGuildsIntent = new Intents(this.manager.client.options.intents).has(Intents.FLAGS.GUILDS);
534
+ // Step 2. Create a timeout that will mark the shard as ready if there are still unavailable guilds
535
+ // * The timeout is 15 seconds by default
536
+ // * This can be optionally changed in the client options via the `waitGuildTimeout` option
537
+ // * a timeout time of zero will skip this timeout, which potentially could cause the Client to miss guilds.
538
+
539
+ const { waitGuildTimeout } = this.manager.client.options;
540
+
541
+ this.readyTimeout = setTimeout(() => {
542
+ this.debug(
543
+ `Shard ${hasGuildsIntent ? 'did' : 'will'} not receive any more guild packets` +
544
+ `${hasGuildsIntent ? ` in ${waitGuildTimeout} ms` : ''}.\nUnavailable guild count: ${
545
+ this.expectedGuilds.size
546
+ }`,
547
+ );
548
+
549
+ this.readyTimeout = null;
550
+
551
+ this.status = Status.READY;
552
+
553
+ this.emit(ShardEvents.ALL_READY, this.expectedGuilds);
554
+ // }, hasGuildsIntent && waitGuildTimeout).unref();
555
+ }, waitGuildTimeout).unref();
556
+ }
557
+
558
+ /**
559
+ * Sets the HELLO packet timeout.
560
+ * @param {number} [time] If set to -1, it will clear the hello timeout
561
+ * @private
562
+ */
563
+ setHelloTimeout(time) {
564
+ if (time === -1) {
565
+ if (this.helloTimeout) {
566
+ this.debug('Clearing the HELLO timeout.');
567
+ clearTimeout(this.helloTimeout);
568
+ this.helloTimeout = null;
569
+ }
570
+ return;
571
+ }
572
+ this.debug('Setting a HELLO timeout for 20s.');
573
+ this.helloTimeout = setTimeout(() => {
574
+ this.debug('Did not receive HELLO in time. Destroying and connecting again.');
575
+ this.destroy({ reset: true, closeCode: 4009 });
576
+ }, 20_000).unref();
577
+ }
578
+
579
+ /**
580
+ * Sets the WebSocket Close timeout.
581
+ * This method is responsible for detecting any zombie connections if the WebSocket fails to close properly.
582
+ * @param {number} [time] If set to -1, it will clear the timeout
583
+ * @private
584
+ */
585
+ setWsCloseTimeout(time) {
586
+ if (this.wsCloseTimeout) {
587
+ this.debug('[WebSocket] Clearing the close timeout.');
588
+ clearTimeout(this.wsCloseTimeout);
589
+ }
590
+ if (time === -1) {
591
+ this.wsCloseTimeout = null;
592
+ return;
593
+ }
594
+ this.wsCloseTimeout = setTimeout(() => {
595
+ this.setWsCloseTimeout(-1);
596
+ // Check if close event was emitted.
597
+ if (this.closeEmitted) {
598
+ this.debug(`[WebSocket] close was already emitted, assuming the connection was closed properly.`);
599
+ // Setting the variable false to check for zombie connections.
600
+ this.closeEmitted = false;
601
+ return;
602
+ }
603
+
604
+ this.debug(
605
+ // eslint-disable-next-line max-len
606
+ `[WebSocket] Close Emitted: ${this.closeEmitted} | did not close properly, assuming a zombie connection.\nEmitting close and reconnecting again.`,
607
+ );
608
+
609
+ if (this.connection) this._cleanupConnection();
610
+
611
+ this.emitClose({
612
+ code: 4009,
613
+ reason: 'Session time out.',
614
+ wasClean: false,
615
+ });
616
+ }, time);
617
+ }
618
+
619
+ /**
620
+ * Sets the heartbeat timer for this shard.
621
+ * @param {number} time If -1, clears the interval, any other number sets an interval
622
+ * @private
623
+ */
624
+ setHeartbeatTimer(time) {
625
+ if (time === -1) {
626
+ if (this.heartbeatInterval) {
627
+ this.debug('Clearing the heartbeat interval.');
628
+ clearInterval(this.heartbeatInterval);
629
+ this.heartbeatInterval = null;
630
+ }
631
+ return;
632
+ }
633
+ this.debug(`Setting a heartbeat interval for ${time}ms.`);
634
+ // Sanity checks
635
+ if (this.heartbeatInterval) clearInterval(this.heartbeatInterval);
636
+ this.heartbeatInterval = setInterval(() => this.sendHeartbeat(), time).unref();
637
+ }
638
+
639
+ /**
640
+ * Sends a heartbeat to the WebSocket.
641
+ * If this shard didn't receive a heartbeat last time, it will destroy it and reconnect
642
+ * @param {string} [tag='HeartbeatTimer'] What caused this heartbeat to be sent
643
+ * @param {boolean} [ignoreHeartbeatAck] If we should send the heartbeat forcefully.
644
+ * @private
645
+ */
646
+ sendHeartbeat(
647
+ tag = 'HeartbeatTimer',
648
+ ignoreHeartbeatAck = [Status.WAITING_FOR_GUILDS, Status.IDENTIFYING, Status.RESUMING].includes(this.status),
649
+ ) {
650
+ if (ignoreHeartbeatAck && !this.lastHeartbeatAcked) {
651
+ this.debug(`[${tag}] Didn't process heartbeat ack yet but we are still connected. Sending one now.`);
652
+ } else if (!this.lastHeartbeatAcked) {
653
+ this.debug(
654
+ `[${tag}] Didn't receive a heartbeat ack last time, assuming zombie connection. Destroying and reconnecting.
655
+ Status : ${STATUS_KEYS[this.status]}
656
+ Sequence : ${this.sequence}
657
+ Connection State: ${this.connection ? CONNECTION_STATE[this.connection.readyState] : 'No Connection??'}`,
658
+ );
659
+
660
+ this.destroy({ reset: true, closeCode: 4009 });
661
+ return;
662
+ }
663
+
664
+ this.debug(`[${tag}] Sending a heartbeat.`);
665
+ this.lastHeartbeatAcked = false;
666
+ this.lastPingTimestamp = Date.now();
667
+ this.send({ op: Opcodes.HEARTBEAT, d: this.sequence }, true);
668
+ }
669
+
670
+ /**
671
+ * Acknowledges a heartbeat.
672
+ * @private
673
+ */
674
+ ackHeartbeat() {
675
+ this.lastHeartbeatAcked = true;
676
+ const latency = Date.now() - this.lastPingTimestamp;
677
+ this.debug(`Heartbeat acknowledged, latency of ${latency}ms.`);
678
+ this.ping = latency;
679
+ }
680
+
681
+ /**
682
+ * Identifies the client on the connection.
683
+ * @private
684
+ * @returns {void}
685
+ */
686
+ identify() {
687
+ return this.sessionId ? this.identifyResume() : this.identifyNew();
688
+ }
689
+
690
+ /**
691
+ * Identifies as a new connection on the gateway.
692
+ * @private
693
+ */
694
+ identifyNew() {
695
+ const { client } = this.manager;
696
+ if (!client.token) {
697
+ this.debug('[IDENTIFY] No token available to identify a new session.');
698
+ return;
699
+ }
700
+
701
+ this.status = Status.IDENTIFYING;
702
+
703
+ Object.keys(client.options.ws.properties)
704
+ .filter(k => k.startsWith('$'))
705
+ .forEach(k => {
706
+ client.options.ws.properties[k.slice(1)] = client.options.ws.properties[k];
707
+ delete client.options.ws.properties[k];
708
+ });
709
+ const d = {
710
+ presence: client.options.presence,
711
+ ...client.options.ws,
712
+ token: client.token,
713
+ };
714
+
715
+ delete d.version;
716
+
717
+ this.debug(
718
+ `[IDENTIFY] Shard ${this.id}/${client.options.shardCount} with intents: ${Intents.resolve(
719
+ client.options.intents,
720
+ )} 😊`,
721
+ );
722
+ this.send({ op: Opcodes.IDENTIFY, d }, true);
723
+ }
724
+
725
+ /**
726
+ * Resumes a session on the gateway.
727
+ * @private
728
+ */
729
+ identifyResume() {
730
+ if (!this.sessionId) {
731
+ this.debug('[RESUME] No session id was present; identifying as a new session.');
732
+ this.identifyNew();
733
+ return;
734
+ }
735
+
736
+ this.status = Status.RESUMING;
737
+
738
+ this.debug(`[RESUME] Session ${this.sessionId}, sequence ${this.closeSequence}`);
739
+
740
+ const d = {
741
+ token: this.manager.client.token,
742
+ session_id: this.sessionId,
743
+ seq: this.closeSequence,
744
+ };
745
+
746
+ this.send({ op: Opcodes.RESUME, d }, true);
747
+ }
748
+
749
+ /**
750
+ * Adds a packet to the queue to be sent to the gateway.
751
+ * <warn>If you use this method, make sure you understand that you need to provide
752
+ * a full [Payload](https://discord.com/developers/docs/topics/gateway-events#payload-structure).
753
+ * Do not use this method if you don't know what you're doing.</warn>
754
+ * @param {Object} data The full packet to send
755
+ * @param {boolean} [important=false] If this packet should be added first in queue
756
+ */
757
+ send(data, important = false) {
758
+ this.ratelimit.queue[important ? 'unshift' : 'push'](data);
759
+ this.processQueue();
760
+ }
761
+
762
+ /**
763
+ * Sends data, bypassing the queue.
764
+ * @param {Object} data Packet to send
765
+ * @returns {void}
766
+ * @private
767
+ */
768
+ _send(data) {
769
+ if (this.connection?.readyState !== WebSocket.OPEN) {
770
+ this.debug(`Tried to send packet '${JSON.stringify(data)}' but no WebSocket is available!`);
771
+ this.destroy({ closeCode: 4_000 });
772
+ return;
773
+ }
774
+
775
+ this.connection.send(WebSocket.pack(data), err => {
776
+ if (err) this.manager.client.emit(Events.SHARD_ERROR, err, this.id);
777
+ });
778
+ }
779
+
780
+ /**
781
+ * Processes the current WebSocket queue.
782
+ * @returns {void}
783
+ * @private
784
+ */
785
+ processQueue() {
786
+ if (this.ratelimit.remaining === 0) return;
787
+ if (this.ratelimit.queue.length === 0) return;
788
+ if (this.ratelimit.remaining === this.ratelimit.total) {
789
+ this.ratelimit.timer = setTimeout(() => {
790
+ this.ratelimit.remaining = this.ratelimit.total;
791
+ this.processQueue();
792
+ }, this.ratelimit.time).unref();
793
+ }
794
+ while (this.ratelimit.remaining > 0) {
795
+ const item = this.ratelimit.queue.shift();
796
+ if (!item) return;
797
+ this._send(item);
798
+ this.ratelimit.remaining--;
799
+ }
800
+ }
801
+
802
+ /**
803
+ * Destroys this shard and closes its WebSocket connection.
804
+ * @param {Object} [options={ closeCode: 1000, reset: false, emit: true, log: true }] Options for destroying the shard
805
+ * @private
806
+ */
807
+ destroy({ closeCode = 1_000, reset = false, emit = true, log = true } = {}) {
808
+ if (log) {
809
+ this.debug(`[DESTROY]
810
+ Close Code : ${closeCode}
811
+ Reset : ${reset}
812
+ Emit DESTROYED: ${emit}`);
813
+ }
814
+
815
+ // Step 0: Remove all timers
816
+ this.setHeartbeatTimer(-1);
817
+ this.setHelloTimeout(-1);
818
+ this.debug(
819
+ `[WebSocket] Destroy: Attempting to close the WebSocket. | WS State: ${
820
+ CONNECTION_STATE[this.connection?.readyState ?? WebSocket.CLOSED]
821
+ }`,
822
+ );
823
+ // Step 1: Close the WebSocket connection, if any, otherwise, emit DESTROYED
824
+ if (this.connection) {
825
+ // If the connection is currently opened, we will (hopefully) receive close
826
+ if (this.connection.readyState === WebSocket.OPEN) {
827
+ this.connection.close(closeCode);
828
+ this.debug(`[WebSocket] Close: Tried closing. | WS State: ${CONNECTION_STATE[this.connection.readyState]}`);
829
+ } else {
830
+ // Connection is not OPEN
831
+ this.debug(`WS State: ${CONNECTION_STATE[this.connection.readyState]}`);
832
+ // Attempt to close the connection just in case
833
+ try {
834
+ this.connection.close(closeCode);
835
+ } catch (err) {
836
+ this.debug(
837
+ `[WebSocket] Close: Something went wrong while closing the WebSocket: ${
838
+ err.message || err
839
+ }. Forcefully terminating the connection | WS State: ${CONNECTION_STATE[this.connection.readyState]}`,
840
+ );
841
+ this.connection.terminate();
842
+ }
843
+ // Emit the destroyed event if needed
844
+ if (emit) this._emitDestroyed();
845
+ }
846
+ } else if (emit) {
847
+ // We requested a destroy, but we had no connection. Emit destroyed
848
+ this._emitDestroyed();
849
+ }
850
+
851
+ this.debug(
852
+ `[WebSocket] Adding a WebSocket close timeout to ensure a correct WS reconnect.
853
+ Timeout: ${this.manager.client.options.closeTimeout}ms`,
854
+ );
855
+ this.setWsCloseTimeout(this.manager.client.options.closeTimeout);
856
+
857
+ // Step 2: Null the connection object
858
+ this.connection = null;
859
+
860
+ // Step 3: Set the shard status to DISCONNECTED
861
+ this.status = Status.DISCONNECTED;
862
+
863
+ // Step 4: Cache the old sequence (use to attempt a resume)
864
+ if (this.sequence !== -1) this.closeSequence = this.sequence;
865
+
866
+ // Step 5: Reset the sequence, resume URL and session id if requested
867
+ if (reset) {
868
+ this.resumeURL = null;
869
+ this.sequence = -1;
870
+ this.sessionId = null;
871
+ }
872
+
873
+ // Step 6: reset the rate limit data
874
+ this.ratelimit.remaining = this.ratelimit.total;
875
+ this.ratelimit.queue.length = 0;
876
+ if (this.ratelimit.timer) {
877
+ clearTimeout(this.ratelimit.timer);
878
+ this.ratelimit.timer = null;
879
+ }
880
+ }
881
+
882
+ /**
883
+ * Cleans up the WebSocket connection listeners.
884
+ * @private
885
+ */
886
+ _cleanupConnection() {
887
+ this.connection.onopen = this.connection.onclose = this.connection.onmessage = null;
888
+ this.connection.onerror = () => null;
889
+ }
890
+
891
+ /**
892
+ * Emits the DESTROYED event on the shard
893
+ * @private
894
+ */
895
+ _emitDestroyed() {
896
+ /**
897
+ * Emitted when a shard is destroyed, but no WebSocket connection was present.
898
+ * @private
899
+ * @event WebSocketShard#destroyed
900
+ */
901
+ this.emit(ShardEvents.DESTROYED);
902
+ }
903
+ }
904
+
905
+ module.exports = WebSocketShard;