fix: more helpers

This commit is contained in:
Skillz4Killz
2023-02-14 21:42:58 +00:00
parent 5732fdc278
commit 6f3eb70712
6 changed files with 507 additions and 44 deletions

View File

@@ -1,9 +1,9 @@
import type { AtLeastOne, BigString, Camelize, DiscordGetGatewayBot } from '@discordeno/types'
import { GatewayOpcodes } from '@discordeno/types'
import type { AtLeastOne, BigString, Camelize, DiscordGetGatewayBot, DiscordMember, RequestGuildMembers } from '@discordeno/types'
import { GatewayIntents, GatewayOpcodes } from '@discordeno/types'
import type { LeakyBucket } from '@discordeno/utils'
import { createLeakyBucket, delay } from '@discordeno/utils'
import { Collection, createLeakyBucket, delay } from '@discordeno/utils'
import Shard from './Shard.js'
import type { ShardEvents, UpdateVoiceState } from './types.js'
import type { ShardEvents, StatusUpdate, UpdateVoiceState } from './types.js'
export function createGatewayManager(options: CreateGatewayManagerOptions): GatewayManager {
if (!options.connection) {
@@ -40,6 +40,12 @@ export function createGatewayManager(options: CreateGatewayManagerOptions): Gate
spawnShardDelay: options.spawnShardDelay ?? 5300,
shards: new Map(),
buckets: new Map(),
cache: {
requestMembers: {
enabled: options.cache?.requestMembers?.enabled ?? false,
pending: new Collection(),
}
},
calculateTotalShards() {
// Bots under 100k servers do not have access to total shards.
@@ -196,6 +202,85 @@ export function createGatewayManager(options: CreateGatewayManagerOptions): Gate
},
})
},
async editBotStatus(data) {
await Promise.all(
[...gateway.shards.values()].map(async (shard) => {
gateway.editShardStatus(shard.id, data)
}),
)
},
async editShardStatus(shardId, data) {
const shard = gateway.shards.get(shardId)
if (!shard) {
throw new Error(`Shard (id: ${shardId}) not found.`)
}
return await shard.send({
op: GatewayOpcodes.PresenceUpdate,
d: {
since: null,
afk: false,
activities: data.activities,
status: data.status,
},
})
},
async requestMembers(guildId, options) {
// You can request 1 member without the intent
// Check if intents is not 0 as proxy ws won't set intents in other instances
if (gateway.intents && (!options?.limit || options.limit > 1) && !(gateway.intents & GatewayIntents.GuildMembers)) {
throw new Error('MISSING_INTENT_GUILD_MEMBERS')
}
if (options?.userIds?.length) {
options.limit = options.userIds.length
}
const shardId = gateway.calculateShardId(guildId)
const shard = gateway.shards.get(shardId)
if (!shard) {
throw new Error(`Shard (id: ${shardId}) not found.`)
}
const nonce = `${guildId}-${Date.now()}`
// Gateway does not require caching these requests so directly send and return
if (!gateway.cache.requestMembers?.enabled) {
await shard.send({
op: GatewayOpcodes.RequestGuildMembers,
d: {
guild_id: guildId.toString(),
// If a query is provided use it, OR if a limit is NOT provided use ""
query: options?.query ?? (options?.limit ? undefined : ''),
limit: options?.limit ?? 0,
presences: options?.presences ?? false,
user_ids: options?.userIds?.map((id) => id.toString()),
nonce,
},
})
return [];
}
return await new Promise((resolve) => {
gateway.cache.requestMembers?.pending.set(nonce, { nonce, resolve, members: [] })
shard.send({
op: GatewayOpcodes.RequestGuildMembers,
d: {
guild_id: guildId.toString(),
// If a query is provided use it, OR if a limit is NOT provided use ""
query: options?.query ?? (options?.limit ? undefined : ''),
limit: options?.limit ?? 0,
presences: options?.presences ?? false,
user_ids: options?.userIds?.map((id) => id.toString()),
nonce,
},
})
})
},
}
return gateway
@@ -276,6 +361,18 @@ export interface CreateGatewayManagerOptions {
version?: number
/** The events handlers */
events: ShardEvents
/** This managers cache related settings. */
cache?: {
requestMembers?: {
/**
* Whether or not request member requests should be cached.
* @default false
*/
enabled?: boolean
/** The pending requests. */
pending: Collection<string, RequestMemberRequest>
}
}
}
export interface GatewayManager extends Required<CreateGatewayManagerOptions> {
@@ -329,4 +426,52 @@ export interface GatewayManager extends Required<CreateGatewayManagerOptions> {
channelId: BigString,
options?: AtLeastOne<Omit<UpdateVoiceState, 'guildId' | 'channelId'>>,
) => Promise<void>
/**
* Edits the bot status in all shards that this gateway manages.
*
* @param data The status data to set the bots status to.
* @returns Promise<void>
*/
editBotStatus: (data: StatusUpdate) => Promise<void>
/**
* Edits the bot's status on one shard.
*
* @param shardId The shard id to edit the status for.
* @param data The status data to set the bots status to.
* @returns Promise<void>
*/
editShardStatus: (shardId: number, data: StatusUpdate) => Promise<void>
/**
* Fetches the list of members for a guild over the gateway.
*
* @param guildId - The ID of the guild to get the list of members for.
* @param options - The parameters for the fetching of the members.
*
* @remarks
* If requesting the entire member list:
* - Requires the `GUILD_MEMBERS` intent.
*
* If requesting presences ({@link RequestGuildMembers.presences | presences} set to `true`):
* - Requires the `GUILD_PRESENCES` intent.
*
* If requesting a prefix ({@link RequestGuildMembers.query | query} non-`undefined`):
* - Returns a maximum of 100 members.
*
* If requesting a users by ID ({@link RequestGuildMembers.userIds | userIds} non-`undefined`):
* - Returns a maximum of 100 members.
*
* Fires a _Guild Members Chunk_ gateway event for every 1000 members fetched.
*
* @see {@link https://discord.com/developers/docs/topics/gateway#request-guild-members}
*/
requestMembers: (guildId: BigString, options?: Omit<RequestGuildMembers, 'guildId'>) => Promise<Camelize<DiscordMember[]>>
}
export interface RequestMemberRequest {
/** The unique nonce for this request. */
nonce: string
/** The resolver handler to run when all members arrive. */
resolve: (value: Camelize<DiscordMember[]> | PromiseLike<Camelize<DiscordMember[]>>) => void
/** The members that have already arrived for this request. */
members: Camelize<DiscordMember[]>
}

