@ovencord/discord.js 14.16.14 → 14.16.15-dev.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 (57) hide show
  1. package/package.json +10 -11
  2. package/src/client/Client.ts +102 -114
  3. package/src/client/actions/Action.ts +27 -23
  4. package/src/client/actions/ChannelCreate.ts +2 -2
  5. package/src/client/actions/ChannelDelete.ts +1 -1
  6. package/src/client/actions/ChannelUpdate.ts +2 -2
  7. package/src/client/actions/GuildChannelsPositionUpdate.ts +1 -1
  8. package/src/client/actions/GuildEmojiCreate.ts +1 -1
  9. package/src/client/actions/GuildEmojiDelete.ts +1 -1
  10. package/src/client/actions/GuildEmojiUpdate.ts +1 -1
  11. package/src/client/actions/GuildEmojisUpdate.ts +1 -1
  12. package/src/client/actions/GuildMemberRemove.ts +1 -1
  13. package/src/client/actions/GuildMemberUpdate.ts +1 -1
  14. package/src/client/actions/GuildRoleCreate.ts +1 -1
  15. package/src/client/actions/GuildRoleDelete.ts +1 -1
  16. package/src/client/actions/GuildRolesPositionUpdate.ts +1 -1
  17. package/src/client/actions/GuildScheduledEventDelete.ts +1 -1
  18. package/src/client/actions/GuildScheduledEventUserAdd.ts +1 -1
  19. package/src/client/actions/GuildScheduledEventUserRemove.ts +1 -1
  20. package/src/client/actions/GuildSoundboardSoundDelete.ts +1 -1
  21. package/src/client/actions/GuildStickerCreate.ts +1 -1
  22. package/src/client/actions/GuildStickerDelete.ts +1 -1
  23. package/src/client/actions/GuildStickerUpdate.ts +1 -1
  24. package/src/client/actions/GuildStickersUpdate.ts +1 -1
  25. package/src/client/actions/GuildUpdate.ts +1 -1
  26. package/src/client/actions/InteractionCreate.ts +1 -1
  27. package/src/client/actions/MessageCreate.ts +2 -2
  28. package/src/client/actions/MessageDelete.ts +2 -2
  29. package/src/client/actions/MessageDeleteBulk.ts +1 -1
  30. package/src/client/actions/MessagePollVoteAdd.ts +2 -2
  31. package/src/client/actions/MessagePollVoteRemove.ts +2 -2
  32. package/src/client/actions/MessageReactionAdd.ts +2 -2
  33. package/src/client/actions/MessageReactionRemove.ts +2 -2
  34. package/src/client/actions/MessageReactionRemoveAll.ts +1 -1
  35. package/src/client/actions/MessageReactionRemoveEmoji.ts +1 -1
  36. package/src/client/actions/MessageUpdate.ts +1 -1
  37. package/src/client/actions/StageInstanceCreate.ts +1 -1
  38. package/src/client/actions/StageInstanceDelete.ts +1 -1
  39. package/src/client/actions/StageInstanceUpdate.ts +1 -1
  40. package/src/client/actions/ThreadCreate.ts +1 -1
  41. package/src/client/actions/ThreadMembersUpdate.ts +1 -1
  42. package/src/client/actions/TypingStart.ts +1 -1
  43. package/src/client/actions/UserUpdate.ts +1 -1
  44. package/src/client/websocket/handlers/RATE_LIMITED.ts +1 -1
  45. package/src/managers/ApplicationEmojiManager.ts +11 -11
  46. package/src/managers/PresenceManager.ts +0 -1
  47. package/src/managers/UserManager.ts +0 -1
  48. package/src/sharding/Shard.ts +38 -37
  49. package/src/sharding/ShardClientUtil.ts +18 -19
  50. package/src/sharding/ShardingManager.ts +7 -7
  51. package/src/structures/AnonymousGuild.ts +0 -1
  52. package/src/structures/BaseGuild.ts +0 -1
  53. package/src/structures/Guild.ts +0 -1
  54. package/src/structures/interfaces/Collector.ts +1 -1
  55. package/src/util/AsyncEventEmitter.ts +150 -0
  56. package/src/util/Partials.ts +1 -1
  57. package/src/util/Status.ts +5 -15
@@ -1,17 +1,17 @@
1
1
  /* eslint-disable no-use-before-define */
2
2
 
3
3
  import path from 'node:path';
