feat: add support for using keyword on discord.js Client and WebSocketManager (#10063)

* feat: add support for `using` keyword on client

* fix: use async dispose

* feat: add support for web socket manager disposing

* fix: use interface for client

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Suneet Tipirneni 2024-02-13 12:48:56 -05:00 committed by GitHub
parent f48cb2a357
commit 543d61737e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 34 additions and 3 deletions

View file

@ -106,6 +106,10 @@ class BaseClient extends EventEmitter {
toJSON(...props) {
return flatten(this, ...props);
}
async [Symbol.asyncDispose]() {
await this.destroy();
}
}
module.exports = BaseClient;

View file

@ -1,7 +1,10 @@
'use strict';
const { polyfillDispose } = require('@discordjs/util');
const { __exportStar } = require('tslib');
polyfillDispose();
// "Root" classes (starting points)
exports.BaseClient = require('./client/BaseClient');
exports.Client = require('./client/Client');

View file

@ -517,7 +517,7 @@ export abstract class Base {
public valueOf(): string;
}
export class BaseClient extends EventEmitter {
export class BaseClient extends EventEmitter implements AsyncDisposable {
public constructor(options?: ClientOptions | WebhookClientOptions);
private decrementMaxListeners(): void;
private incrementMaxListeners(): void;
@ -526,6 +526,7 @@ export class BaseClient extends EventEmitter {
public rest: REST;
public destroy(): void;
public toJSON(...props: Record<string, boolean | string>[]): unknown;
public [Symbol.asyncDispose](): Promise<void>;
}
export type GuildCacheMessage<Cached extends CacheType> = CacheTypeReducer<

View file

@ -3,3 +3,4 @@ export * from './range.js';
export * from './calculateShardId.js';
export * from './runtime.js';
export * from './userAgentAppendix.js';
export * from './polyfillDispose.js';

View file

@ -0,0 +1,14 @@
/**
* Polyfill for `Symbol.dispose` and `Symbol.asyncDispose` which is used as a part of
* {@link https://github.com/tc39/proposal-explicit-resource-management}. Node versions below 18.x
* don't have these symbols by default, so we need to polyfill them.
*/
export function polyfillDispose() {
// Polyfill for `Symbol.dispose` and `Symbol.asyncDispose` if not available.
// Taken from https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#using-declarations-and-explicit-resource-management
// @ts-expect-error This is a polyfill, so it's fine to write
Symbol.dispose ??= Symbol('Symbol.dispose');
// @ts-expect-error Same as above
Symbol.asyncDispose ??= Symbol('Symbol.asyncDispose');
}

View file

@ -1,5 +1,6 @@
import type { REST } from '@discordjs/rest';
import { range, type Awaitable } from '@discordjs/util';
import { polyfillDispose } from '@discordjs/util';
import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
import {
Routes,
@ -17,6 +18,9 @@ import type { IIdentifyThrottler } from '../throttling/IIdentifyThrottler.js';
import { DefaultWebSocketManagerOptions, type CompressionMethod, type Encoding } from '../utils/constants.js';
import type { WebSocketShardDestroyOptions, WebSocketShardEvents } from './WebSocketShard.js';
// We put this here because in index.ts WebSocketManager seems to be outputted before polyfillDispose() is called from tsup.
polyfillDispose();
/**
* Represents a range of shard ids
*/
@ -199,7 +203,7 @@ export interface ManagerShardEventsMap {
];
}
export class WebSocketManager extends AsyncEventEmitter<ManagerShardEventsMap> {
export class WebSocketManager extends AsyncEventEmitter<ManagerShardEventsMap> implements AsyncDisposable {
/**
* The options being used by this manager
*/
@ -334,4 +338,8 @@ export class WebSocketManager extends AsyncEventEmitter<ManagerShardEventsMap> {
public fetchStatus() {
return this.strategy.fetchStatus();
}
public async [Symbol.asyncDispose]() {
await this.destroy();
}
}

View file

@ -42,7 +42,7 @@
// Language and Environment
"experimentalDecorators": true,
"lib": ["ESNext"],
"lib": ["ESNext", "esnext.disposable"],
"target": "ESNext",
"useDefineForClassFields": true
},