Skip to content

Commit 6ced9bd

Browse files
authored
refactor(client)!: remove BaseClient
1 parent a512a7b commit 6ced9bd

File tree

4 files changed

+116
-159
lines changed

4 files changed

+116
-159
lines changed

packages/discord.js/src/client/BaseClient.js

Lines changed: 0 additions & 131 deletions
This file was deleted.

packages/discord.js/src/client/Client.js

Lines changed: 107 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
const process = require('node:process');
44
const { clearTimeout, setImmediate, setTimeout } = require('node:timers');
55
const { Collection } = require('@discordjs/collection');
6-
const { makeURLSearchParams } = require('@discordjs/rest');
6+
const { REST, RESTEvents, makeURLSearchParams } = require('@discordjs/rest');
77
const { WebSocketManager, WebSocketShardEvents, WebSocketShardStatus } = require('@discordjs/ws');
8+
const { AsyncEventEmitter } = require('@vladfrangu/async_event_emitter');
89
const { GatewayDispatchEvents, GatewayIntentBits, OAuth2Scopes, Routes } = require('discord-api-types/v10');
910
const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
1011
const { ChannelManager } = require('../managers/ChannelManager.js');
@@ -28,7 +29,7 @@ const { Options } = require('../util/Options.js');
2829
const { PermissionsBitField } = require('../util/PermissionsBitField.js');
2930
const { Status } = require('../util/Status.js');
3031
const { Sweepers } = require('../util/Sweepers.js');
31-
const { BaseClient } = require('./BaseClient.js');
32+
const { flatten } = require('../util/Util.js');
3233
const { ActionsManager } = require('./actions/ActionsManager.js');
3334
const { ClientVoiceManager } = require('./voice/ClientVoiceManager.js');
3435
const { 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

802891
exports.Client = Client;
@@ -846,6 +935,11 @@ exports.Client = Client;
846935
* @see {@link https://discord.js.org/docs/packages/collection/stable/Collection:Class}
847936
*/
848937

938+
/**
939+
* @external REST
940+
* @see {@link https://discord.js.org/docs/packages/rest/stable/REST:Class}
941+
*/
942+
849943
/**
850944
* @external ImageURLOptions
851945
* @see {@link https://discord.js.org/docs/packages/rest/stable/ImageURLOptions:Interface}

packages/discord.js/src/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
const { __exportStar } = require('tslib');
44

55
// "Root" classes (starting points)
6-
exports.BaseClient = require('./client/BaseClient.js').BaseClient;
76
exports.Client = require('./client/Client.js').Client;
87
exports.Shard = require('./sharding/Shard.js').Shard;
98
exports.ShardClientUtil = require('./sharding/ShardClientUtil.js').ShardClientUtil;

packages/discord.js/typings/index.d.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -492,18 +492,6 @@ export abstract class Base {
492492
public valueOf(): string;
493493
}
494494

495-
export class BaseClient<Events extends {}> extends AsyncEventEmitter<Events> implements AsyncDisposable {
496-
public constructor(options?: ClientOptions);
497-
private decrementMaxListeners(): void;
498-
private incrementMaxListeners(): void;
499-
500-
public options: ClientOptions;
501-
public rest: REST;
502-
public destroy(): void;
503-
public toJSON(...props: Record<string, boolean | string>[]): unknown;
504-
public [Symbol.asyncDispose](): Promise<void>;
505-
}
506-
507495
export type GuildCacheMessage<Cached extends CacheType> = CacheTypeReducer<
508496
Cached,
509497
Message<true>,
@@ -913,7 +901,10 @@ export type If<Value extends boolean, TrueResult, FalseResult = null> = Value ex
913901
? FalseResult
914902
: FalseResult | TrueResult;
915903

916-
export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEventTypes> {
904+
export class Client<Ready extends boolean = boolean>
905+
extends AsyncEventEmitter<ClientEventTypes>
906+
implements AsyncDisposable
907+
{
917908
public constructor(options: ClientOptions);
918909
private readonly actions: unknown;
919910
private readonly expectedGuilds: Set<Snowflake>;
@@ -928,6 +919,8 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
928919
private _triggerClientReady(): void;
929920
private _validateOptions(options: ClientOptions): void;
930921
private get _censoredToken(): string | null;
922+
private decrementMaxListeners(): void;
923+
private incrementMaxListeners(): void;
931924
// This a technique used to brand the ready state. Or else we'll get `never` errors on typeguard checks.
932925
private readonly _ready: Ready;
933926

@@ -939,6 +932,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
939932
public get ping(): number | null;
940933
public get readyAt(): If<Ready, Date>;
941934
public readyTimestamp: If<Ready, number>;
935+
public rest: REST;
942936
public sweepers: Sweepers;
943937
public shard: ShardClientUtil | null;
944938
public status: Status;
@@ -968,7 +962,8 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
968962
public generateInvite(options?: InviteGenerationOptions): string;
969963
public login(token?: string): Promise<string>;
970964
public isReady(): this is Client<true>;
971-
public toJSON(): unknown;
965+
public toJSON(...props: Record<string, boolean | string>[]): unknown;
966+
public [Symbol.asyncDispose](): Promise<void>;
972967
}
973968

974969
export interface StickerPackFetchOptions {

0 commit comments

Comments
 (0)