4
- import process from 'node:process';
5
- import { setTimeout, clearTimeout } from 'node:timers';
6
- import { setTimeout as sleep } from 'node:timers/promises';
7
4
  import { SHARE_ENV } from 'node:worker_threads';
8
- import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
5
+ import { AsyncEventEmitter } from '../util/AsyncEventEmitter.js';
9
6
  import { DiscordjsError, ErrorCodes } from '../errors/index.js';
10
7
  import { ShardEvents } from '../util/ShardEvents.js';
11
8
  import { makeError, makePlainError } from '../util/Util.js';
12
9
 
13
- let childProcess = null;
14
- let Worker = null;
10
+ import type { ChildProcess } from 'node:child_process';
11
+ import type { Worker as WorkerThread } from 'node:worker_threads';
12
+
13
+ let childProcess: typeof import('node:child_process') | null = null;
14
+ let Worker: typeof WorkerThread | null = null;
15
15
 
16
16
  /**
17
17
  * A self-contained shard created by the {@link ShardingManager}. Each one has a {@link ChildProcess} that contains
@@ -27,11 +27,13 @@ export class Shard extends AsyncEventEmitter {
27
27
  public args: any;
28
28
  public execArgv: any;
29
29
  public env: any;
30
- public worker: any;
30
+ public worker: WorkerThread | null = null;
31
+ public process: ChildProcess | null = null;
32
+ public ready: boolean = false;
31
33
  public _evals: any;
32
34
  public _fetches: any;
33
35
  public _exitListener: any;
34
- constructor(manager, id) {
36
+ constructor(manager: any, id: any) {
35
37
  super();
36
38
 
37
39
  switch (manager.mode) {
@@ -155,14 +157,13 @@ export class Shard extends AsyncEventEmitter {
155
157
 
156
158
  switch (this.manager.mode) {
157
159
  case 'process':
158
- this.process = childProcess
159
- .fork(path.resolve(this.manager.file), this.args, {
160
- env: this.env,
161
- execArgv: this.execArgv,
162
- silent: this.silent,
163
- })
164
- .on('message', this._handleMessage.bind(this))
165
- .on('exit', this._exitListener);
160
+ this.process = childProcess.fork(path.resolve(this.manager.file), this.args, {
161
+ env: this.env,
162
+ execArgv: this.execArgv,
163
+ silent: this.silent,
164
+ });
165
+ (this.process as any).on('message', this._handleMessage.bind(this));
166
+ (this.process as any).on('exit', this._exitListener);
166
167
  break;
167
168
  case 'worker':
168
169
  this.worker = new Worker(path.resolve(this.manager.file), {
@@ -170,9 +171,9 @@ export class Shard extends AsyncEventEmitter {
170
171
  env: SHARE_ENV,
171
172
  execArgv: this.execArgv,
172
173
  argv: this.args,
173
- })
174
- .on('message', this._handleMessage.bind(this))
175
- .on('exit', this._exitListener);
174
+ });
175
+ (this.worker as any).on('message', this._handleMessage.bind(this));
176
+ (this.worker as any).on('exit', this._exitListener);
176
177
  break;
177
178
  default:
178
179
  break;
@@ -232,11 +233,11 @@ export class Shard extends AsyncEventEmitter {
232
233
  */
