Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(VoiceState): add methods for fetching voice state #10442

Merged
merged 13 commits into from
Aug 20, 2024
23 changes: 14 additions & 9 deletions packages/core/src/api/guild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ import {
type RESTPatchAPIGuildTemplateJSONBody,
type RESTPatchAPIGuildTemplateResult,
type RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody,
type RESTPatchAPIGuildVoiceStateCurrentMemberResult,
type RESTPatchAPIGuildVoiceStateUserJSONBody,
type RESTPatchAPIGuildWelcomeScreenJSONBody,
type RESTPatchAPIGuildWelcomeScreenResult,
Expand Down Expand Up @@ -102,6 +101,7 @@ import {
type RESTPutAPIGuildTemplateSyncResult,
type Snowflake,
} from 'discord-api-types/v10';
import { VoiceAPI } from './voice';
imnaiyar marked this conversation as resolved.
Show resolved Hide resolved

export class GuildsAPI {
public constructor(private readonly rest: REST) {}
Expand Down Expand Up @@ -687,19 +687,20 @@ export class GuildsAPI {
/**
* Edits a user's voice state in a guild
*
* @see {@link https://discord.com/developers/docs/resources/guild#modify-user-voice-state}
* @see {@link https://discord.com/developers/docs/resources/voice#modify-user-voice-state}
* @param guildId - The id of the guild to edit the current user's voice state in
* @param userId - The id of the user to edit the voice state for
* @param body - The data for editing the voice state
* @param options - The options for editing the voice state
* @deprecated Use {@link VoiceAPI.editUserVoiceState} instead
*/
public async editUserVoiceState(
guildId: Snowflake,
userId: Snowflake,
body: RESTPatchAPIGuildVoiceStateUserJSONBody,
{ reason, signal }: Pick<RequestData, 'reason' | 'signal'> = {},
) {
await this.rest.patch(Routes.guildVoiceState(guildId, userId), { reason, body, signal });
return new VoiceAPI(this.rest).editUserVoiceState(guildId, userId, body, { reason, signal });
}

/**
Expand Down Expand Up @@ -1298,14 +1299,18 @@ export class GuildsAPI {
/**
* Sets the voice state for the current user
*
* @see {@link https://discord.com/developers/docs/resources/guild#modify-current-user-voice-state}
* @see {@link https://discord.com/developers/docs/resources/voice#modify-current-user-voice-state}
* @param guildId - The id of the guild
* @param body - The options for setting the voice state
* @param body - The data for setting the voice state
* @param options - The options for setting the voice state
* @deprecated Use {@link VoiceAPI.editVoiceState} instead
*/
public async setVoiceState(guildId: Snowflake, body: RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody = {}) {
return this.rest.patch(Routes.guildVoiceState(guildId, '@me'), {
body,
}) as Promise<RESTPatchAPIGuildVoiceStateCurrentMemberResult>;
public async setVoiceState(
guildId: Snowflake,
body: RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody = {},
{ signal }: Pick<RequestData, 'signal'> = {},
) {
return new VoiceAPI(this.rest).editVoiceState(guildId, body, { signal });
}

/**
Expand Down
77 changes: 76 additions & 1 deletion packages/core/src/api/voice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
/* eslint-disable jsdoc/check-param-names */

import type { RequestData, REST } from '@discordjs/rest';
import { Routes, type RESTGetAPIVoiceRegionsResult } from 'discord-api-types/v10';
import {
Routes,
type Snowflake,
type RESTGetAPIVoiceRegionsResult,
type RESTGetAPIGuildVoiceStateUserResult,
type RESTGetAPIGuildVoiceStateCurrentMemberResult,
type RESTPatchAPIGuildVoiceStateUserJSONBody,
type RESTPatchAPIGuildVoiceStateCurrentMemberResult,
type RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody,
type RESTPatchAPIGuildVoiceStateUserResult,
} from 'discord-api-types/v10';

export class VoiceAPI {
public constructor(private readonly rest: REST) {}
Expand All @@ -15,4 +25,69 @@ export class VoiceAPI {
public async getVoiceRegions({ signal }: Pick<RequestData, 'signal'> = {}) {
return this.rest.get(Routes.voiceRegions(), { signal }) as Promise<RESTGetAPIVoiceRegionsResult>;
}

/**
* Fetches voice state of a user by their id
*
* @see {@link https://discord.com/developers/docs/resources/voice#get-user-voice-state}
* @param options - The options for fetching user voice state
*/
public async getUserVoiceState(guildId: Snowflake, userId: Snowflake, { signal }: Pick<RequestData, 'signal'> = {}) {
return this.rest.get(Routes.guildVoiceState(guildId, userId), {
signal,
}) as Promise<RESTGetAPIGuildVoiceStateUserResult>;
}

/**
* Fetches the current user's voice state
*
* @see {@link https://discord.com/developers/docs/resources/voice#get-current-user-voice-state}
* @param options - The options for fetching user voice state
*/
public async getVoiceState(guildId: Snowflake, { signal }: Pick<RequestData, 'signal'> = {}) {
return this.rest.get(Routes.guildVoiceState(guildId, '@me'), {
signal,
}) as Promise<RESTGetAPIGuildVoiceStateCurrentMemberResult>;
}

/**
* Edits a user's voice state in a guild
*
* @see {@link https://discord.com/developers/docs/resources/voice#modify-user-voice-state}
* @param guildId - The id of the guild to edit the current user's voice state in
* @param userId - The id of the user to edit the voice state for
* @param body - The data for editing the voice state
* @param options - The options for editing the voice state
*/
public async editUserVoiceState(
guildId: Snowflake,
userId: Snowflake,
body: RESTPatchAPIGuildVoiceStateUserJSONBody,
{ reason, signal }: Pick<RequestData, 'reason' | 'signal'> = {},
) {
return this.rest.patch(Routes.guildVoiceState(guildId, userId), {
reason,
body,
signal,
}) as Promise<RESTPatchAPIGuildVoiceStateUserResult>;
}

/**
* Edits the voice state for the current user
*
* @see {@link https://discord.com/developers/docs/resources/voice#modify-current-user-voice-state}
* @param guildId - The id of the guild
* @param body - The data for editing the voice state
* @param options - The options for editing the voice state
*/
public async editVoiceState(
guildId: Snowflake,
body: RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody = {},
{ signal }: Pick<RequestData, 'signal'> = {},
) {
return this.rest.patch(Routes.guildVoiceState(guildId, '@me'), {
body,
signal,
}) as Promise<RESTPatchAPIGuildVoiceStateCurrentMemberResult>;
}
}
22 changes: 22 additions & 0 deletions packages/discord.js/src/managers/VoiceStateManager.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

const { Routes } = require('discord-api-types/v10');
const CachedManager = require('./CachedManager');
const VoiceState = require('../structures/VoiceState');

Expand Down Expand Up @@ -32,6 +33,27 @@ class VoiceStateManager extends CachedManager {
if (cache) this.cache.set(data.user_id, entry);
return entry;
}

/**
* Obtains a user's voice state from discord or from the cache if it's already available.
* @param {GuildMemberResolvable|'@me'} member The member whose voice state is to be fetched
* @param {BaseFetchOptions} [options] Additional options for this fetch
* @returns {Promise<VoiceState>}
* @example
* // Fetch a member's voice state
* guild.voiceStates.fetch("66564597481480192")
* .then(console.log)
* .catch(console.error);
*/
async fetch(member, { cache = true, force = false } = {}) {
const id = member === '@me' ? member : this.guild.members.resolveId(member);
if (!force) {
const existing = this.cache.get(id === '@me' ? this.client.user.id : id);
if (existing) return existing;
}
const data = await this.client.rest.get(Routes.guildVoiceState(this.guild.id, id));
return this._add(data, cache);
}
}

module.exports = VoiceStateManager;
9 changes: 9 additions & 0 deletions packages/discord.js/src/structures/VoiceState.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,15 @@ class VoiceState extends Base {
return this;
}

/**
* Fetches this voice state.
* @param {boolean} [force=true] Whether to skip the cache check and request the API
* @returns {Promise<VoiceState>}
*/
fetch(force = true) {
return this.guild.voiceStates.fetch(this.id, { force });
}

/**
* Toggles the request to speak in the channel.
* Only applicable for stage channels and for the client's own voice state.
Expand Down
2 changes: 2 additions & 0 deletions packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3625,6 +3625,7 @@ export class VoiceState extends Base {
public setRequestToSpeak(request?: boolean): Promise<this>;
public setSuppressed(suppressed?: boolean): Promise<this>;
public edit(options: VoiceStateEditOptions): Promise<this>;
public fetch(force?: boolean): Promise<VoiceState>;
}

// tslint:disable-next-line no-empty-interface
Expand Down Expand Up @@ -4627,6 +4628,7 @@ export class UserManager extends CachedManager<Snowflake, User, UserResolvable>
export class VoiceStateManager extends CachedManager<Snowflake, VoiceState, typeof VoiceState> {
private constructor(guild: Guild, iterable?: Iterable<RawVoiceStateData>);
public guild: Guild;
public fetch(member: GuildMemberResolvable | '@me', options?: BaseFetchOptions): Promise<VoiceState>;
}

//#endregion
Expand Down
4 changes: 2 additions & 2 deletions packages/discord.js/typings/rawDataTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
APIUnavailableGuild,
APIUser,
APIVoiceRegion,
APIVoiceState,
APIWebhook,
GatewayActivity,
GatewayActivityAssets,
Expand All @@ -62,7 +63,6 @@ import {
GatewayPresenceUpdate,
GatewayReadyDispatchData,
GatewayTypingStartDispatchData,
GatewayVoiceState,
RESTAPIPartialCurrentUserGuild,
RESTGetAPIWebhookWithTokenResult,
RESTPatchAPIChannelMessageJSONBody,
Expand Down Expand Up @@ -195,7 +195,7 @@ export type RawUserData =

export type RawVoiceRegionData = APIVoiceRegion;

export type RawVoiceStateData = GatewayVoiceState | Omit<GatewayVoiceState, 'guild_id'>;
export type RawVoiceStateData = APIVoiceState | Omit<APIVoiceState, 'guild_id'>;

export type RawWebhookData =
| APIWebhook
Expand Down
Loading