View File

@@ -1,4 +1,4 @@
import type { ActivityTypes, Camelize, DiscordGatewayPayload, GatewayOpcodes, PresenceStatus } from '@discordeno/types'
import type { ActivityTypes, Camelize, DiscordActivity, DiscordGatewayPayload, GatewayOpcodes, PresenceStatus } from '@discordeno/types'
import type Shard from './Shard.js'
export enum ShardState {
@@ -167,3 +167,15 @@ export interface UpdateVoiceState {
/** Is the client deafened */
selfDeaf: boolean
}
/** https://discord.com/developers/docs/topics/gateway-events#update-presence */
export interface StatusUpdate {
// /** Unix time (in milliseconds) of when the client went idle, or null if the client is not idle */
// since: number | null;
/** The user's activities */
activities: Camelize<DiscordActivity[]>
/** The user's new status */
status: keyof typeof PresenceStatus
// /** Whether or not the client is afk */
// afk: boolean;
}

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable no-const-assign */
import { InteractionResponseTypes } from '@discordeno/types'
import { DiscordGuildWidget, InteractionResponseTypes } from '@discordeno/types'
import {
calculateBits,
camelize,
@@ -53,6 +53,8 @@ import type {
DiscordFollowedChannel,
DiscordGetGatewayBot,
DiscordGuild,
DiscordGuildPreview,
DiscordGuildWidgetSettings,
DiscordIntegration,
DiscordInvite,
DiscordInviteMetadata,
@@ -61,6 +63,8 @@ import type {
DiscordMember,
DiscordMemberWithUser,
DiscordMessage,
DiscordModifyGuildWelcomeScreen,
DiscordPrunedCount,
DiscordRole,
DiscordScheduledEvent,
DiscordStageInstance,
@@ -72,6 +76,7 @@ import type {
DiscordVanityUrl,
DiscordVoiceRegion,
DiscordWebhook,
DiscordWelcomeScreen,
EditAutoModerationRuleOptions,
EditChannelPermissionOverridesOptions,
EditGuildRole,
@@ -175,6 +180,9 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
dm: () => {
return '/users/@me/channels'
},
pins: (channelId) => {
return `/channels/${channelId}/pins`
},
reactions: {
bot: (channelId, messageId, emoji) => {
return `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}/@me`
@@ -195,6 +203,18 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
if (options.limit) url += `&limit=${options.limit}`
}
return url
},
message: (channelId, messageId, emoji, options) => {
let url = `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}?`
if (options) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
if (options.after) url += `after=${options.after}`
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
if (options.limit) url += `&limit=${options.limit}`
}
return url
},
},
@@ -505,6 +525,26 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
},
},
mfa: (guildId) => `/guilds/${guildId}/mfa`,
preview: (guildId) => {
return `/guilds/${guildId}/preview`
},
prune: (guildId, options) => {
let url = `/guilds/${guildId}/prune?`
if (options) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
if (options.days) url += `days=${options.days}`
if (Array.isArray(options.includeRoles)) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
url += `&include_roles=${options.includeRoles.join(',')}`
} else if (options.includeRoles) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
url += `&include_roles=${options.includeRoles}`
}
}
return url
},
roles: {
one: (guildId, roleId) => {
return `/guilds/${guildId}/roles/${roleId}`
@@ -545,12 +585,25 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
webhooks: (guildId) => {
return `/guilds/${guildId}/webhooks`
},
welcome: (guildId) => {
return `/guilds/${guildId}/welcome-screen`
},
widget: (guildId) => {
return `/guilds/${guildId}/widget`
},
widgetJson: (guildId) => {
return `/guilds/${guildId}/widget.json`
},
},
sticker: (stickerId: BigString) => {
return `/stickers/${stickerId}`
},
regions: () => {
return '/voice/regions'
},
// Interaction Endpoints
interactions: {
commands: {
@@ -1235,7 +1288,6 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
)
},
/** Modify a guild's MFA level. Requires guild ownership. */
async editGuildMfaLevel(guildId: BigString, mfaLevel: MfaLevels, reason?: string): Promise<void> {
return await rest.post(rest.routes.guilds.mfa(guildId), { level: mfaLevel, reason })
},
@@ -1309,6 +1361,14 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.patch<DiscordWebhook>(rest.routes.webhooks.webhook(webhookId, token), options)
},
async editWelcomeScreen(guildId, options) {
return await rest.patch<DiscordWelcomeScreen>(rest.routes.guilds.welcome(guildId), options)
},
async editWidgetSettings(guildId, options) {
return await rest.patch<DiscordGuildWidgetSettings>(rest.routes.guilds.widget(guildId), options)
},
async executeWebhook(webhookId, token, options) {
return await rest.post<DiscordMessage>(rest.routes.webhooks.webhook(webhookId, token, options), options)
},
@@ -1349,6 +1409,10 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.get<DiscordAutoModerationRule[]>(rest.routes.guilds.automod.rules(guildId))
},
async getAvailableVoiceRegions() {
return await rest.get<DiscordVoiceRegion[]>(rest.routes.regions())
},
async getBan(guildId, userId) {
return await rest.get<DiscordBan>(rest.routes.guilds.members.ban(guildId, userId))
},
@@ -1415,6 +1479,10 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.get<DiscordApplicationCommand[]>(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId))
},
async getGuildPreview(guildId) {
return await rest.get<DiscordGuildPreview>(rest.routes.guilds.preview(guildId))
},
async getGuildTemplate(templateCode) {
return await rest.get<DiscordTemplate>(rest.routes.guilds.templates.code(templateCode))
},
@@ -1439,6 +1507,14 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.get<DiscordInviteMetadata[]>(rest.routes.guilds.invites(guildId))
},
async getMessage(channelId, messageId) {
return await rest.get<DiscordMessage>(rest.routes.channels.message(channelId, messageId))
},
async getMessages(channelId, options) {
return await rest.get<DiscordMessage[]>(rest.routes.channels.messages(channelId, options))
},
async getNitroStickerPacks() {
return await rest.get<DiscordStickerPack[]>(rest.routes.nitroStickerPacks())
},
@@ -1447,6 +1523,10 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.get<DiscordMessage>(rest.routes.interactions.responses.original(rest.applicationId, token))
},
async getPinnedMessages(channelId) {
return await rest.get<DiscordMessage[]>(rest.routes.channels.pins(channelId))
},
async getPrivateArchivedThreads(channelId, options) {
return await rest.get<DiscordListArchivedThreads>(rest.routes.channels.threads.private(channelId, options))
},
@@ -1455,6 +1535,10 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.get<DiscordListArchivedThreads>(rest.routes.channels.threads.joined(channelId, options))
},
async getPruneCount(guildId, options) {
return await rest.get<DiscordPrunedCount>(rest.routes.guilds.prune(guildId, options))
},
async getPublicArchivedThreads(channelId, options) {
return await rest.get<DiscordListArchivedThreads>(rest.routes.channels.threads.public(channelId, options))
},
@@ -1503,6 +1587,10 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.get<DiscordThreadMember[]>(rest.routes.channels.threads.members(channelId))
},
async getReactions(channelId, messageId, reaction, options) {
return await rest.get<DiscordUser[]>(rest.routes.channels.reactions.message(channelId, messageId, reaction, options))
},
async getUser(id) {
return await rest.get<DiscordUser>(rest.routes.user(id))
},
@@ -1527,6 +1615,18 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.get<DiscordWebhook>(rest.routes.webhooks.webhook(webhookId, token))
},
async getWelcomeScreen(guildId) {
return await rest.get<DiscordWelcomeScreen>(rest.routes.guilds.welcome(guildId))
},
async getWidget(guildId) {
return await rest.get<DiscordGuildWidget>(rest.routes.guilds.widgetJson(guildId))
},
async getWidgetSettings(guildId) {
return await rest.get<DiscordGuildWidgetSettings>(rest.routes.guilds.widget(guildId))
},
async joinThread(channelId) {
return await rest.put(rest.routes.channels.threads.me(channelId))
},
@@ -1730,6 +1830,8 @@ export interface RestManager {
bulk: (channelId: BigString) => string
/** Route for non-specific dm channel. */
dm: () => string
/** Route for handling a channels pins. */
pins: (channelId: BigString) => string
/** Route for non-specific webhook in a channel. */
webhooks: (channelId: BigString) => string
/** Route for a specific channel. */
@@ -1787,6 +1889,8 @@ export interface RestManager {
all: (channelId: BigString, messageId: BigString) => string
/** Route for handling all reactions for a single emoji on a message. */
emoji: (channelId: BigString, messageId: BigString, emoji: string, options?: GetReactions) => string
/** Route for handling a specific reaction on a message. */
message: (channelId: BigString, messageId: BigString, emoji: string, options?: GetReactions) => string
}
}
/** Routes for guild related endpoints. */
@@ -1827,8 +1931,18 @@ export interface RestManager {
invite: (inviteCode: string, options?: GetInvite) => string
/** Route for handling non-specific invites in a guild. */
invites: (guildId: BigString) => string
/** Route for handling a guild's preview. */
preview: (guildId: BigString) => string
/** Route for handling pruning of a guild. */
prune: (guildId: BigString, options?: GetGuildPruneCountQuery) => string
/** Route for handling non-specific webhooks in a guild */
webhooks: (guildId: BigString) => string
/** Route for handling a guild's welcome screen. */
welcome: (guildId: BigString) => string
/** Route for handling a guild's widget. */
widget: (guildId: BigString) => string
/** Route for handling a guild's widget in the form of json. */
widgetJson: (guildId: BigString) => string
/** Route for handling a guilds mfa level. */
mfa: (guildId: BigString) => string
/** Routes for handling a guild's members. */
@@ -1909,6 +2023,8 @@ export interface RestManager {
}
/** Route for handling a sticker. */
sticker: (stickerId: BigString) => string
/** Route for handling all voice regions. */
regions: () => string
}
/** Check the rate limits for a url or a bucket. */
checkRateLimits: (url: string) => number | false
@@ -2873,7 +2989,6 @@ export interface RestManager {
/**
* Edits the voice state of the bot user.
*
* @param rest - The rest manager to use to make the request.
* @param guildId - The ID of the guild in which to edit the voice state of the bot user.
* @param options - The parameters for the edit of the voice state.
*
@@ -3016,6 +3131,35 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/resources/webhook#modify-webhook-with-token}
*/
editWebhookWithToken: (webhookId: BigString, token: string, options: Omit<ModifyWebhook, 'channelId'>) => Promise<Camelize<DiscordWebhook>>
/**
* Edits a guild's welcome screen.
*
* @param guildId - The ID of the guild to edit the welcome screen of.
* @param options - The parameters for the edit of the welcome screen.
* @returns An instance of the edited {@link WelcomeScreen}.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* Fires a _Guild Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-welcome-screen}
*/
editWelcomeScreen: (guildId: BigString, options: Camelize<DiscordModifyGuildWelcomeScreen>) => Promise<Camelize<DiscordWelcomeScreen>>
/**
* Edits the settings of a guild's widget.
*
* @param guildId - The ID of the guild to edit the settings of the widget of.
* @returns An instance of the edited {@link GuildWidgetSettings}.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* Fires a _Guild Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-widget}
*/
editWidgetSettings: (guildId: BigString, options: Camelize<DiscordGuildWidgetSettings>) => Promise<Camelize<DiscordGuildWidgetSettings>>
/**
* Executes a webhook, causing a message to be posted in the channel configured for the webhook.
*
@@ -3118,6 +3262,12 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/resources/auto-moderation#list-auto-moderation-rules-for-guild}
*/
getAutomodRules: (guildId: BigString) => Promise<Camelize<DiscordAutoModerationRule[]>>
/**
* Gets the list of available voice regions.
*
* @returns A collection of {@link VoiceRegions | VoiceRegion} objects assorted by voice region ID.
*/
getAvailableVoiceRegions: () => Promise<Camelize<DiscordVoiceRegion[]>>
/**
* Gets a ban by user ID.
*
@@ -3289,6 +3439,18 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/interactions/application-commands#get-global-application-commandss}
*/
getGuildApplicationCommands: (guildId: BigString) => Promise<Camelize<DiscordApplicationCommand[]>>
/**
* Gets the preview of a guild by a guild's ID.
*
* @param guildId - The ID of the guild to get the preview of.
* @returns An instance of {@link GuildPreview}.
*
* @remarks
* If the bot user is not in the guild, the guild must be lurkable.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-preview}
*/
getGuildPreview: (guildId: BigString) => Promise<Camelize<DiscordGuildPreview>>
/**
* Returns a sticker object for the given guild and sticker IDs.
*
@@ -3382,6 +3544,38 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/resources/invite#get-invites}
*/
getInvites: (guildId: BigString) => Promise<Camelize<DiscordInviteMetadata[]>>
/**
* Gets a message from a channel by the ID of the message.
*
* @param channelId - The ID of the channel from which to get the message.
* @param messageId - The ID of the message to get.
* @returns An instance of {@link Message}.
*
* @remarks
* Requires that the bot user be able to see the contents of the channel in which the message was posted.
*
* If getting a message from a guild channel:
* - Requires the `READ_MESSAGE_HISTORY` permission.
*
* @see {@link https://discord.com/developers/docs/resources/channel#get-channel-message}
*/
getMessage: (channelId: BigString, messageId: BigString) => Promise<Camelize<DiscordMessage>>
/**
* Gets multiple messages from a channel.
*
* @param channelId - The ID of the channel from which to get the messages.
* @param options - The parameters for the fetching of the messages.
* @returns A collection of {@link Message} objects assorted by message ID.
*
* @remarks
* Requires that the bot user be able to see the contents of the channel in which the messages were posted.
*
* If getting a messages from a guild channel:
* - Requires the `READ_MESSAGE_HISTORY` permission.
*
* @see {@link https://discord.com/developers/docs/resources/channel#get-channel-messages}
*/
getMessages: (channelId: BigString, options?: GetMessagesOptions) => Promise<Camelize<DiscordMessage[]>>
/**
* Returns the list of sticker packs available to Nitro subscribers.
*
@@ -3407,6 +3601,21 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#get-original-interaction-response}
*/
getOriginalInteractionResponse: (token: string) => Promise<Camelize<DiscordMessage>>
/**
* Gets the pinned messages for a channel.
*
* @param channelId - The ID of the channel to get the pinned messages for.
* @returns A collection of {@link Message} objects assorted by message ID.
*
* @remarks
* Requires that the bot user be able to see the contents of the channel in which the messages were posted.
*
* If getting a message from a guild channel:
* - Requires the `READ_MESSAGE_HISTORY` permission.
*
* @see {@link https://discord.com/developers/docs/resources/channel#get-pinned-messages}
*/
getPinnedMessages: (channelId: BigString) => Promise<Camelize<DiscordMessage[]>>
/**
* Gets the list of private archived threads for a channel.
*
@@ -3442,6 +3651,19 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/resources/channel#list-joined-private-archived-threads}
*/
getPrivateJoinedArchivedThreads: (channelId: BigString, options?: ListArchivedThreads) => Promise<Camelize<DiscordArchivedThreads>>
/**
* Gets the number of members that would be kicked from a guild during pruning.
*
* @param guildId - The ID of the guild to get the prune count of.
* @param options - The parameters for the fetching of the prune count.
* @returns A number indicating the number of members that would be kicked.
*
* @remarks
* Requires the `KICK_MEMBERS` permission.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-prune-count}
*/
getPruneCount: (guildId: BigString, options?: GetGuildPruneCountQuery) => Promise<Camelize<DiscordPrunedCount>>
/**
* Gets the list of public archived threads for a channel.
*
@@ -3555,6 +3777,18 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/resources/channel#list-thread-members}
*/
getThreadMembers: (channelId: BigString) => Promise<Camelize<DiscordThreadMember[]>>
/**
* Gets the list of users that reacted with an emoji to a message.
*
* @param channelId - The ID of the channel the message to get the users for is in.
* @param messageId - The ID of the message to get the users for.
* @param reaction - The reaction for which to get the users.
* @param options - The parameters for the fetching of the users.
* @returns A collection of {@link User} objects assorted by user ID.
*
* @see {@link https://discord.com/developers/docs/resources/channel#get-reactions}
*/
getReactions: (channelId: BigString, messageId: BigString, reaction: string, options?: GetReactions) => Promise<Camelize<DiscordUser[]>>
/**
* Get a user's data from the api
*
@@ -3624,6 +3858,40 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/resources/webhook#get-webhook-with-token}
*/
getWebhookWithToken: (webhookId: BigString, token: string) => Promise<Camelize<DiscordWebhook>>
/**
* Gets the welcome screen for a guild.
*
* @param guildId - The ID of the guild to get the welcome screen for.
* @returns An instance of {@link WelcomeScreen}.
*
* @remarks
* If the welcome screen is not enabled:
* - Requires the `MANAGE_GUILD` permission.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-welcome-screen}
*/
getWelcomeScreen: (guildId: BigString) => Promise<Camelize<DiscordWelcomeScreen>>
/**
* Gets the guild widget by guild ID.
*
* @param guildId - The ID of the guild to get the widget of.
* @returns An instance of {@link GuildWidget}.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-widget}
*/
getWidget: (guildId: BigString) => Promise<Camelize<DiscordGuildWidget>>
/**
* Gets the settings of a guild's widget.
*
* @param guildId - The ID of the guild to get the widget of.
* @returns An instance of {@link GuildWidgetSettings}.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-widget-settings}
*/
getWidgetSettings: (guildId: BigString) => Promise<Camelize<DiscordGuildWidgetSettings>>
/**
* Adds the bot user to a thread.
*

View File

@@ -1964,26 +1964,26 @@ export interface DiscordApplicationCommandPermissions {
permission: boolean
}
// /** https://discord.com/developers/docs/resources/guild#get-guild-widget-example-get-guild-widget */
// export interface DiscordGuildWidget {
// id: string
// name: string
// instant_invite: string
// channels: Array<{
// id: string
// name: string
// position: number
// }>
// members: Array<{
// id: string
// username: string
// discriminator: string
// avatar?: string | null
// status: string
// avatar_url: string
// }>
// presence_count: number
// }
/** https://discord.com/developers/docs/resources/guild#get-guild-widget-example-get-guild-widget */
export interface DiscordGuildWidget {
id: string
name: string
instant_invite: string
channels: Array<{
id: string
name: string
position: number
}>
members: Array<{
id: string
username: string
discriminator: string
avatar?: string | null
status: string
avatar_url: string
}>
presence_count: number
}
/** https://discord.com/developers/docs/resources/guild#guild-preview-object */
export interface DiscordGuildPreview {
@@ -2467,12 +2467,12 @@ export interface DiscordVoiceRegion {
custom: boolean
}
// export interface DiscordGuildWidgetSettings {
// /** whether the widget is enabled */
// enabled: boolean
// /** the widget channel id */
// channel_id: string | null
// }
export interface DiscordGuildWidgetSettings {
/** whether the widget is enabled */
enabled: boolean
/** the widget channel id */
channel_id: string | null
}
export interface DiscordInstallParams {
/** the scopes to add the application to the server with */
@@ -2886,15 +2886,15 @@ export interface DiscordCreateMessage {
// level: MfaLevels
// }
// /** https://discord.com/developers/docs/resources/guild#modify-guild-welcome-screen */
// export interface DiscordModifyGuildWelcomeScreen {
// /** Whether the welcome screen is enabled */
// enabled?: boolean | null
// /** Channels linked in the welcome screen and their display options */
// welcome_screen?: DiscordWelcomeScreenChannel[] | null
// /** The server description to show in the welcome screen */
// description?: string | null
// }
/** https://discord.com/developers/docs/resources/guild#modify-guild-welcome-screen */
export interface DiscordModifyGuildWelcomeScreen {
/** Whether the welcome screen is enabled */
enabled?: boolean | null
/** Channels linked in the welcome screen and their display options */
welcome_screen?: DiscordWelcomeScreenChannel[] | null
/** The server description to show in the welcome screen */
description?: string | null
}
// export interface DiscordStartThreadWithMessage {
// /** 1-100 character thread name */
@@ -3147,4 +3147,8 @@ export interface DiscordActiveThreads {
export interface DiscordVanityUrl {
code: string | null
uses: number
}
export interface DiscordPrunedCount {
pruned: number
}

View File

@@ -1087,3 +1087,17 @@ export interface EditUserVoiceState {
/** The user id to target */
userId: BigString
}
/** https://discord.com/developers/docs/resources/guild#get-guild-widget-image-query-string-params */
export interface GetGuildWidgetImageQuery {
/**
* Style of the widget returned, default: shield
*
* Shield: Widget with Discord icon and guild members online count.
* Banner1: Large image with guild icon, name and online count. "POWERED BY DISCORD" as the footer of the widget
* Banner2: Smaller widget style with guild icon, name and online count. Split on the right with Discord logo
* Banner3: Large image with guild icon, name and online count. In the footer, Discord logo on the left and "Chat Now" on the right
* Banner4: Large Discord logo at the top of the widget. Guild icon, name and online count in the middle portion of the widget and a "JOIN MY SERVER" button at the bottom
*/
style?: 'shield' | 'banner1' | 'banner2' | 'banner3' | 'banner4'
}

View File

@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import type { BigString, ImageFormat, ImageSize } from '@discordeno/types'
import type { BigString, GetGuildWidgetImageQuery, ImageFormat, ImageSize } from '@discordeno/types'
import { iconBigintToHash } from './hash.js'
/** Help format an image url. */
@@ -120,3 +120,23 @@ export function guildSplashUrl(
)
: undefined
}
/**
* Builds a URL to the guild widget image stored in the Discord CDN.
*
* @param guildId - The ID of the guild to get the link to the widget image for.
* @param options - The parameters for the building of the URL.
* @returns The link to the resource.
*/
export function getWidgetImageUrl (
guildId: BigString,
options?: GetGuildWidgetImageQuery
): string {
let url = `https://cdn.discordapp.com/guilds/${guildId}/widget.png`
if (options?.style) {
url += `?style=${options.style}`
}
return url
}