lavacord 2.2.0 → 3.0.0

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 (59) hide show
  1. package/LICENSE +24 -201
  2. package/README.md +473 -69
  3. package/dist/cjs/index.cjs +44 -0
  4. package/dist/cjs/index.cjs.map +1 -0
  5. package/dist/cjs/index.d.cts +1211 -0
  6. package/dist/cjs/lib/LavalinkNode.cjs +423 -0
  7. package/dist/cjs/lib/LavalinkNode.cjs.map +1 -0
  8. package/dist/cjs/lib/Manager.cjs +405 -0
  9. package/dist/cjs/lib/Manager.cjs.map +1 -0
  10. package/dist/cjs/lib/Player.cjs +220 -0
  11. package/dist/cjs/lib/Player.cjs.map +1 -0
  12. package/dist/cjs/lib/Rest.cjs +192 -0
  13. package/dist/cjs/lib/Rest.cjs.map +1 -0
  14. package/dist/cjs/lib/Types.cjs +4 -0
  15. package/dist/cjs/lib/Types.cjs.map +1 -0
  16. package/dist/cjs/wrappers/cloudstorm.cjs +54 -0
  17. package/dist/cjs/wrappers/cloudstorm.cjs.map +1 -0
  18. package/dist/cjs/wrappers/detritus.cjs +57 -0
  19. package/dist/cjs/wrappers/detritus.cjs.map +1 -0
  20. package/dist/cjs/wrappers/discord.js.cjs +37 -0
  21. package/dist/cjs/wrappers/discord.js.cjs.map +1 -0
  22. package/dist/cjs/wrappers/eris.cjs +51 -0
  23. package/dist/cjs/wrappers/eris.cjs.map +1 -0
  24. package/dist/cjs/wrappers/oceanic.cjs +52 -0
  25. package/dist/cjs/wrappers/oceanic.cjs.map +1 -0
  26. package/dist/esm/chunk-PAWJFY3S.mjs +6 -0
  27. package/dist/esm/chunk-PAWJFY3S.mjs.map +1 -0
  28. package/dist/esm/index.d.mts +1211 -0
  29. package/dist/esm/index.mjs +12 -0
  30. package/dist/esm/index.mjs.map +1 -0
  31. package/dist/esm/lib/LavalinkNode.mjs +420 -0
  32. package/dist/esm/lib/LavalinkNode.mjs.map +1 -0
  33. package/dist/esm/lib/Manager.mjs +402 -0
  34. package/dist/esm/lib/Manager.mjs.map +1 -0
  35. package/dist/esm/lib/Player.mjs +217 -0
  36. package/dist/esm/lib/Player.mjs.map +1 -0
  37. package/dist/esm/lib/Rest.mjs +188 -0
  38. package/dist/esm/lib/Rest.mjs.map +1 -0
  39. package/dist/esm/lib/Types.mjs +3 -0
  40. package/dist/esm/lib/Types.mjs.map +1 -0
  41. package/dist/esm/wrappers/cloudstorm.mjs +45 -0
  42. package/dist/esm/wrappers/cloudstorm.mjs.map +1 -0
  43. package/dist/esm/wrappers/detritus.mjs +48 -0
  44. package/dist/esm/wrappers/detritus.mjs.map +1 -0
  45. package/dist/esm/wrappers/discord.js.mjs +28 -0
  46. package/dist/esm/wrappers/discord.js.mjs.map +1 -0
  47. package/dist/esm/wrappers/eris.mjs +42 -0
  48. package/dist/esm/wrappers/eris.mjs.map +1 -0
  49. package/dist/esm/wrappers/oceanic.mjs +43 -0
  50. package/dist/esm/wrappers/oceanic.mjs.map +1 -0
  51. package/dist/lib/LavalinkNode.d.ts +3 -3
  52. package/dist/lib/LavalinkNode.js +16 -26
  53. package/dist/lib/LavalinkNode.js.map +1 -1
  54. package/dist/lib/Manager.d.ts +2 -2
  55. package/dist/lib/Manager.js.map +1 -1
  56. package/dist/lib/Rest.js +5 -7
  57. package/dist/lib/Rest.js.map +1 -1
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/package.json +109 -64
@@ -0,0 +1,1211 @@
1
+ import { BetterWs } from 'cloudstorm';
2
+ import * as discord_api_types_v10 from 'discord-api-types/v10';
3
+ import { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdate, GatewayVoiceStateUpdateDispatchData } from 'discord-api-types/v10';
4
+ import { EventEmitter } from 'events';
5
+ import { PlayerState as PlayerState$1, Track, VoiceState, Filters as Filters$1, UpdatePlayerData, Player as Player$1, UpdatePlayerResult, Equalizer, DestroyPlayerResult, Stats, TrackLoadingResult, DecodeTrackResult, DecodeTracksResult, GetLavalinkVersionResult, GetLavalinkInfoResult, GetLavalinkStatsResult, UpdateSessionResult, ErrorResponse } from 'lavalink-types';
6
+ import { WebsocketMessage, PlayerState, TrackStartEvent, TrackEndEvent, TrackExceptionEvent, TrackStuckEvent, WebSocketClosedEvent, Filters } from 'lavalink-types/v4';
7
+ import { URLSearchParams } from 'url';
8
+
9
+ /**
10
+ * Represents the voice state required for a player update, typically used when switching nodes or resuming.
11
+ *
12
+ * @remarks
13
+ * This interface contains the session ID and event data needed to establish a voice connection.
14
+ *
15
+ * @public
16
+ */
17
+ interface PlayerUpdateVoiceState {
18
+ /**
19
+ * The session ID of the voice connection.
20
+ *
21
+ * @readonly
22
+ */
23
+ sessionId: string;
24
+ /**
25
+ * The voice server update event data from Discord.
26
+ *
27
+ * @readonly
28
+ */
29
+ event: GatewayVoiceServerUpdateDispatchData;
30
+ }
31
+ /**
32
+ * Defines the options for configuring the Lavacord Manager.
33
+ *
34
+ * @remarks
35
+ * These options control how the Manager interacts with Discord and Lavalink.
36
+ *
37
+ * @public
38
+ */
39
+ interface ManagerOptions {
40
+ /**
41
+ * The user ID of the bot.
42
+ *
43
+ * @remarks
44
+ * It's recommended to set this when the bot client is ready.
45
+ */
46
+ userId?: string;
47
+ /**
48
+ * The Player class to be used by the manager for creating new player instances.
49
+ *
50
+ * @remarks
51
+ * Allows for extending the base Player functionality with custom implementations.
52
+ */
53
+ player?: typeof Player;
54
+ /**
55
+ * The function used to send gateway voice packets to Discord.
56
+ *
57
+ * @remarks
58
+ * This needs to be implemented by the end-user based on their Discord library.
59
+ *
60
+ * @param packet - The Discord packet to send.
61
+ * @returns A Promise or value representing the send operation result.
62
+ */
63
+ send?: (packet: GatewayVoiceStateUpdate) => unknown;
64
+ }
65
+ /**
66
+ * Defines the data required to join a voice channel.
67
+ *
68
+ * @remarks
69
+ * Contains the essential identifiers for connecting to a specific voice channel.
70
+ *
71
+ * @public
72
+ */
73
+ interface JoinData {
74
+ /**
75
+ * The ID of the guild where the voice channel is located.
76
+ *
77
+ * @readonly
78
+ */
79
+ guild: string;
80
+ /**
81
+ * The ID of the voice channel to join.
82
+ *
83
+ * @readonly
84
+ */
85
+ channel: string;
86
+ /**
87
+ * The ID of the LavalinkNode to use for this connection.
88
+ *
89
+ * @remarks
90
+ * This determines which Lavalink server will handle the audio for this connection.
91
+ *
92
+ * @readonly
93
+ */
94
+ node: string;
95
+ }
96
+ /**
97
+ * Defines the options for joining a voice channel.
98
+ *
99
+ * @remarks
100
+ * Controls the initial state of the bot when connecting to a voice channel.
101
+ *
102
+ * @public
103
+ */
104
+ interface JoinOptions {
105
+ /**
106
+ * Whether the bot should be self-muted upon joining the voice channel.
107
+ *
108
+ * @defaultValue false
109
+ */
110
+ selfmute?: boolean;
111
+ /**
112
+ * Whether the bot should be self-deafened upon joining the voice channel.
113
+ *
114
+ * @defaultValue false
115
+ */
116
+ selfdeaf?: boolean;
117
+ }
118
+ /**
119
+ * Defines the options for configuring a LavalinkNode.
120
+ *
121
+ * @remarks
122
+ * These options specify how to connect to a Lavalink server and how the node should behave.
123
+ *
124
+ * @public
125
+ */
126
+ interface LavalinkNodeOptions {
127
+ /**
128
+ * A unique identifier for this LavalinkNode, used for organization.
129
+ *
130
+ * @remarks
131
+ * This ID is used internally by Lavacord to reference and manage nodes.
132
+ *
133
+ * @readonly
134
+ */
135
+ id: string;
136
+ /**
137
+ * The hostname or IP address of the Lavalink server.
138
+ *
139
+ * @defaultValue "localhost"
140
+ */
141
+ host: string;
142
+ /**
143
+ * The port number of the Lavalink server.
144
+ *
145
+ * @defaultValue 2333
146
+ */
147
+ port?: number | string;
148
+ /**
149
+ * The password for authenticating with the Lavalink server.
150
+ *
151
+ * @defaultValue "youshallnotpass"
152
+ */
153
+ password?: string;
154
+ /**
155
+ * The interval (in milliseconds) at which the node will attempt to reconnect if the connection is lost.
156
+ *
157
+ * @defaultValue 10000 (10 seconds)
158
+ */
159
+ reconnectInterval?: number;
160
+ /**
161
+ * A previous session ID to attempt to resume a connection with the Lavalink server.
162
+ *
163
+ * @remarks
164
+ * This is used when attempting to resume a previous session after reconnection.
165
+ */
166
+ sessionId?: string;
167
+ /**
168
+ * Whether the node should attempt to resume the session if a `sessionId` is present when the WebSocket connection opens or the node becomes ready.
169
+ *
170
+ * @defaultValue false
171
+ */
172
+ resuming?: boolean;
173
+ /**
174
+ * The timeout (in seconds) for resuming a session.
175
+ *
176
+ * @defaultValue 120 (2 minutes)
177
+ */
178
+ resumeTimeout?: number;
179
+ /**
180
+ * Whether to use secure connections (HTTPS/WSS) instead of HTTP/WS.
181
+ *
182
+ * @remarks
183
+ * When true, WebSocket connections will use WSS and REST requests will use HTTPS.
184
+ * This is required when connecting to Lavalink servers behind SSL/TLS.
185
+ *
186
+ * @defaultValue false
187
+ */
188
+ secure?: boolean;
189
+ /**
190
+ * Arbitrary state data that can be attached to the node for user-specific purposes.
191
+ *
192
+ * @remarks
193
+ * This data is not sent to Lavalink and is only used internally.
194
+ */
195
+ state?: unknown;
196
+ }
197
+ /**
198
+ * Type definition for Manager events.
199
+ */
200
+ interface ManagerEvents {
201
+ /**
202
+ * Emitted when a node becomes ready.
203
+ * @event
204
+ */
205
+ ready: [LavalinkNode];
206
+ /**
207
+ * Emitted for all raw messages from Lavalink.
208
+ * @event
209
+ */
210
+ raw: [WebsocketMessage, LavalinkNode];
211
+ /**
212
+ * Emitted when a node encounters an error.
213
+ * @event
214
+ */
215
+ error: [unknown, LavalinkNode];
216
+ /**
217
+ * Emitted when a node disconnects.
218
+ * @event
219
+ */
220
+ disconnect: [number, string, LavalinkNode];
221
+ /**
222
+ * Emitted when a node is attempting to reconnect.
223
+ * @event
224
+ */
225
+ reconnecting: [LavalinkNode];
226
+ /**
227
+ * Represents Lavalink's playerUpdate event.
228
+ * emits every x time as defined by the lavalink server.
229
+ * @see {@link https://lavalink.dev/api/websocket.html#player-update-op}
230
+ * @event
231
+ */
232
+ playerState: [Player, PlayerState];
233
+ /**
234
+ * Emitted when a track starts playing.
235
+ * @see {@link https://lavalink.dev/api/websocket.html#trackstartevent}
236
+ * @event
237
+ */
238
+ playerTrackStart: [Player, TrackStartEvent];
239
+ /**
240
+ * Emitted when a track ends.
241
+ * @see {@link https://lavalink.dev/api/websocket.html#trackendevent}
242
+ * @event
243
+ */
244
+ playerTrackEnd: [Player, TrackEndEvent];
245
+ /**
246
+ * Emitted when a track encounters an exception.
247
+ * @see {@link https://lavalink.dev/api/websocket.html#trackexceptionevent}
248
+ * @event
249
+ */
250
+ playerTrackException: [Player, TrackExceptionEvent];
251
+ /**
252
+ * Emitted when a track gets stuck.
253
+ * @see {@link https://lavalink.dev/api/websocket.html#trackstuckevent}
254
+ * @event
255
+ */
256
+ playerTrackStuck: [Player, TrackStuckEvent];
257
+ /**
258
+ * Emitted when the voice WebSocket is closed.
259
+ * @see {@link https://lavalink.dev/api/websocket.html#websocketclosedevent}
260
+ * @event
261
+ */
262
+ playerWebSocketClosed: [Player, WebSocketClosedEvent];
263
+ /**
264
+ * Emitted for warnings.
265
+ * @event
266
+ */
267
+ warn: [string];
268
+ /**
269
+ * Emitted when a player is paused or resumed.
270
+ * @event
271
+ */
272
+ playerPause: [Player, boolean];
273
+ /**
274
+ * Emitted when a player's volume changes.
275
+ * @event
276
+ */
277
+ playerVolume: [Player, number];
278
+ /**
279
+ * Emitted when a player seeks to a position.
280
+ * @event
281
+ */
282
+ playerSeek: [Player, number];
283
+ /**
284
+ * Emitted when a player updates its filters.
285
+ * @event
286
+ */
287
+ playerFilters: [Player, Filters];
288
+ }
289
+ interface PlayerEvents {
290
+ /**
291
+ * Represents Lavalink's playerUpdate event.
292
+ * emits every x time as defined by the lavalink server.
293
+ * @see {@link https://lavalink.dev/api/websocket.html#player-update-op}
294
+ * @event
295
+ */
296
+ state: [PlayerState];
297
+ /**
298
+ * Emitted when a track starts playing.
299
+ * @see {@link https://lavalink.dev/api/websocket.html#trackstartevent}
300
+ * @event
301
+ */
302
+ trackStart: [TrackStartEvent];
303
+ /**
304
+ * Emitted when a track ends.
305
+ * @see {@link https://lavalink.dev/api/websocket.html#trackendevent}
306
+ * @event
307
+ */
308
+ trackEnd: [TrackEndEvent];
309
+ /**
310
+ * Emitted when a track encounters an exception.
311
+ * @see {@link https://lavalink.dev/api/websocket.html#trackexceptionevent}
312
+ * @event
313
+ */
314
+ trackException: [TrackExceptionEvent];
315
+ /**
316
+ * Emitted when a track gets stuck.
317
+ * @see {@link https://lavalink.dev/api/websocket.html#trackstuckevent}
318
+ * @event
319
+ */
320
+ trackStuck: [TrackStuckEvent];
321
+ /**
322
+ * Emitted when the voice WebSocket is closed.
323
+ * @see {@link https://lavalink.dev/api/websocket.html#websocketclosedevent}
324
+ * @event
325
+ */
326
+ webSocketClosed: [WebSocketClosedEvent];
327
+ /**
328
+ * Emitted when the player is paused or resumed.
329
+ * @event
330
+ */
331
+ pause: [boolean];
332
+ /**
333
+ * Emitted when the player seeks to a position.
334
+ * @event
335
+ */
336
+ seek: [number];
337
+ /**
338
+ * Emitted when the player volume changes.
339
+ * @event
340
+ */
341
+ volume: [number];
342
+ /**
343
+ * Emitted when the player updates its filters.
344
+ * @event
345
+ */
346
+ filters: [Filters];
347
+ }
348
+
349
+ /**
350
+ * The Player class that handles playback and audio manipulation for a specific guild.
351
+ *
352
+ * @remarks
353
+ * This class is responsible for audio playback operations, including playing, stopping,
354
+ * pausing, resuming, and applying audio filters. Each instance represents a player
355
+ * for a specific guild.
356
+ */
357
+ declare class Player extends EventEmitter<PlayerEvents> {
358
+ /**
359
+ * The Lavalink node this player is connected to
360
+ */
361
+ node: LavalinkNode;
362
+ /**
363
+ * The guild ID for this player
364
+ */
365
+ guildId: string;
366
+ /**
367
+ * The current state of this Player
368
+ *
369
+ * @remarks
370
+ * Contains information about the player state from Lavalink, including position, filters, etc.
371
+ */
372
+ state: PlayerState$1;
373
+ /**
374
+ * The timestamp when the current track started playing
375
+ *
376
+ * @remarks
377
+ * This is a client-side timestamp, not synchronized with Lavalink.
378
+ * Can be used to calculate approximate playback position.
379
+ */
380
+ timestamp: number | null;
381
+ /**
382
+ * Whether the audio playback is currently paused
383
+ */
384
+ paused: boolean;
385
+ /**
386
+ * The current volume level (0-1000)
387
+ */
388
+ volume: number;
389
+ /**
390
+ * The current track in Lavalink's base64 string form
391
+ *
392
+ * @remarks
393
+ * This is null when no track is loaded or when playback has ended.
394
+ */
395
+ track: Track | null;
396
+ /**
397
+ * The voice connection state from Lavalink API
398
+ */
399
+ voice: VoiceState | null;
400
+ /**
401
+ * The current audio filters applied to this player
402
+ *
403
+ * @remarks
404
+ * This includes effects like equalizer, karaoke, etc.
405
+ */
406
+ filters: Filters$1;
407
+ /**
408
+ * Creates a new player instance.
409
+ *
410
+ * @param node - The Lavalink node this player is connected to.
411
+ * @param guildId - The guild ID that this player is associated with.
412
+ */
413
+ constructor(
414
+ /**
415
+ * The Lavalink node this player is connected to
416
+ */
417
+ node: LavalinkNode,
418
+ /**
419
+ * The guild ID for this player
420
+ */
421
+ guildId: string);
422
+ /**
423
+ * Updates the current player on the Lavalink node.
424
+ * @see {@link https://lavalink.dev/api/rest#update-player}
425
+ *
426
+ * @param options - The update options to apply to the player.
427
+ * @param noReplace - If true, the event will be dropped if there's a currently playing track.
428
+ * @returns {Promise<APIPlayer>} The updated player information from Lavalink.
429
+ */
430
+ update(options: UpdatePlayerData, noReplace?: boolean): Promise<Player$1>;
431
+ /**
432
+ * Plays a track using its base64 encoded string.
433
+ *
434
+ * @param track - The base64 encoded track string from Lavalink.
435
+ * @param options - Additional options for playback.
436
+ * @returns A promise resolving to the updated player information.
437
+ */
438
+ play(track: string, options?: Omit<UpdatePlayerData, "track"> & {
439
+ noReplace?: boolean;
440
+ userData?: Record<any, any>;
441
+ }): Promise<UpdatePlayerResult>;
442
+ /**
443
+ * Stops the currently playing track.
444
+ *
445
+ * @remarks
446
+ * This will trigger a "TrackEndEvent" with reason "STOPPED".
447
+ *
448
+ * @returns A promise resolving to the updated player information.
449
+ */
450
+ stop(): Promise<UpdatePlayerResult>;
451
+ /**
452
+ * Pauses or resumes the current track.
453
+ *
454
+ * @param pause - Whether to pause (true) or resume (false) playback.
455
+ * @returns A promise resolving to the updated player information.
456
+ */
457
+ pause(pause: boolean): Promise<UpdatePlayerResult>;
458
+ /**
459
+ * Changes the volume of the current playback.
460
+ *
461
+ * @param volume - The volume level as a number between 0 and 1000
462
+ * @returns A promise resolving to the updated player information.
463
+ */
464
+ setVolume(volume: number): Promise<UpdatePlayerResult>;
465
+ /**
466
+ * Seeks to a specific position in the current track.
467
+ *
468
+ * @param position - The position to seek to in milliseconds.
469
+ * @returns A promise resolving to the updated player information.
470
+ */
471
+ seek(position: number): Promise<UpdatePlayerResult>;
472
+ /**
473
+ * Applies audio filters to the current playback.
474
+ *
475
+ * @param options - The filter options to apply.
476
+ * @returns A promise resolving to the updated player information.
477
+ */
478
+ setFilters(options: Filters$1): Promise<UpdatePlayerResult>;
479
+ /**
480
+ * Sets the equalizer effect for the current playback.
481
+ *
482
+ * @param bands - An array of equalizer bands to adjust.
483
+ * @returns A promise resolving to the updated player information.
484
+ *
485
+ * @remarks
486
+ * Each band is an object with 'band' (0-14) and 'gain' (-0.25 to 1.0) properties.
487
+ */
488
+ setEqualizer(bands: Equalizer[]): Promise<UpdatePlayerResult>;
489
+ /**
490
+ * Destroys the player on the Lavalink node.
491
+ *
492
+ * @remarks
493
+ * This sends a destroy signal to Lavalink to clean up resources for this guild ID.
494
+ * It doesn't affect the Discord voice connection - use {@link Manager.leave} for that.
495
+ *
496
+ * @returns {Promise<DestroyPlayerResult>} A promise resolving to the destroy result.
497
+ */
498
+ destroy(): Promise<DestroyPlayerResult>;
499
+ /**
500
+ * Provides voice server update information to Lavalink to establish a connection.
501
+ *
502
+ * @param data - The voice update state containing session ID and voice server information.
503
+ * @returns A promise resolving to the updated player information.
504
+ */
505
+ connect(data: PlayerUpdateVoiceState): Promise<UpdatePlayerResult>;
506
+ /**
507
+ * Switches the player to a different voice channel.
508
+ *
509
+ * @param channel - The ID of the voice channel to switch to.
510
+ * @param options - Options for joining the channel (selfMute, selfDeaf).
511
+ * @returns Does not return anything, but sends a WebSocket message to the Lavalink node.
512
+ */
513
+ switchChannel(channel: string, options?: JoinOptions): unknown;
514
+ /**
515
+ * Gets the manager instance that created this player.
516
+ *
517
+ * @returns {Manager} The manager instance.
518
+ */
519
+ get manager(): Manager;
520
+ }
521
+
522
+ /**
523
+ * Main class that handles Lavalink node connections and player management.
524
+ *
525
+ * @remarks
526
+ * The Manager acts as the central hub for Lavacord, managing connections to Lavalink nodes,
527
+ * handling voice state updates, and providing a unified interface for player operations.
528
+ */
529
+ declare class Manager extends EventEmitter<ManagerEvents> {
530
+ /**
531
+ * A Map of Lavalink Nodes indexed by their IDs.
532
+ */
533
+ nodes: Map<string, LavalinkNode>;
534
+ /**
535
+ * A Map of all active players indexed by guild ID.
536
+ */
537
+ players: Map<string, Player>;
538
+ /**
539
+ * A Map of voice server update states indexed by guild ID.
540
+ */
541
+ voiceServers: Map<string, GatewayVoiceServerUpdateDispatchData>;
542
+ /**
543
+ * A Map of voice state update states indexed by guild ID.
544
+ */
545
+ voiceStates: Map<string, discord_api_types_v10.APIVoiceState>;
546
+ /**
547
+ * The user ID of the bot this Manager is managing.
548
+ */
549
+ userId: string | null;
550
+ /**
551
+ * Function to send voice state update packets to Discord.
552
+ *
553
+ * @remarks
554
+ * This can be implemented by the user in two ways:
555
+ * 1. Via constructor options: `new Manager(nodes, { send: fn })`
556
+ * 2. Via class extension: `class MyManager extends Manager { send(packet) { ... } }`
557
+ */
558
+ private _send?;
559
+ /**
560
+ * The Player class constructor used when creating new players.
561
+ *
562
+ * @remarks
563
+ * Can be overridden in the manager options to use a custom Player implementation.
564
+ */
565
+ private readonly Player;
566
+ /**
567
+ * A Set of guild IDs that are waiting for a connection.
568
+ *
569
+ * @internal
570
+ */
571
+ private readonly expecting;
572
+ /**
573
+ * Creates a new Manager instance.
574
+ *
575
+ * @param nodes - An array of Lavalink node options to connect to.
576
+ * @param options - Configuration options for the Manager.
577
+ *
578
+ * @example
579
+ * ```typescript
580
+ * // Method 1: Define send function via options
581
+ * const manager = new Manager([
582
+ * {
583
+ * id: "main",
584
+ * host: "localhost",
585
+ * port: 2333,
586
+ * password: "youshallnotpass"
587
+ * }
588
+ * ], {
589
+ * userId: "bot_user_id",
590
+ * send: (packet) => {
591
+ * const guild = client.guilds.cache.get(packet.d.guild_id);
592
+ * if (guild) guild.shard.send(packet);
593
+ * }
594
+ * });
595
+ *
596
+ * // Method 2: Extend Manager class
597
+ * class MyManager extends Manager {
598
+ * send(packet) {
599
+ * const guild = this.client.guilds.cache.get(packet.d.guild_id);
600
+ * if (guild) guild.shard.send(packet);
601
+ * }
602
+ * }
603
+ * const manager = new MyManager(nodes, { userId: "bot_user_id" });
604
+ * ```
605
+ */
606
+ constructor(nodes: LavalinkNodeOptions[], options?: ManagerOptions);
607
+ /**
608
+ * Connects all Lavalink nodes to their respective Lavalink servers.
609
+ *
610
+ * @returns A promise that resolves when all connections are established.
611
+ *
612
+ * @example
613
+ * ```typescript
614
+ * // Connect all nodes
615
+ * manager.connect()
616
+ * .then(() => console.log('All nodes connected!'))
617
+ * .catch(error => console.error('Failed to connect nodes:', error));
618
+ * ```
619
+ */
620
+ connect(): Promise<LavalinkNode[]>;
621
+ /**
622
+ * Disconnects all players and nodes, effectively cleaning up all resources.
623
+ *
624
+ * @returns A promise that resolves when all disconnections are complete.
625
+ *
626
+ * @example
627
+ * ```typescript
628
+ * // Disconnect everything
629
+ * manager.disconnect()
630
+ * .then(() => console.log('All players and nodes cleaned up'))
631
+ * .catch(error => console.error('Error during disconnection:', error));
632
+ * ```
633
+ */
634
+ disconnect(): Promise<void>;
635
+ /**
636
+ * Creates a new Lavalink node and adds it to the nodes map.
637
+ *
638
+ * @param options - Configuration options for the node.
639
+ * @returns The newly created LavalinkNode instance.
640
+ *
641
+ * @example
642
+ * ```typescript
643
+ * // Add a new node
644
+ * const newNode = manager.createNode({
645
+ * id: "node2",
646
+ * host: "example.com",
647
+ * port: 2333,
648
+ * password: "securepassword",
649
+ * resuming: true
650
+ * });
651
+ * ```
652
+ */
653
+ createNode(options: LavalinkNodeOptions): LavalinkNode;
654
+ /**
655
+ * Disconnects and removes a node from the manager.
656
+ *
657
+ * @param id - The ID of the node to remove.
658
+ * @returns Whether the node was successfully removed.
659
+ *
660
+ * @example
661
+ * ```typescript
662
+ * // Remove a node
663
+ * const removed = manager.removeNode("node1");
664
+ * if (removed) {
665
+ * console.log("Node successfully removed");
666
+ * } else {
667
+ * console.log("Node not found");
668
+ * }
669
+ * ```
670
+ */
671
+ removeNode(id: string): boolean;
672
+ /**
673
+ * Joins a voice channel and creates a player for the guild.
674
+ *
675
+ * @param data - The data needed to join a voice channel.
676
+ * @param joinOptions - Options for joining the channel (selfmute, selfdeaf).
677
+ * @returns A promise resolving to the Player instance.
678
+ *
679
+ * @example
680
+ * ```typescript
681
+ * // Join a voice channel
682
+ * const player = await manager.join({
683
+ * guild: "123456789012345678", // Guild ID
684
+ * channel: "123456789012345679", // Voice Channel ID
685
+ * node: "main" // Node ID
686
+ * }, {
687
+ * selfdeaf: true // Join deafened
688
+ * });
689
+ *
690
+ * // Now you can use the player to play music
691
+ * const result = await Rest.load(player.node, "https://www.youtube.com/watch?v=dQw4w9WgXcQ");
692
+ * await player.play(result.tracks[0].track);
693
+ * ```
694
+ */
695
+ join(data: JoinData, joinOptions?: JoinOptions): Promise<Player>;
696
+ /**
697
+ * Leaves a voice channel and cleans up the player.
698
+ *
699
+ * @param guild - The ID of the guild to leave.
700
+ * @returns A promise resolving to whether the operation was successful.
701
+ *
702
+ * @example
703
+ * ```typescript
704
+ * // Leave a voice channel
705
+ * const success = await manager.leave("123456789012345678");
706
+ * if (success) {
707
+ * console.log("Successfully left the voice channel");
708
+ * } else {
709
+ * console.log("Not in a voice channel in this guild");
710
+ * }
711
+ * ```
712
+ */
713
+ leave(guild: string): Promise<boolean>;
714
+ /**
715
+ * Switches a player from one node to another, implementing fallback capability.
716
+ *
717
+ * @param player - The player to move to another node.
718
+ * @param node - The destination node.
719
+ * @returns A promise resolving to the updated player.
720
+ *
721
+ * @example
722
+ * ```typescript
723
+ * // Switch a player to another node (e.g. if current node is failing)
724
+ * const player = manager.players.get("123456789012345678");
725
+ * const newNode = manager.nodes.get("backup-node");
726
+ *
727
+ * if (player && newNode) {
728
+ * await manager.switch(player, newNode);
729
+ * console.log("Player switched to backup node");
730
+ * }
731
+ * ```
732
+ */
733
+ switch(player: Player, node: LavalinkNode): Promise<Player>;
734
+ /**
735
+ * Processes voice server update events from Discord.
736
+ *
737
+ * @param data - The voice server update data from Discord.
738
+ * @returns A promise resolving to whether a connection was established.
739
+ *
740
+ * @example
741
+ * ```typescript
742
+ * // In your Discord.js client events
743
+ * client.ws.on(GatewayDispatchEvents.VoiceServerUpdate, (data) => {
744
+ * manager.voiceServerUpdate(data);
745
+ * });
746
+ * ```
747
+ */
748
+ voiceServerUpdate(data: GatewayVoiceServerUpdateDispatchData): Promise<boolean>;
749
+ /**
750
+ * Processes voice state update events from Discord.
751
+ *
752
+ * @param data - The voice state update data from Discord.
753
+ * @returns A promise resolving to whether a connection was established.
754
+ *
755
+ * @example
756
+ * ```typescript
757
+ * // In your Discord.js client events
758
+ * client.ws.on(GatewayDispatchEvents.VoiceStateUpdate, (data) => {
759
+ * manager.voiceStateUpdate(data);
760
+ * });
761
+ * ```
762
+ */
763
+ voiceStateUpdate(data: GatewayVoiceStateUpdateDispatchData): Promise<boolean>;
764
+ /**
765
+ * Sends a voice state update packet to Discord.
766
+ *
767
+ * @param guild - The ID of the guild.
768
+ * @param channel - The ID of the voice channel to join, or null to leave.
769
+ * @param options - Options for joining (selfmute, selfdeaf).
770
+ * @returns The result from the send function.
771
+ *
772
+ * @example
773
+ * ```typescript
774
+ * // Join a voice channel
775
+ * manager.sendWS("123456789012345678", "123456789012345679", { selfdeaf: true });
776
+ *
777
+ * // Leave a voice channel
778
+ * manager.sendWS("123456789012345678", null);
779
+ * ```
780
+ */
781
+ sendWS(guild: string, channel: string | null, { selfmute, selfdeaf }?: JoinOptions): unknown;
782
+ /**
783
+ * Gets all connected nodes, sorted by CPU load.
784
+ *
785
+ * @returns An array of connected nodes sorted by CPU load (least to most).
786
+ *
787
+ * @example
788
+ * ```typescript
789
+ * // Get the node with the least CPU load
790
+ * const bestNode = manager.idealNodes[0];
791
+ * if (bestNode) {
792
+ * console.log(`Best node for new connections: ${bestNode.id}`);
793
+ * }
794
+ * ```
795
+ */
796
+ get idealNodes(): LavalinkNode[];
797
+ /**
798
+ * Attempts to establish a connection for a guild using available voice data.
799
+ *
800
+ * @internal
801
+ * @param guildID - The ID of the guild to attempt connecting.
802
+ * @returns A promise resolving to whether a connection was established.
803
+ */
804
+ private _attemptConnection;
805
+ /**
806
+ * Creates a new player instance.
807
+ *
808
+ * @internal
809
+ * @param data - The data needed to create a player.
810
+ * @returns The created Player instance.
811
+ */
812
+ private spawnPlayer;
813
+ protected send(packet: GatewayVoiceStateUpdate): unknown;
814
+ }
815
+
816
+ /**
817
+ * The LavalinkNode class handles the connection and communication with a Lavalink server.
818
+ *
819
+ * @summary Manages WebSocket connections to Lavalink servers and processes server events
820
+ *
821
+ * This class is responsible for establishing WebSocket connections to Lavalink,
822
+ * handling reconnection logic, and processing incoming messages from the server.
823
+ *
824
+ * @remarks
825
+ * LavalinkNode instances are typically created and managed by the {@link Manager} class,
826
+ * which handles load balancing across multiple nodes and routing player actions
827
+ * to the appropriate node.
828
+ */
829
+ declare class LavalinkNode {
830
+ manager: Manager;
831
+ /**
832
+ * The identifier for this Lavalink node. Used to distinguish between multiple nodes.
833
+ *
834
+ * @summary Unique identifier for the node
835
+ * @remarks
836
+ * This is a required property that must be unique across all nodes in your application.
837
+ * It's used for identifying this node in logs and when selecting nodes for new players.
838
+ */
839
+ id: string;
840
+ /**
841
+ * The hostname or IP address of the Lavalink server.
842
+ *
843
+ * @summary Server hostname or IP address
844
+ * @remarks
845
+ * This can be a domain name, IPv4, or IPv6 address pointing to your Lavalink server.
846
+ */
847
+ readonly host = "localhost";
848
+ /**
849
+ * The port number that the Lavalink server is listening on.
850
+ *
851
+ * @summary Server port number
852
+ * @remarks
853
+ * This should match the port configured in your Lavalink server's application.yml.
854
+ */
855
+ readonly port: number | string;
856
+ /**
857
+ * The time in milliseconds between reconnection attempts if the connection fails.
858
+ *
859
+ * @summary Reconnection delay in milliseconds
860
+ * @remarks
861
+ * Lower values will attempt reconnections more quickly, but might
862
+ * cause excessive connection attempts during prolonged server outages.
863
+ */
864
+ reconnectInterval: number;
865
+ /**
866
+ * The password used for authorization with the Lavalink server.
867
+ *
868
+ * @summary Authorization password for the Lavalink server
869
+ * @remarks
870
+ * This password must match the one configured in your Lavalink server's application.yml.
871
+ * It's used in the Authorization header when establishing the WebSocket connection.
872
+ */
873
+ readonly password = "youshallnotpass";
874
+ /**
875
+ * Whether to use secure connections (HTTPS/WSS) instead of HTTP/WS.
876
+ *
877
+ * @summary Secure connection flag for SSL/TLS
878
+ * @remarks
879
+ * When true, WebSocket connections will use WSS and REST requests will use HTTPS.
880
+ * This is required when connecting to Lavalink servers behind SSL/TLS.
881
+ */
882
+ readonly secure = false;
883
+ /**
884
+ * The WebSocket instance used for communication with the Lavalink server.
885
+ *
886
+ * @summary Active WebSocket connection to the Lavalink server
887
+ * @remarks
888
+ * When not connected to Lavalink, this property will be null.
889
+ * You can check the {@link connected} property to determine connection status.
890
+ */
891
+ ws: BetterWs | null;
892
+ /**
893
+ * The statistics received from the Lavalink server.
894
+ *
895
+ * @summary Server resource usage and player statistics
896
+ * @remarks
897
+ * Contains information about system resource usage, player counts, and audio frame statistics.
898
+ * This is updated whenever the Lavalink server sends a stats update (typically every minute).
899
+ * You can use these stats to implement node selection strategies in your application.
900
+ */
901
+ stats: Stats;
902
+ /**
903
+ * Whether this node should attempt to resume the session when reconnecting.
904
+ *
905
+ * @summary Session resumption flag
906
+ * @remarks
907
+ * When true, the node will try to resume the previous session after a disconnect,
908
+ * preserving player states and connections. This helps maintain playback during
909
+ * brief disconnections or node restarts.
910
+ */
911
+ resuming: boolean;
912
+ /**
913
+ * The timeout in seconds after which a disconnected session can no longer be resumed.
914
+ *
915
+ * @summary Maximum session resumption timeout in seconds
916
+ * @remarks
917
+ * This value is sent to the Lavalink server when configuring session resuming.
918
+ * After this many seconds of disconnection, the session will be fully closed
919
+ * and cannot be resumed.
920
+ */
921
+ resumeTimeout: number;
922
+ /**
923
+ * Custom data that can be attached to the node instance.
924
+ *
925
+ * @summary Custom application data storage
926
+ * @remarks
927
+ * Not used internally by Lavacord, available for application-specific needs.
928
+ * You can use this property to store any data relevant to your implementation,
929
+ * such as region information, feature flags, or custom metrics.
930
+ */
931
+ state?: any;
932
+ /**
933
+ * The unique session identifier provided by Lavalink on successful connection.
934
+ *
935
+ * @summary Lavalink session identifier
936
+ * @remarks
937
+ * This ID is used for resuming sessions and in certain REST API calls.
938
+ * It's automatically assigned when connecting to the Lavalink server.
939
+ */
940
+ sessionId?: string;
941
+ /**
942
+ * The version of the Lavalink protocol this node is using.
943
+ *
944
+ * @summary Lavalink protocol version
945
+ * @remarks
946
+ * This is set automatically when connecting to the Lavalink server.
947
+ * It indicates which version of the Lavalink protocol this node supports.
948
+ * The default value is "4", which corresponds to the latest stable version.
949
+ *
950
+ * @defaultValue "4"
951
+ */
952
+ version: string;
953
+ /**
954
+ * Timeout reference used for the reconnection mechanism.
955
+ * This holds the NodeJS.Timeout instance used to schedule reconnection attempts.
956
+ */
957
+ private _reconnect?;
958
+ /**
959
+ * Current reconnection attempt count for exponential backoff.
960
+ */
961
+ private _reconnectAttempts;
962
+ /**
963
+ * Tracks whether the session has been updated with the Lavalink server.
964
+ * Used internally to avoid redundant session update requests.
965
+ */
966
+ private _sessionUpdated;
967
+ /**
968
+ * Creates a new LavalinkNode instance.
969
+ *
970
+ * @summary Initializes a new Lavalink node connection
971
+ * @param manager - The {@link Manager} instance that controls this node
972
+ * @param options - Configuration options for this Lavalink node as defined in {@link LavalinkNodeOptions}
973
+ */
974
+ constructor(manager: Manager, options: LavalinkNodeOptions);
975
+ /**
976
+ * Establishes a connection to the Lavalink server.
977
+ *
978
+ * This method creates a new WebSocket connection to the configured Lavalink server.
979
+ * If the node is already connected, it will close the existing connection first.
980
+ * The method sets up event listeners for the WebSocket to handle messages, errors,
981
+ * and connection state changes.
982
+ *
983
+ * Note: This method is primarily used internally by the {@link Manager} class.
984
+ * Users typically should not call this method directly as the Manager handles
985
+ * node connections automatically.
986
+ *
987
+ * @returns A promise that resolves when connected or rejects if connection fails
988
+ * @throws {Error} If the connection fails due to network issues, authentication problems, or other errors
989
+ */
990
+ connect(): Promise<BetterWs>;
991
+ /**
992
+ * Gracefully closes the connection to the Lavalink server.
993
+ *
994
+ * This method closes the WebSocket connection with a normal closure code (1000)
995
+ * and a reason of "destroy", indicating an intentional disconnection rather
996
+ * than an error condition.
997
+ *
998
+ * Note: This method is primarily used internally by the {@link Manager} class.
999
+ * Users typically should not call this method directly as the Manager handles
1000
+ * node disconnections automatically.
1001
+ *
1002
+ * @returns void
1003
+ */
1004
+ destroy(): void;
1005
+ /**
1006
+ * Indicates whether this node is currently connected to the Lavalink server.
1007
+ *
1008
+ * @summary Connection status check
1009
+ * @remarks
1010
+ * Checks if the {@link ws} instance exists and if its ready state is 1.
1011
+ * This property is useful for verifying connection status before attempting operations
1012
+ * or implementing node selection strategies.
1013
+ *
1014
+ * @returns `true` if connected, `false` otherwise
1015
+ */
1016
+ get connected(): boolean;
1017
+ /**
1018
+ * Gets the WebSocket URL for connecting to the Lavalink server.
1019
+ *
1020
+ * @summary WebSocket connection URL
1021
+ * @remarks
1022
+ * Returns either a secure (wss://) or insecure (ws://) WebSocket URL
1023
+ * based on the {@link secure} property configuration.
1024
+ *
1025
+ * @returns The complete WebSocket URL including protocol, host, port, and path
1026
+ */
1027
+ get socketURL(): string;
1028
+ /**
1029
+ * Gets the REST API base URL for the Lavalink server.
1030
+ *
1031
+ * @summary REST API base URL
1032
+ * @remarks
1033
+ * Returns either a secure (https://) or insecure (http://) REST URL
1034
+ * based on the {@link secure} property configuration.
1035
+ *
1036
+ * @returns The complete REST API base URL including protocol, host, port, and path
1037
+ */
1038
+ get restURL(): string;
1039
+ /**
1040
+ * Handles the WebSocket 'open' event when a connection is established.
1041
+ */
1042
+ private onOpen;
1043
+ /**
1044
+ * Processes incoming WebSocket messages from the Lavalink server.
1045
+ * @param msg - The raw data received from the WebSocket
1046
+ */
1047
+ private onMessage;
1048
+ /**
1049
+ * Handles WebSocket errors.
1050
+ * @param error - The error received from the WebSocket
1051
+ */
1052
+ private onError;
1053
+ /**
1054
+ * Handles WebSocket closure.
1055
+ *
1056
+ * @param code - The WebSocket close code (see Lavalink API for code meanings)
1057
+ * @param reason - The reason why the WebSocket was closed
1058
+ */
1059
+ private onClose;
1060
+ /**
1061
+ * Initiates a reconnection attempt after a delay with exponential backoff.
1062
+ */
1063
+ private reconnect;
1064
+ private _handleEvent;
1065
+ }
1066
+
1067
+ /**
1068
+ * Error class for Lavalink REST API errors.
1069
+ * @remarks
1070
+ * Contains the full error response from the Lavalink server.
1071
+ * See {@link https://lavalink.dev/api/rest#error-responses}
1072
+ * @public
1073
+ */
1074
+ declare class RestError extends Error {
1075
+ error: ErrorResponse;
1076
+ data: RequestInit;
1077
+ constructor(error: ErrorResponse, data: RequestInit);
1078
+ }
1079
+ /**
1080
+ * A utility class for interacting with the Lavalink REST API.
1081
+ *
1082
+ * @remarks
1083
+ * Provides methods to perform various operations on a Lavalink server through its REST API,
1084
+ * including loading tracks, decoding tracks, and controlling players.
1085
+ *
1086
+ * @public
1087
+ * @sealed
1088
+ */
1089
+ declare class Rest {
1090
+ /**
1091
+ * Base request function that handles communication with Lavalink REST API.
1092
+ *
1093
+ * @internal
1094
+ * @param node - The Lavalink node to send the request to.
1095
+ * @param path - The API route path, starting with /.
1096
+ * @param init - Optional request initialization options.
1097
+ * @param requiresSessionId - Whether the request requires a valid session ID.
1098
+ * @returns A promise resolving to the response data.
1099
+ * @throws {@link RestError} If Lavalink returns an error response.
1100
+ */
1101
+ private static baseRequest;
1102
+ /**
1103
+ * Loads tracks from various sources using Lavalink's loadtracks endpoint.
1104
+ *
1105
+ * @param node - The Lavalink node to use.
1106
+ * @param identifer - The identifier to load tracks from (URL, search query, etc.)
1107
+ * @returns A promise resolving to the track loading result.
1108
+ * @throws {@link RestError} If Lavalink encounters an error.
1109
+ *
1110
+ * @public
1111
+ */
1112
+ static load(node: LavalinkNode, identifer: string): Promise<TrackLoadingResult>;
1113
+ /**
1114
+ * Decodes track(s) from their base64 encoded form.
1115
+ *
1116
+ * @param node - The Lavalink node to use.
1117
+ * @param track - A single track to decode.
1118
+ * @returns A promise resolving to the decoded track information.
1119
+ * @throws {@link RestError} If Lavalink encounters an error.
1120
+
1121
+ * @public
1122
+ */
1123
+ static decode(node: LavalinkNode, track: string): Promise<DecodeTrackResult>;
1124
+ /**
1125
+ * Decodes multiple tracks from their base64 encoded form.
1126
+ *
1127
+ * @param node - The Lavalink node to use.
1128
+ * @param tracks - An array of tracks to decode.
1129
+ * @returns A promise resolving to an array of decoded track information.
1130
+ * @throws {@link RestError} If Lavalink encounters an error.
1131
+ *
1132
+ * @public
1133
+ */
1134
+ static decode(node: LavalinkNode, tracks: string[]): Promise<DecodeTracksResult>;
1135
+ /**
1136
+ * Retrieves the version from the Lavalink server.
1137
+ *
1138
+ * @param node - The Lavalink node to query.
1139
+ * @returns A promise resolving to the version of lavalink.
1140
+ * @throws {@link RestError} If Lavalink encounters an error.
1141
+ *
1142
+ * @public
1143
+ */
1144
+ static version(node: LavalinkNode): Promise<GetLavalinkVersionResult>;
1145
+ /**
1146
+ * Retrieves the information of the Lavalink server.
1147
+ *
1148
+ * @param node - The Lavalink node to query.
1149
+ * @returns A promise resolving to the information of lavalink.
1150
+ * @throws {@link RestError} If Lavalink encounters an error.
1151
+ *
1152
+ * @public
1153
+ */
1154
+ static info(node: LavalinkNode): Promise<GetLavalinkInfoResult>;
1155
+ /**
1156
+ * Retrieves the statistics of the Lavalink node.
1157
+ *
1158
+ * @param node - The Lavalink node to query.
1159
+ * @returns A promise resolving to the statistics of lavalink.
1160
+ * @throws {@link RestError} If Lavalink encounters an error.
1161
+ *
1162
+ * @public
1163
+ */
1164
+ static stats(node: LavalinkNode): Promise<GetLavalinkStatsResult>;
1165
+ /**
1166
+ * Updates the session properties of a Lavalink node.
1167
+ *
1168
+ * @param node - The Lavalink node to update.
1169
+ * @returns A promise resolving to the update session result.
1170
+ * @throws {@link RestError} If Lavalink encounters an error.
1171
+ *
1172
+ * @public
1173
+ */
1174
+ static updateSession(node: LavalinkNode): Promise<UpdateSessionResult>;
1175
+ /**
1176
+ * Updates a player on a Lavalink node.
1177
+ *
1178
+ * @param node - The Lavalink node hosting the player.
1179
+ * @param guildId - The guild ID associated with the player.
1180
+ * @param data - The player update data.
1181
+ * @param noReplace - If true, the event will be dropped if there's a currently playing track.
1182
+ * @returns A promise resolving to the updated player information.
1183
+ * @throws {@link RestError} If Lavalink encounters an error.
1184
+
1185
+ * @public
1186
+ */
1187
+ static updatePlayer(node: LavalinkNode, guildId: string, data: UpdatePlayerData, noReplace?: boolean): Promise<UpdatePlayerResult>;
1188
+ /**
1189
+ * Destroys a player on a Lavalink node.
1190
+ *
1191
+ * @param node - The Lavalink node hosting the player.
1192
+ * @param guildId - The guild ID associated with the player to destroy.
1193
+ * @returns A promise resolving to the destroy player result.
1194
+ * @throws {@link RestError} If Lavalink encounters an error.
1195
+ *
1196
+ * @public
1197
+ */
1198
+ static destroyPlayer(node: LavalinkNode, guildId: string): Promise<DestroyPlayerResult>;
1199
+ }
1200
+ interface BaseRequestInit extends RequestInit {
1201
+ query?: string | URLSearchParams | Record<string, string> | [string, string][];
1202
+ }
1203
+
1204
+ /**
1205
+ * @module Lavacord
1206
+ */
1207
+
1208
+ declare const VERSION: string;
1209
+
1210
+ export { LavalinkNode, Manager, Player, Rest, RestError, VERSION };
1211
+ export type { BaseRequestInit, JoinData, JoinOptions, LavalinkNodeOptions, ManagerEvents, ManagerOptions, PlayerEvents, PlayerUpdateVoiceState };