33const process = require ( 'node:process' ) ;
44const { clearTimeout, setImmediate, setTimeout } = require ( 'node:timers' ) ;
55const { Collection } = require ( '@discordjs/collection' ) ;
6- const { makeURLSearchParams } = require ( '@discordjs/rest' ) ;
6+ const { REST , RESTEvents, makeURLSearchParams } = require ( '@discordjs/rest' ) ;
7+ const { AsyncEventEmitter } = require ( '@vladfrangu/async_event_emitter' ) ;
78const { WebSocketManager, WebSocketShardEvents, WebSocketShardStatus } = require ( '@discordjs/ws' ) ;
89const { GatewayDispatchEvents, GatewayIntentBits, OAuth2Scopes, Routes } = require ( 'discord-api-types/v10' ) ;
910const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require ( '../errors/index.js' ) ;
@@ -28,7 +29,7 @@ const { Options } = require('../util/Options.js');
2829const { PermissionsBitField } = require ( '../util/PermissionsBitField.js' ) ;
2930const { Status } = require ( '../util/Status.js' ) ;
3031const { Sweepers } = require ( '../util/Sweepers.js' ) ;
31- const { BaseClient } = require ( './BaseClient .js' ) ;
32+ const { flatten } = require ( '../util/Util .js' ) ;
3233const { ActionsManager } = require ( './actions/ActionsManager.js' ) ;
3334const { ClientVoiceManager } = require ( './voice/ClientVoiceManager.js' ) ;
3435const { PacketHandlers } = require ( './websocket/handlers/index.js' ) ;
@@ -47,14 +48,57 @@ const BeforeReadyWhitelist = [
4748/**
4849 * The main hub for interacting with the Discord API, and the starting point for any bot.
4950 *
50- * @extends {BaseClient }
51+ * @extends {AsyncEventEmitter }
5152 */
52- class Client extends BaseClient {
53+ class Client extends AsyncEventEmitter {
5354 /**
5455 * @param {ClientOptions } options Options for the client
5556 */
56- constructor ( options ) {
57- super ( options ) ;
57+ constructor ( options = { } ) {
58+ super ( ) ;
59+
60+ if ( typeof options !== 'object' || options === null ) {
61+ throw new DiscordjsTypeError ( ErrorCodes . InvalidType , 'options' , 'object' , true ) ;
62+ }
63+
64+ const defaultOptions = Options . createDefault ( ) ;
65+ /**
66+ * The options the client was instantiated with
67+ *
68+ * @type {ClientOptions }
69+ */
70+ this . options = {
71+ ...defaultOptions ,
72+ ...options ,
73+ presence : {
74+ ...defaultOptions . presence ,
75+ ...options . presence ,
76+ } ,
77+ sweepers : {
78+ ...defaultOptions . sweepers ,
79+ ...options . sweepers ,
80+ } ,
81+ ws : {
82+ ...defaultOptions . ws ,
83+ ...options . ws ,
84+ } ,
85+ rest : {
86+ ...defaultOptions . rest ,
87+ ...options . rest ,
88+ userAgentAppendix : options . rest ?. userAgentAppendix
89+ ? `${ Options . userAgentAppendix } ${ options . rest . userAgentAppendix } `
90+ : Options . userAgentAppendix ,
91+ } ,
92+ } ;
93+
94+ /**
95+ * The REST manager of the client
96+ *
97+ * @type {REST }
98+ */
99+ this . rest = new REST ( this . options . rest ) ;
100+
101+ this . rest . on ( RESTEvents . Debug , message => this . emit ( Events . Debug , message ) ) ;
58102
59103 const data = require ( 'node:worker_threads' ) . workerData ?? process . env ;
60104 const defaults = Options . createDefault ( ) ;
@@ -442,12 +486,56 @@ class Client extends BaseClient {
442486 }
443487
444488 /**
445- * Logs out, terminates the connection to Discord, and destroys the client.
489+ * Options used for deleting a webhook.
490+ *
491+ * @typedef {Object } WebhookDeleteOptions
492+ * @property {string } [token] Token of the webhook
493+ * @property {string } [reason] The reason for deleting the webhook
494+ */
495+
496+ /**
497+ * Deletes a webhook.
498+ *
499+ * @param {Snowflake } id The webhook's id
500+ * @param {WebhookDeleteOptions } [options] Options for deleting the webhook
501+ * @returns {Promise<void> }
502+ */
503+ async deleteWebhook ( id , { token, reason } = { } ) {
504+ await this . rest . delete ( Routes . webhook ( id , token ) , { auth : ! token , reason } ) ;
505+ }
506+
507+ /**
508+ * Increments max listeners by one, if they are not zero.
509+ *
510+ * @private
511+ */
512+ incrementMaxListeners ( ) {
513+ const maxListeners = this . getMaxListeners ( ) ;
514+ if ( maxListeners !== 0 ) {
515+ this . setMaxListeners ( maxListeners + 1 ) ;
516+ }
517+ }
518+
519+ /**
520+ * Decrements max listeners by one, if they are not zero.
521+ *
522+ * @private
523+ */
524+ decrementMaxListeners ( ) {
525+ const maxListeners = this . getMaxListeners ( ) ;
526+ if ( maxListeners !== 0 ) {
527+ this . setMaxListeners ( maxListeners - 1 ) ;
528+ }
529+ }
530+
531+ /**
532+ * Destroys all assets used by the client.
446533 *
447534 * @returns {Promise<void> }
448535 */
449536 async destroy ( ) {
450- super . destroy ( ) ;
537+ this . rest . clearHashSweeper ( ) ;
538+ this . rest . clearHandlerSweeper ( ) ;
451539
452540 this . sweepers . destroy ( ) ;
453541 await this . ws . destroy ( ) ;
@@ -700,11 +788,8 @@ class Client extends BaseClient {
700788 return `${ this . options . rest . api } ${ Routes . oauth2Authorization ( ) } ?${ query } ` ;
701789 }
702790
703- toJSON ( ) {
704- return super . toJSON ( {
705- actions : false ,
706- presence : false ,
707- } ) ;
791+ toJSON ( ...props ) {
792+ return flatten ( this , { actions : false , presence : false } , ...props ) ;
708793 }
709794
710795 /**
@@ -797,6 +882,10 @@ class Client extends BaseClient {
797882 throw new DiscordjsTypeError ( ErrorCodes . ClientInvalidOption , 'jsonTransformer' , 'a function' ) ;
798883 }
799884 }
885+
886+ async [ Symbol . asyncDispose ] ( ) {
887+ await this . destroy ( ) ;
888+ }
800889}
801890
802891exports . Client = Client ;
0 commit comments