233
234
  kill() {
234
235
  if (this.process) {
235
- this.process.removeListener('exit', this._exitListener);
236
+ (this.process as any).removeListener('exit', this._exitListener);
236
237
  this.process.kill();
237
238
  } else {
238
- this.worker.removeListener('exit', this._exitListener);
239
- this.worker.terminate();
239
+ (this.worker as any).removeListener('exit', this._exitListener);
240
+ (this.worker as any).terminate();
240
241
  }
241
242
 
242
243
  this._handleExit(false);
@@ -260,7 +261,7 @@ export class Shard extends AsyncEventEmitter {
260
261
  */
261
262
  async respawn({ delay = 500, timeout = 30_000 } = {}) {
262
263
  this.kill();
263
- if (delay > 0) await sleep(delay);
264
+ if (delay > 0) await Bun.sleep(delay);
264
265
  return this.spawn(timeout);
265
266
  }
266
267
 
@@ -270,15 +271,15 @@ export class Shard extends AsyncEventEmitter {
270
271
  * @param {*} message Message to send to the shard
271
272
  * @returns {Promise<Shard>}
272
273
  */
273
- async send(message) {
274
+ async send(message: any): Promise<Shard> {
274
275
  return new Promise((resolve, reject) => {
275
276
  if (this.process) {
276
- this.process.send(message, err => {
277
+ (this.process as any).send(message, (err: Error | null) => {
277
278
  if (err) reject(err);
278
279
  else resolve(this);
279
280
  });
280
281
  } else {
281
- this.worker.postMessage(message);
282
+ (this.worker as any).postMessage(message);
282
283
  resolve(this);
283
284
  }
284
285
  });
@@ -294,7 +295,7 @@ export class Shard extends AsyncEventEmitter {
294
295
  * .then(count => console.log(`${count} guilds in shard ${shard.id}`))
295
296
  * .catch(console.error);
296
297
  */
297
- async fetchClientValue(prop) {
298
+ async fetchClientValue(prop: any): Promise<any> {
298
299
  // Shard is dead (maybe respawning), don't cache anything and error immediately
299
300
  if (!this.process && !this.worker) {
300
301
  throw new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id);
@@ -306,9 +307,9 @@ export class Shard extends AsyncEventEmitter {
306
307
  const promise = new Promise((resolve, reject) => {
307
308
  const child = this.process ?? this.worker;
308
309
 
309
- const listener = message => {
310
+ const listener = (message: any) => {
310
311
  if (message?._fetchProp !== prop) return;
311
- child.removeListener('message', listener);
312
+ (child as any).removeListener('message', listener);
312
313
  this.decrementMaxListeners(child);
313
314
  this._fetches.delete(prop);
314
315
  if (message._error) reject(makeError(message._error));
@@ -316,10 +317,10 @@ export class Shard extends AsyncEventEmitter {
316
317
  };
317
318
 
318
319
  this.incrementMaxListeners(child);
319
- child.on('message', listener);
320
+ (child as any).on('message', listener);
320
321
 
321
322
  this.send({ _fetchProp: prop }).catch(error => {
322
- child.removeListener('message', listener);
323
+ (child as any).removeListener('message', listener);
323
324
  this.decrementMaxListeners(child);
324
325
  this._fetches.delete(prop);
325
326
  reject(error);
@@ -337,7 +338,7 @@ export class Shard extends AsyncEventEmitter {
337
338
  * @param {*} [context] The context for the eval
338
339
  * @returns {Promise<*>} Result of the script execution
339
340
  */
340
- async eval(script, context) {
341
+ async eval(script: any, context?: any): Promise<any> {
341
342
  // Stringify the script if it's a Function
342
343
  const _eval = typeof script === 'function' ? `(${script})(this, ${JSON.stringify(context)})` : script;
343
344
 
@@ -352,9 +353,9 @@ export class Shard extends AsyncEventEmitter {
352
353
  const promise = new Promise((resolve, reject) => {
353
354
  const child = this.process ?? this.worker;
354
355
 
355
- const listener = message => {
356
+ const listener = (message: any) => {
356
357
  if (message?._eval !== _eval) return;
357
- child.removeListener('message', listener);
358
+ (child as any).removeListener('message', listener);
358
359
  this.decrementMaxListeners(child);
359
360
  this._evals.delete(_eval);
360
361
  if (message._error) reject(makeError(message._error));
@@ -362,10 +363,10 @@ export class Shard extends AsyncEventEmitter {
362
363
  };
363
364
 
364
365
  this.incrementMaxListeners(child);
365
- child.on('message', listener);
366
+ (child as any).on('message', listener);
366
367
 
367
368
  this.send({ _eval }).catch(error => {
368
- child.removeListener('message', listener);
369
+ (child as any).removeListener('message', listener);
369
370
  this.decrementMaxListeners(child);
370
371
  this._evals.delete(_eval);
371
372
  reject(error);
@@ -382,7 +383,7 @@ export class Shard extends AsyncEventEmitter {
382
383
  * @param {*} message Message received
383
384
  * @private
384
385
  */
385
- _handleMessage(message) {
386
+ _handleMessage(message: any): void {
386
387
  if (message) {
387
388
  // Shard is ready
388
389
  if (message._ready) {
@@ -1,6 +1,4 @@
1
1
  /* eslint-disable */
2
-
3
- import process from 'node:process';
4
2
  import { calculateShardId } from '@ovencord/util';
5
3
  import { WebSocketShardEvents } from '@ovencord/ws';
6
4
  import { DiscordjsError, DiscordjsTypeError, ErrorCodes } from '../errors/index.js';
@@ -15,8 +13,9 @@ export class ShardClientUtil {
15
13
  public client: any;
16
14
  public mode: any;
17
15
  public parentPort: any;
18
- public _singleton: any;
19
- constructor(client, mode) {
16
+ private static _singleton: ShardClientUtil | null = null;
17
+
18
+ constructor(client: any, mode: any) {
20
19
  /**
21
20
  * Client for the shard
22
21
  *
@@ -76,18 +75,18 @@ export class ShardClientUtil {
76
75
  * @returns {Promise<void>}
77
76
  * @emits Shard#message
78
77
  */
79
- async send(message) {
78
+ async send(message: any): Promise<void> {
80
79
  return new Promise((resolve, reject) => {
81
80
  switch (this.mode) {
82
81
  case 'process':
83
- process.send(message, err => {
82
+ process.send!(message, (err: Error | null) => {
84
83
  if (err) reject(err);
85
- else resolve();
84
+ else resolve(undefined);
86
85
  });
87
86
  break;
88
87
  case 'worker':
89
88
  this.parentPort.postMessage(message);
90
- resolve();
89
+ resolve(undefined);
91
90
  break;
92
91
  default:
93
92
  break;
@@ -107,11 +106,11 @@ export class ShardClientUtil {
107
106
  * .catch(console.error);
108
107
  * @see {@link ShardingManager#fetchClientValues}
109
108
  */
110
- async fetchClientValues(prop, shard) {
109
+ async fetchClientValues(prop: any, shard: any): Promise<any> {
111
110
  return new Promise((resolve, reject) => {
112
111
  const parent = this.parentPort ?? process;
113
112
 
114
- const listener = message => {
113
+ const listener = (message: any) => {
115
114
  if (message?._sFetchProp !== prop || message._sFetchPropShard !== shard) return;
116
115
  parent.removeListener('message', listener);
117
116
  this.decrementMaxListeners(parent);
@@ -142,7 +141,7 @@ export class ShardClientUtil {
142
141
  * .catch(console.error);
143
142
  * @see {@link ShardingManager#broadcastEval}
144
143
  */
145
- async broadcastEval(script, options = {}) {
144
+ async broadcastEval(script: any, options: any = {}): Promise<any> {
146
145
  return new Promise((resolve, reject) => {
147
146
  const parent = this.parentPort ?? process;
148
147
  if (typeof script !== 'function') {
@@ -152,7 +151,7 @@ export class ShardClientUtil {
152
151
 
153
152
  const evalScript = `(${script})(this, ${JSON.stringify(options.context)})`;
154
153
 
155
- const listener = message => {
154
+ const listener = (message: any) => {
156
155
  if (message?._sEval !== evalScript || message._sEvalShard !== options.shard) return;
157
156
  parent.removeListener('message', listener);
158
157
  this.decrementMaxListeners(parent);
@@ -177,7 +176,7 @@ export class ShardClientUtil {
177
176
  * @returns {Promise<void>} Resolves upon the message being sent
178
177
  * @see {@link ShardingManager#respawnAll}
179
178
  */
180
- async respawnAll({ shardDelay = 5_000, respawnDelay = 500, timeout = 30_000 } = {}) {
179
+ async respawnAll({ shardDelay = 5_000, respawnDelay = 500, timeout = 30_000 } = {}): Promise<void> {
181
180
  return this.send({ _sRespawnAll: { shardDelay, respawnDelay, timeout } });
182
181
  }
183
182
 
@@ -187,7 +186,7 @@ export class ShardClientUtil {
187
186
  * @param {*} message Message received
188
187
  * @private
189
188
  */
190
- async _handleMessage(message) {
189
+ async _handleMessage(message: any): Promise<void> {
191
190
  if (!message) return;
192
191
  if (message._fetchProp) {
193
192
  try {
@@ -214,7 +213,7 @@ export class ShardClientUtil {
214
213
  * @param {*} message Message to send
215
214
  * @private
216
215
  */
217
- _respond(type, message) {
216
+ _respond(type: string, message: any): void {
218
217
  this.send(message).catch(error_ => {
219
218
  const error = new Error(`Error when sending ${type} response to master process: ${error_.message}`);
220
219
  error.stack = error_.stack;
@@ -239,7 +238,7 @@ export class ShardClientUtil {
239
238
  * @param {ShardingManagerMode} mode Mode the shard was spawned with
240
239
  * @returns {ShardClientUtil}
241
240
  */
242
- static singleton(client, mode) {
241
+ static singleton(client: any, mode: any): ShardClientUtil {
243
242
  if (this._singleton) {
244
243
  client.emit(
245
244
  Events.Warn,
@@ -259,7 +258,7 @@ export class ShardClientUtil {
259
258
  * @param {number} shardCount Number of shards
260
259
  * @returns {number}
261
260
  */
262
- static shardIdForGuildId(guildId, shardCount) {
261
+ static shardIdForGuildId(guildId: string, shardCount: number): number {
263
262
  const shard = calculateShardId(guildId, shardCount);
264
263
  if (shard < 0) throw new DiscordjsError(ErrorCodes.ShardingShardMiscalculation, shard, guildId, shardCount);
265
264
  return shard;
@@ -271,7 +270,7 @@ export class ShardClientUtil {
271
270
  * @param {Worker|ChildProcess} emitter The emitter that emits the events.
272
271
  * @private
273
272
  */
274
- incrementMaxListeners(emitter) {
273
+ incrementMaxListeners(emitter: any): void {
275
274
  const maxListeners = emitter.getMaxListeners();
276
275
  if (maxListeners !== 0) {
277
276
  emitter.setMaxListeners(maxListeners + 1);
@@ -284,7 +283,7 @@ export class ShardClientUtil {
284
283
  * @param {Worker|ChildProcess} emitter The emitter that emits the events.
285
284
  * @private
286
285
  */
287
- decrementMaxListeners(emitter) {
286
+ decrementMaxListeners(emitter: any): void {
288
287
  const maxListeners = emitter.getMaxListeners();
289
288
  if (maxListeners !== 0) {
290
289
  emitter.setMaxListeners(maxListeners - 1);
@@ -1,10 +1,8 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import process from 'node:process';
4
- import { setTimeout as sleep } from 'node:timers/promises';
5
3
  import { Collection } from '@ovencord/collection';
6
4
  import { range } from '@ovencord/util';
7
- import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
5
+ import { AsyncEventEmitter } from '../util/AsyncEventEmitter.js';
8
6
  import { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } from '../errors/index.js';
9
7
  import { fetchRecommendedShardCount } from '../util/Util.js';
10
8
  import { Shard } from './Shard.js';
@@ -24,10 +22,12 @@ export class ShardingManager extends AsyncEventEmitter {
24
22
  public shardList: any;
25
23
  public totalShards: any;
26
24
  public mode: any;
25
+ public respawn: boolean;
27
26
  public silent: any;
28
27
  public shardArgs: any;
29
28
  public execArgv: any;
30
29
  public token: any;
30
+ public shards: any;
31
31
  /**
32
32
  * The mode to spawn shards with for a {@link ShardingManager}. Can be either one of:
33
33
  * - 'process' to use child processes
@@ -55,7 +55,7 @@ export class ShardingManager extends AsyncEventEmitter {
55
55
  * @param {string} file Path to your shard script file
56
56
  * @param {ShardingManagerOptions} [options] Options for the sharding manager
57
57
  */
58
- constructor(file, options) {
58
+ constructor(file: any, options?: any) {
59
59
  super();
60
60
  const _options = {
61
61
  totalShards: 'auto',
@@ -261,7 +261,7 @@ export class ShardingManager extends AsyncEventEmitter {
261
261
  const promises = [];
262
262
  const shard = this.createShard(shardId);
263
263
  promises.push(shard.spawn(timeout));
264
- if (delay > 0 && this.shards.size !== this.shardList.length) promises.push(sleep(delay));
264
+ if (delay > 0 && this.shards.size !== this.shardList.length) promises.push(Bun.sleep(delay));
265
265
  await Promise.all(promises);
266
266
  }
267
267
 
@@ -295,7 +295,7 @@ export class ShardingManager extends AsyncEventEmitter {
295
295
  * @param {BroadcastEvalOptions} [options={}] The options for the broadcast
296
296
  * @returns {Promise<*|Array<*>>} Results of the script execution
297
297
  */
298
- async broadcastEval(script, options = {}) {
298
+ async broadcastEval(script: any, options: any = {}): Promise<any> {
299
299
  if (typeof script !== 'function') {
300
300
  throw new DiscordjsTypeError(ErrorCodes.ShardingInvalidEvalBroadcast);
301
301
  }
@@ -365,7 +365,7 @@ export class ShardingManager extends AsyncEventEmitter {
365
365
  let shardCounter = 0;
366
366
  for (const shard of this.shards.values()) {
367
367
  const promises = [shard.respawn({ delay: respawnDelay, timeout })];
368
- if (++shardCounter < this.shards.size && shardDelay > 0) promises.push(sleep(shardDelay));
368
+ if (++shardCounter < this.shards.size && shardDelay > 0) promises.push(Bun.sleep(shardDelay));
369
369
  await Promise.all(promises);
370
370
  }
371
371
 
@@ -7,7 +7,6 @@ import { BaseGuild } from './BaseGuild.js';
7
7
  * @abstract
8
8
  */
9
9
  export class AnonymousGuild extends BaseGuild {
10
- public client: any;
11
10
  public features: any;
12
11
  public description: any;
13
12
  public verificationLevel: any;
@@ -10,7 +10,6 @@ import { Base } from './Base.js';
10
10
  * @abstract
11
11
  */
12
12
  export class BaseGuild extends Base {
13
- public client: any;
14
13
  public id: any;
15
14
  public name: any;
16
15
  public features: any;
@@ -38,7 +38,6 @@ import { WelcomeScreen } from './WelcomeScreen.js';
38
38
  * @extends {AnonymousGuild}
39
39
  */
40
40
  export class Guild extends AnonymousGuild {
41
- public client: any;
42
41
  public commands: any;
43
42
  public members: any;
44
43
  public channels: any;
@@ -1,6 +1,6 @@
1
1
  import { setTimeout, clearTimeout } from 'node:timers';
2
2
  import { Collection } from '@ovencord/collection';
3
- import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
3
+ import { AsyncEventEmitter } from '../../util/AsyncEventEmitter.js';
4
4
  import { DiscordjsTypeError, ErrorCodes } from '../../errors/index.js';
5
5
  import { flatten } from '../../util/Util.js';
6
6
 
@@ -0,0 +1,150 @@
1
+ export type EventMap = Record<string | symbol, any[]>;
2
+
3
+ export class AsyncEventEmitter<Events extends EventMap = EventMap> {
4
+ private _listeners = new Map<keyof Events | string | symbol, Set<Function>>();
5
+ private _maxListeners = 10;
6
+
7
+ public on<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void | Promise<void>): this;
8
+ public on<K extends string | symbol>(event: K, listener: (...args: any[]) => void | Promise<void>): this;
9
+ public on(event: string | symbol, listener: Function): this {
10
+ if (!this._listeners.has(event)) {
11
+ this._listeners.set(event, new Set());
12
+ }
13
+
14
+ const listeners = this._listeners.get(event)!;
15
+ listeners.add(listener);
16
+
17
+ if (listeners.size > this._maxListeners) {
18
+ console.warn(
19
+ `Possible AsyncEventEmitter memory leak detected. ` +
20
+ `${listeners.size} ${String(event)} listeners added. ` +
21
+ `Use emitter.setMaxListeners() to increase limit`
22
+ );
23
+ }
24
+
25
+ return this;
26
+ }
27
+
28
+ public once<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void | Promise<void>): this;
29
+ public once<K extends string | symbol>(event: K, listener: (...args: any[]) => void | Promise<void>): this;
30
+ public once(event: string | symbol, listener: Function): this {
31
+ const wrapper = async (...args: any[]) => {
32
+ this.off(event, wrapper);
33
+ await listener(...args);
34
+ };
35
+
36
+ Object.defineProperty(wrapper, '_originalListener', {
37
+ value: listener,
38
+ writable: false,
39
+ enumerable: false,
40
+ });
41
+
42
+ return this.on(event, wrapper);
43
+ }
44
+
45
+ public off<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void | Promise<void>): this;
46
+ public off<K extends string | symbol>(event: K, listener: (...args: any[]) => void | Promise<void>): this;
47
+ public off(event: string | symbol, listener: Function): this {
48
+ const listeners = this._listeners.get(event);
49
+ if (!listeners) return this;
50
+
51
+ for (const fn of listeners) {
52
+ if (fn === listener || (fn as any)._originalListener === listener) {
53
+ listeners.delete(fn);
54
+ }
55
+ }
56
+
57
+ if (listeners.size === 0) {
58
+ this._listeners.delete(event);
59
+ }
60
+
61
+ return this;
62
+ }
63
+
64
+ public async emit<K extends keyof Events>(event: K, ...args: Events[K]): Promise<boolean>;
65
+ public async emit<K extends string | symbol>(event: K, ...args: any[]): Promise<boolean>;
66
+ public async emit(event: string | symbol, ...args: any[]): Promise<boolean> {
67
+ const listeners = this._listeners.get(event);
68
+ if (!listeners?.size) return false;
69
+
70
+ // We copy the listeners to ensure that if a listener is removed during execution,
71
+ // the loop still iterates over the snapshot of listeners at the time of emission.
72
+ // However, for strict sequential execution where one might remove another,
73
+ // iterating over the live Set or a copy is a design choice.
74
+ // Discord.js usually handles this by copying or iterating safe.
75
+ // The user's snippet iterates directly over the listeners collection from .get().
76
+ // If we use 'for of' on a Set, it handles deletions gracefully (the deleted item won't be visited if not reached yet),
77
+ // but additions might be visited.
78
+ // For now, adhering to user's "for (const listener of listeners)" pattern.
79
+
80
+ // NOTE: Iterating over the Set directly allows listeners to remove themselves safely.
81
+ for (const listener of listeners) {
82
+ try {
83
+ await listener(...args);
84
+ } catch (error) {
85
+ if (event === 'error') {
86
+ console.error('Error in error handler:', error);
87
+ } else if (this.listenerCount('error') > 0) {
88
+ await this.emit('error', error);
89
+ } else {
90
+ console.error(`Unhandled error in ${String(event)} event:`, error);
91
+ throw error;
92
+ }
93
+ }
94
+ }
95
+
96
+ return true;
97
+ }
98
+
99
+ public removeAllListeners(event?: keyof Events | string | symbol): this {
100
+ if (event !== undefined) {
101
+ this._listeners.delete(event);
102
+ } else {
103
+ this._listeners.clear();
104
+ }
105
+ return this;
106
+ }
107
+
108
+ public setMaxListeners(n: number): this {
109
+ this._maxListeners = n;
110
+ return this;
111
+ }
112
+
113
+ public getMaxListeners(): number {
114
+ return this._maxListeners;
115
+ }
116
+
117
+ public listenerCount(event: keyof Events | string | symbol): number {
118
+ return this._listeners.get(event)?.size ?? 0;
119
+ }
120
+
121
+ public eventNames(): Array<keyof Events | string | symbol> {
122
+ return Array.from(this._listeners.keys());
123
+ }
124
+
125
+ public rawListeners(event: keyof Events | string | symbol): Function[] {
126
+ return Array.from(this._listeners.get(event) ?? []);
127
+ }
128
+
129
+ public waitFor<K extends keyof Events>(event: K, timeout?: number): Promise<Events[K]>;
130
+ public waitFor<K extends string | symbol>(event: K, timeout?: number): Promise<any[]>;
131
+ public waitFor(event: string | symbol, timeout?: number): Promise<any[]> {
132
+ return new Promise((resolve, reject) => {
133
+ let timeoutId: Timer | undefined;
134
+
135
+ const listener = (...args: any[]) => {
136
+ if (timeoutId) clearTimeout(timeoutId);
137
+ resolve(args);
138
+ };
139
+
140
+ this.once(event, listener);
141
+
142
+ if (timeout) {
143
+ timeoutId = setTimeout(() => {
144
+ this.off(event, listener);
145
+ reject(new Error(`Timeout waiting for ${String(event)}`));
146
+ }, timeout);
147
+ }
148
+ });
149
+ }
150
+ }
@@ -47,4 +47,4 @@ export const Partials = createEnum([
47
47
  'Poll',
48
48
  'PollAnswer',
49
49
  'SoundboardSound',
50
- ]);
50
+ ]) as any;
@@ -1,16 +1,6 @@
1
1
 
2
- import { createEnum } from './Enums.js';
3
-
4
- /**
5
- * @typedef {Object} Status
6
- * @property {number} Ready ready
7
- * @property {number} Idle idle
8
- * @property {number} WaitingForGuilds waiting for guilds
9
- */
10
-
11
- // JSDoc for IntelliSense purposes
12
- /**
13
- * @type {Status}
14
- * @ignore
15
- */
16
- export const Status = createEnum(['Ready', 'Idle', 'WaitingForGuilds']);
2
+ export enum Status {
3
+ Ready,
4
+ Idle,
5
+ WaitingForGuilds,
6
+ }