feat: add helpers to rest

This commit is contained in:
H01001000
2022-12-05 05:33:54 +08:00
parent 639d14cfe2
commit c271a85627
213 changed files with 9364 additions and 276 deletions

View File

@@ -1,39 +1,192 @@
import { calculateShardId, createGatewayManager, CreateShardManager, ShardSocketCloseCodes } from '@discordeno/gateway'
import {
calculateShardId,
createGatewayManager,
CreateShardManager,
ShardSocketCloseCodes
} from '@discordeno/gateway'
import { createRestManager, CreateRestManagerOptions } from '@discordeno/rest'
import {
AllowedMentions, BigString, DiscordActivity, DiscordAllowedMentions, DiscordApplication, DiscordApplicationCommand, DiscordApplicationCommandOption, DiscordApplicationCommandOptionChoice, DiscordAttachment, DiscordAuditLogEntry, DiscordAutoModerationActionExecution, DiscordAutoModerationRule, DiscordChannel, DiscordComponent, DiscordCreateApplicationCommand, DiscordEmbed, DiscordEmoji, DiscordGatewayPayload, DiscordGetGatewayBot, DiscordGuild, DiscordGuildApplicationCommandPermissions, DiscordGuildWidget, DiscordGuildWidgetSettings, DiscordIntegrationCreateUpdate, DiscordInteraction, DiscordInteractionDataOption, DiscordInteractionResponse, DiscordInviteCreate, DiscordMember, DiscordMessage, DiscordPresenceUpdate, DiscordReady, DiscordRole, DiscordScheduledEvent, DiscordStageInstance, DiscordSticker, DiscordStickerPack, DiscordTeam, DiscordTemplate, DiscordThreadMember, DiscordUser, DiscordVoiceRegion, DiscordVoiceState, DiscordWebhook, DiscordWelcomeScreen, Errors, GatewayDispatchEventNames, GatewayIntents, GetGatewayBot
AllowedMentions,
BigString,
DiscordActivity,
DiscordAllowedMentions,
DiscordApplication,
DiscordApplicationCommand,
DiscordApplicationCommandOption,
DiscordApplicationCommandOptionChoice,
DiscordAttachment,
DiscordAuditLogEntry,
DiscordAutoModerationActionExecution,
DiscordAutoModerationRule,
DiscordChannel,
DiscordComponent,
DiscordCreateApplicationCommand,
DiscordEmbed,
DiscordEmoji,
DiscordGatewayPayload,
DiscordGetGatewayBot,
DiscordGuild,
DiscordGuildApplicationCommandPermissions,
DiscordGuildWidget,
DiscordGuildWidgetSettings,
DiscordIntegrationCreateUpdate,
DiscordInteraction,
DiscordInteractionDataOption,
DiscordInteractionResponse,
DiscordInviteCreate,
DiscordMember,
DiscordMessage,
DiscordPresenceUpdate,
DiscordReady,
DiscordRole,
DiscordScheduledEvent,
DiscordStageInstance,
DiscordSticker,
DiscordStickerPack,
DiscordTeam,
DiscordTemplate,
DiscordThreadMember,
DiscordUser,
DiscordVoiceRegion,
DiscordVoiceState,
DiscordWebhook,
DiscordWelcomeScreen,
Errors,
GatewayDispatchEventNames,
GatewayIntents,
GetGatewayBot
} from '@discordeno/types'
import {
baseEndpoints, bigintToSnowflake, calculateBits, calculatePermissions, CHANNEL_MENTION_REGEX, Collection, CONTEXT_MENU_COMMANDS_NAME_REGEX, delay, DISCORDENO_VERSION, DISCORD_SNOWFLAKE_REGEX, getBotIdFromToken, iconBigintToHash, iconHashToBigInt, removeTokenPrefix, SLASH_COMMANDS_NAME_REGEX, snowflakeToBigint, urlToBase64, USER_AGENT, validateLength
baseEndpoints,
bigintToSnowflake,
calculateBits,
calculatePermissions,
CHANNEL_MENTION_REGEX,
Collection,
CONTEXT_MENU_COMMANDS_NAME_REGEX,
delay,
DISCORDENO_VERSION,
DISCORD_SNOWFLAKE_REGEX,
formatImageURL,
getBotIdFromToken,
iconBigintToHash,
iconHashToBigInt,
removeTokenPrefix,
SLASH_COMMANDS_NAME_REGEX,
snowflakeToBigint,
urlToBase64,
USER_AGENT,
validateLength
} from '@discordeno/utils'
import * as handlers from './handlers/index.js'
import * as helpers from './helpers/index.js'
import { Activity, transformActivity } from './transformers/activity.js'
import { Application, transformApplication } from './transformers/application.js'
import { ApplicationCommand, transformApplicationCommand } from './transformers/applicationCommand.js'
import { ApplicationCommandOption, transformApplicationCommandOption } from './transformers/applicationCommandOption.js'
import { ApplicationCommandPermission, transformApplicationCommandPermission } from './transformers/applicationCommandPermission.js'
import {
Application,
transformApplication
} from './transformers/application.js'
import {
ApplicationCommand,
transformApplicationCommand
} from './transformers/applicationCommand.js'
import {
ApplicationCommandOption,
transformApplicationCommandOption
} from './transformers/applicationCommandOption.js'
import {
ApplicationCommandPermission,
transformApplicationCommandPermission
} from './transformers/applicationCommandPermission.js'
import { Attachment, transformAttachment } from './transformers/attachment.js'
import { AuditLogEntry, transformAuditLogEntry } from './transformers/auditLogEntry.js'
import {
AuditLogEntry,
transformAuditLogEntry
} from './transformers/auditLogEntry.js'
import { Component, transformComponent } from './transformers/component.js'
import { Embed, transformEmbed } from './transformers/embed.js'
import { Emoji, transformEmoji } from './transformers/emoji.js'
import { transformGatewayBot } from './transformers/gatewayBot.js'
import {
ApplicationCommandOptionChoice, AutoModerationActionExecution, AutoModerationRule, Channel, Guild, GuildWidget, GuildWidgetSettings, Integration, Interaction, InteractionDataOption, Invite, Member, Message, PresenceUpdate, Role, ScheduledEvent, StageInstance, Sticker, StickerPack, Team, Template, ThreadMember, transformActivityToDiscordActivity, transformAllowedMentionsToDiscordAllowedMentions, transformApplicationCommandOptionChoice, transformApplicationCommandOptionChoiceToDiscordApplicationCommandOptionChoice, transformApplicationCommandOptionToDiscordApplicationCommandOption, transformApplicationCommandToDiscordApplicationCommand, transformApplicationToDiscordApplication, transformAttachmentToDiscordAttachment, transformAutoModerationActionExecution, transformAutoModerationRule, transformChannel, transformComponentToDiscordComponent, transformCreateApplicationCommandToDiscordCreateApplicationCommand, transformEmbedToDiscordEmbed, transformGuild, transformIntegration, transformInteraction, transformInteractionDataOption, transformInteractionResponseToDiscordInteractionResponse, transformInvite, transformMember, transformMemberToDiscordMember, transformMessage, transformPresence, transformRole, transformScheduledEvent, transformStageInstance, transformSticker, transformStickerPack, transformTeam, transformTeamToDiscordTeam, transformTemplate, transformThreadMember, transformUser, transformUserToDiscordUser, transformVoiceRegion, transformVoiceState, transformWebhook, transformWelcomeScreen, transformWidget, transformWidgetSettings, User, VoiceRegions, VoiceState, Webhook, WelcomeScreen
ApplicationCommandOptionChoice,
AutoModerationActionExecution,
AutoModerationRule,
Channel,
Guild,
GuildWidget,
GuildWidgetSettings,
Integration,
Interaction,
InteractionDataOption,
Invite,
Member,
Message,
PresenceUpdate,
Role,
ScheduledEvent,
StageInstance,
Sticker,
StickerPack,
Team,
Template,
ThreadMember,
transformActivityToDiscordActivity,
transformAllowedMentionsToDiscordAllowedMentions,
transformApplicationCommandOptionChoice,
transformApplicationCommandOptionChoiceToDiscordApplicationCommandOptionChoice,
transformApplicationCommandOptionToDiscordApplicationCommandOption,
transformApplicationCommandToDiscordApplicationCommand,
transformApplicationToDiscordApplication,
transformAttachmentToDiscordAttachment,
transformAutoModerationActionExecution,
transformAutoModerationRule,
transformChannel,
transformComponentToDiscordComponent,
transformCreateApplicationCommandToDiscordCreateApplicationCommand,
transformEmbedToDiscordEmbed,
transformGuild,
transformIntegration,
transformInteraction,
transformInteractionDataOption,
transformInteractionResponseToDiscordInteractionResponse,
transformInvite,
transformMember,
transformMemberToDiscordMember,
transformMessage,
transformPresence,
transformRole,
transformScheduledEvent,
transformStageInstance,
transformSticker,
transformStickerPack,
transformTeam,
transformTeamToDiscordTeam,
transformTemplate,
transformThreadMember,
transformUser,
transformUserToDiscordUser,
transformVoiceRegion,
transformVoiceState,
transformWebhook,
transformWelcomeScreen,
transformWidget,
transformWidgetSettings,
User,
VoiceRegions,
VoiceState,
Webhook,
WelcomeScreen
} from './transformers/index.js'
import {
CreateApplicationCommand,
InteractionResponse
} from './types.js'
import { CreateApplicationCommand, InteractionResponse } from './types.js'
import { routes } from './utils/routes.js'
import { formatImageURL } from './utils/utils.js'
export function createBot (options: CreateBotOptions): Bot {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const bot = {
id: options.botId ?? getBotIdFromToken(options.token),
applicationId: options.applicationId ?? options.botId ?? getBotIdFromToken(options.token),
applicationId:
options.applicationId ??
options.botId ??
getBotIdFromToken(options.token),
token: removeTokenPrefix(options.token),
events: createEventHandlers(options.events ?? {}),
intents: options.intents,
@@ -58,7 +211,7 @@ export function createBot (options: CreateBotOptions): Bot {
bot.helpers = createHelpers(bot, options.helpers ?? {})
bot.gateway = createGatewayManager({
gatewayBot: bot.botGatewayData ?? {} as any,
gatewayBot: bot.botGatewayData ?? ({} as any),
gatewayConfig: {
token: options.token,
intents: options.intents
@@ -66,7 +219,8 @@ export function createBot (options: CreateBotOptions): Bot {
debug: bot.events.debug,
handleDiscordPayload: bot.handleDiscordPayload ??
handleDiscordPayload:
bot.handleDiscordPayload ??
async function (shard, data: DiscordGatewayPayload) {
// TRIGGER RAW EVENT
bot.events.raw(bot, data, shard.id)
@@ -89,7 +243,7 @@ export function createBot (options: CreateBotOptions): Bot {
export function createEventHandlers (
events: Partial<EventHandlers>
): EventHandlers {
function ignore (): void { }
function ignore (): void {}
return {
debug: events.debug ?? ignore,
@@ -194,7 +348,10 @@ export interface HelperUtils {
}
export async function stopBot (bot: Bot): Promise<Bot> {
await bot.gateway.stop(ShardSocketCloseCodes.Shutdown, 'User requested bot stop')
await bot.gateway.stop(
ShardSocketCloseCodes.Shutdown,
'User requested bot stop'
)
return bot
}
@@ -214,7 +371,8 @@ export interface CreateBotOptions {
helpers?: Partial<Helpers>
}
export type UnPromise<T extends Promise<unknown>> = T extends Promise<infer K> ? K
export type UnPromise<T extends Promise<unknown>> = T extends Promise<infer K>
? K
: never
export interface Bot {
@@ -244,7 +402,7 @@ export interface Bot {
export const defaultHelpers = { ...helpers }
export type DefaultHelpers = typeof defaultHelpers
// deno-lint-ignore no-empty-interface
export interface Helpers extends DefaultHelpers { } // Use interface for declaration merging
export interface Helpers extends DefaultHelpers {} // Use interface for declaration merging
export function createHelpers (
bot: Bot,
@@ -252,11 +410,9 @@ export function createHelpers (
): FinalHelpers {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const converted = {} as FinalHelpers
for (
const [name, fun] of Object.entries({
...createBaseHelpers(customHelpers ?? {})
})
) {
for (const [name, fun] of Object.entries({
...createBaseHelpers(customHelpers ?? {})
})) {
// @ts-expect-error - TODO: make the types better
converted[name as keyof FinalHelpers] = (
...args: RemoveFirstFromTuple<Parameters<typeof fun>>
@@ -268,7 +424,9 @@ export function createHelpers (
return converted
}
export function createBaseHelpers (options: Partial<Helpers>): DefaultHelpers & Partial<Helpers> {
export function createBaseHelpers (
options: Partial<Helpers>
): DefaultHelpers & Partial<Helpers> {
return {
...defaultHelpers,
...options
@@ -277,7 +435,10 @@ export function createBaseHelpers (options: Partial<Helpers>): DefaultHelpers &
export interface Transformers {
reverse: {
allowedMentions: (bot: Bot, payload: AllowedMentions) => DiscordAllowedMentions
allowedMentions: (
bot: Bot,
payload: AllowedMentions
) => DiscordAllowedMentions
embed: (bot: Bot, payload: Embed) => DiscordEmbed
component: (bot: Bot, payload: Component) => DiscordComponent
activity: (bot: Bot, payload: Activity) => DiscordActivity
@@ -286,30 +447,71 @@ export interface Transformers {
team: (bot: Bot, payload: Team) => DiscordTeam
application: (bot: Bot, payload: Application) => DiscordApplication
snowflake: (snowflake: BigString) => string
createApplicationCommand: (bot: Bot, payload: CreateApplicationCommand) => DiscordCreateApplicationCommand
applicationCommand: (bot: Bot, payload: ApplicationCommand) => DiscordApplicationCommand
applicationCommandOption: (bot: Bot, payload: ApplicationCommandOption) => DiscordApplicationCommandOption
createApplicationCommand: (
bot: Bot,
payload: CreateApplicationCommand
) => DiscordCreateApplicationCommand
applicationCommand: (
bot: Bot,
payload: ApplicationCommand
) => DiscordApplicationCommand
applicationCommandOption: (
bot: Bot,
payload: ApplicationCommandOption
) => DiscordApplicationCommandOption
applicationCommandOptionChoice: (
bot: Bot,
payload: ApplicationCommandOptionChoice,
payload: ApplicationCommandOptionChoice
) => DiscordApplicationCommandOptionChoice
interactionResponse: (bot: Bot, payload: InteractionResponse) => DiscordInteractionResponse
interactionResponse: (
bot: Bot,
payload: InteractionResponse
) => DiscordInteractionResponse
attachment: (bot: Bot, payload: Attachment) => DiscordAttachment
}
snowflake: (snowflake: BigString) => bigint
gatewayBot: (payload: DiscordGetGatewayBot) => GetGatewayBot
automodRule: (bot: Bot, payload: DiscordAutoModerationRule) => AutoModerationRule
automodActionExecution: (bot: Bot, payload: DiscordAutoModerationActionExecution) => AutoModerationActionExecution
channel: (bot: Bot, payload: { channel: DiscordChannel } & { guildId?: bigint }) => Channel
guild: (bot: Bot, payload: { guild: DiscordGuild } & { shardId: number }) => Guild
automodRule: (
bot: Bot,
payload: DiscordAutoModerationRule
) => AutoModerationRule
automodActionExecution: (
bot: Bot,
payload: DiscordAutoModerationActionExecution
) => AutoModerationActionExecution
channel: (
bot: Bot,
payload: { channel: DiscordChannel } & { guildId?: bigint }
) => Channel
guild: (
bot: Bot,
payload: { guild: DiscordGuild } & { shardId: number }
) => Guild
user: (bot: Bot, payload: DiscordUser) => User
member: (bot: Bot, payload: DiscordMember, guildId: bigint, userId: bigint) => Member
member: (
bot: Bot,
payload: DiscordMember,
guildId: bigint,
userId: bigint
) => Member
message: (bot: Bot, payload: DiscordMessage) => Message
role: (bot: Bot, payload: { role: DiscordRole } & { guildId: bigint }) => Role
voiceState: (bot: Bot, payload: { voiceState: DiscordVoiceState } & { guildId: bigint }) => VoiceState
role: (
bot: Bot,
payload: { role: DiscordRole } & { guildId: bigint }
) => Role
voiceState: (
bot: Bot,
payload: { voiceState: DiscordVoiceState } & { guildId: bigint }
) => VoiceState
interaction: (bot: Bot, payload: DiscordInteraction) => Interaction
interactionDataOptions: (bot: Bot, payload: DiscordInteractionDataOption) => InteractionDataOption
integration: (bot: Bot, payload: DiscordIntegrationCreateUpdate) => Integration
interactionDataOptions: (
bot: Bot,
payload: DiscordInteractionDataOption
) => InteractionDataOption
integration: (
bot: Bot,
payload: DiscordIntegrationCreateUpdate
) => Integration
invite: (bot: Bot, invite: DiscordInviteCreate) => Invite
application: (bot: Bot, payload: DiscordApplication) => Application
team: (bot: Bot, payload: DiscordTeam) => Team
@@ -321,24 +523,33 @@ export interface Transformers {
component: (bot: Bot, payload: DiscordComponent) => Component
webhook: (bot: Bot, payload: DiscordWebhook) => Webhook
auditLogEntry: (bot: Bot, payload: DiscordAuditLogEntry) => AuditLogEntry
applicationCommand: (bot: Bot, payload: DiscordApplicationCommand) => ApplicationCommand
applicationCommandOption: (bot: Bot, payload: DiscordApplicationCommandOption) => ApplicationCommandOption
applicationCommand: (
bot: Bot,
payload: DiscordApplicationCommand
) => ApplicationCommand
applicationCommandOption: (
bot: Bot,
payload: DiscordApplicationCommandOption
) => ApplicationCommandOption
applicationCommandPermission: (
bot: Bot,
payload: DiscordGuildApplicationCommandPermissions,
payload: DiscordGuildApplicationCommandPermissions
) => ApplicationCommandPermission
scheduledEvent: (bot: Bot, payload: DiscordScheduledEvent) => ScheduledEvent
threadMember: (bot: Bot, payload: DiscordThreadMember) => ThreadMember
welcomeScreen: (bot: Bot, payload: DiscordWelcomeScreen) => WelcomeScreen
voiceRegion: (bot: Bot, payload: DiscordVoiceRegion) => VoiceRegions
widget: (bot: Bot, payload: DiscordGuildWidget) => GuildWidget
widgetSettings: (bot: Bot, payload: DiscordGuildWidgetSettings) => GuildWidgetSettings
widgetSettings: (
bot: Bot,
payload: DiscordGuildWidgetSettings
) => GuildWidgetSettings
stageInstance: (bot: Bot, payload: DiscordStageInstance) => StageInstance
sticker: (bot: Bot, payload: DiscordSticker) => Sticker
stickerPack: (bot: Bot, payload: DiscordStickerPack) => StickerPack
applicationCommandOptionChoice: (
bot: Bot,
payload: DiscordApplicationCommandOptionChoice,
payload: DiscordApplicationCommandOptionChoice
) => ApplicationCommandOptionChoice
template: (bot: Bot, payload: DiscordTemplate) => Template
}
@@ -347,69 +558,85 @@ export interface Transformers {
export function createTransformers (options: Partial<Transformers>) {
return {
reverse: {
allowedMentions: options.reverse?.allowedMentions ?? transformAllowedMentionsToDiscordAllowedMentions,
allowedMentions:
options.reverse?.allowedMentions ??
transformAllowedMentionsToDiscordAllowedMentions,
embed: options.reverse?.embed ?? transformEmbedToDiscordEmbed,
component: options.reverse?.component ?? transformComponentToDiscordComponent,
component:
options.reverse?.component ?? transformComponentToDiscordComponent,
activity: options.reverse?.activity ?? transformActivityToDiscordActivity,
member: options.reverse?.member ?? transformMemberToDiscordMember,
user: options.reverse?.user ?? transformUserToDiscordUser,
team: options.reverse?.team ?? transformTeamToDiscordTeam,
application: options.reverse?.application ?? transformApplicationToDiscordApplication,
application:
options.reverse?.application ??
transformApplicationToDiscordApplication,
snowflake: options.reverse?.snowflake ?? bigintToSnowflake,
createApplicationCommand: options.reverse?.createApplicationCommand ??
createApplicationCommand:
options.reverse?.createApplicationCommand ??
transformCreateApplicationCommandToDiscordCreateApplicationCommand,
applicationCommand: options.reverse?.applicationCommand ??
applicationCommand:
options.reverse?.applicationCommand ??
transformApplicationCommandToDiscordApplicationCommand,
applicationCommandOption: options.reverse?.applicationCommandOption ??
applicationCommandOption:
options.reverse?.applicationCommandOption ??
transformApplicationCommandOptionToDiscordApplicationCommandOption,
applicationCommandOptionChoice: options.reverse?.applicationCommandOptionChoice ??
applicationCommandOptionChoice:
options.reverse?.applicationCommandOptionChoice ??
transformApplicationCommandOptionChoiceToDiscordApplicationCommandOptionChoice,
interactionResponse: options.reverse?.interactionResponse ??
interactionResponse:
options.reverse?.interactionResponse ??
transformInteractionResponseToDiscordInteractionResponse,
attachment: options.reverse?.attachment ?? transformAttachmentToDiscordAttachment
attachment:
options.reverse?.attachment ?? transformAttachmentToDiscordAttachment
},
automodRule: (options.automodRule) ?? transformAutoModerationRule,
automodActionExecution: (options.automodActionExecution) ?? transformAutoModerationActionExecution,
activity: (options.activity) ?? transformActivity,
application: (options.application) ?? transformApplication,
attachment: (options.attachment) ?? transformAttachment,
channel: (options.channel) ?? transformChannel,
component: (options.component) ?? transformComponent,
embed: (options.embed) ?? transformEmbed,
emoji: (options.emoji) ?? transformEmoji,
guild: (options.guild) ?? transformGuild,
integration: (options.integration) ?? transformIntegration,
interaction: (options.interaction) ?? transformInteraction,
interactionDataOptions: (options.interactionDataOptions) ?? transformInteractionDataOption,
invite: (options.invite) ?? transformInvite,
member: (options.member) ?? transformMember,
message: (options.message) ?? transformMessage,
presence: (options.presence) ?? transformPresence,
role: (options.role) ?? transformRole,
user: (options.user) ?? transformUser,
team: (options.team) ?? transformTeam,
voiceState: (options.voiceState) ?? transformVoiceState,
snowflake: (options.snowflake) ?? snowflakeToBigint,
webhook: (options.webhook) ?? transformWebhook,
auditLogEntry: (options.auditLogEntry) ?? transformAuditLogEntry,
applicationCommand: (options.applicationCommand) ??
transformApplicationCommand,
applicationCommandOption: (options.applicationCommandOption) ??
transformApplicationCommandOption,
applicationCommandPermission: (options.applicationCommandPermission) ??
automodRule: options.automodRule ?? transformAutoModerationRule,
automodActionExecution:
options.automodActionExecution ?? transformAutoModerationActionExecution,
activity: options.activity ?? transformActivity,
application: options.application ?? transformApplication,
attachment: options.attachment ?? transformAttachment,
channel: options.channel ?? transformChannel,
component: options.component ?? transformComponent,
embed: options.embed ?? transformEmbed,
emoji: options.emoji ?? transformEmoji,
guild: options.guild ?? transformGuild,
integration: options.integration ?? transformIntegration,
interaction: options.interaction ?? transformInteraction,
interactionDataOptions:
options.interactionDataOptions ?? transformInteractionDataOption,
invite: options.invite ?? transformInvite,
member: options.member ?? transformMember,
message: options.message ?? transformMessage,
presence: options.presence ?? transformPresence,
role: options.role ?? transformRole,
user: options.user ?? transformUser,
team: options.team ?? transformTeam,
voiceState: options.voiceState ?? transformVoiceState,
snowflake: options.snowflake ?? snowflakeToBigint,
webhook: options.webhook ?? transformWebhook,
auditLogEntry: options.auditLogEntry ?? transformAuditLogEntry,
applicationCommand:
options.applicationCommand ?? transformApplicationCommand,
applicationCommandOption:
options.applicationCommandOption ?? transformApplicationCommandOption,
applicationCommandPermission:
options.applicationCommandPermission ??
transformApplicationCommandPermission,
scheduledEvent: (options.scheduledEvent) ?? transformScheduledEvent,
threadMember: (options.threadMember) ?? transformThreadMember,
welcomeScreen: (options.welcomeScreen) ?? transformWelcomeScreen,
voiceRegion: (options.voiceRegion) ?? transformVoiceRegion,
widget: (options.widget) ?? transformWidget,
widgetSettings: (options.widgetSettings) ?? transformWidgetSettings,
stageInstance: (options.stageInstance) ?? transformStageInstance,
sticker: (options.sticker) ?? transformSticker,
stickerPack: (options.stickerPack) ?? transformStickerPack,
gatewayBot: (options.gatewayBot) ?? transformGatewayBot,
applicationCommandOptionChoice: (options.applicationCommandOptionChoice) ?? transformApplicationCommandOptionChoice,
template: (options.template) ?? transformTemplate
scheduledEvent: options.scheduledEvent ?? transformScheduledEvent,
threadMember: options.threadMember ?? transformThreadMember,
welcomeScreen: options.welcomeScreen ?? transformWelcomeScreen,
voiceRegion: options.voiceRegion ?? transformVoiceRegion,
widget: options.widget ?? transformWidget,
widgetSettings: options.widgetSettings ?? transformWidgetSettings,
stageInstance: options.stageInstance ?? transformStageInstance,
sticker: options.sticker ?? transformSticker,
stickerPack: options.stickerPack ?? transformStickerPack,
gatewayBot: options.gatewayBot ?? transformGatewayBot,
applicationCommandOptionChoice:
options.applicationCommandOptionChoice ??
transformApplicationCommandOptionChoice,
template: options.template ?? transformTemplate
}
}
@@ -418,15 +645,21 @@ export interface EventHandlers {
automodRuleCreate: (bot: Bot, rule: AutoModerationRule) => unknown
automodRuleUpdate: (bot: Bot, rule: AutoModerationRule) => unknown
automodRuleDelete: (bot: Bot, rule: AutoModerationRule) => unknown
automodActionExecution: (bot: Bot, payload: AutoModerationActionExecution) => unknown
automodActionExecution: (
bot: Bot,
payload: AutoModerationActionExecution
) => unknown
threadCreate: (bot: Bot, thread: Channel) => unknown
threadDelete: (bot: Bot, thread: Channel) => unknown
threadMemberUpdate: (bot: Bot, payload: {
id: bigint
guildId: bigint
joinedAt: number
flags: number
}) => unknown
threadMemberUpdate: (
bot: Bot,
payload: {
id: bigint
guildId: bigint
joinedAt: number
flags: number
}
) => unknown
threadMembersUpdate: (
bot: Bot,
payload: {
@@ -434,7 +667,7 @@ export interface EventHandlers {
guildId: bigint
addedMembers?: ThreadMember[]
removedMemberIds?: bigint[]
},
}
) => unknown
threadUpdate: (bot: Bot, thread: Channel) => unknown
scheduledEventCreate: (bot: Bot, event: ScheduledEvent) => unknown
@@ -447,7 +680,7 @@ export interface EventHandlers {
guildScheduledEventId: bigint
guildId: bigint
userId: bigint
},
}
) => unknown
/** Sent when a user has unsubscribed to a guild scheduled event. EXPERIMENTAL! */
scheduledEventUserRemove: (
@@ -456,7 +689,7 @@ export interface EventHandlers {
guildScheduledEventId: bigint
guildId: bigint
userId: bigint
},
}
) => unknown
ready: (
bot: Bot,
@@ -469,13 +702,13 @@ export interface EventHandlers {
shard?: number[]
applicationId: bigint
},
rawPayload: DiscordReady,
rawPayload: DiscordReady
) => unknown
interactionCreate: (bot: Bot, interaction: Interaction) => unknown
integrationCreate: (bot: Bot, integration: Integration) => unknown
integrationDelete: (
bot: Bot,
payload: { id: bigint, guildId: bigint, applicationId?: bigint },
payload: { id: bigint, guildId: bigint, applicationId?: bigint }
) => unknown
integrationUpdate: (bot: Bot, payload: { guildId: bigint }) => unknown
inviteCreate: (bot: Bot, invite: Invite) => unknown
@@ -485,31 +718,22 @@ export interface EventHandlers {
channelId: bigint
guildId?: bigint
code: string
},
) => unknown
guildMemberAdd: (
bot: Bot,
member: Member,
user: User,
}
) => unknown
guildMemberAdd: (bot: Bot, member: Member, user: User) => unknown
guildMemberRemove: (bot: Bot, user: User, guildId: bigint) => unknown
guildMemberUpdate: (
bot: Bot,
member: Member,
user: User,
) => unknown
guildMemberUpdate: (bot: Bot, member: Member, user: User) => unknown
messageCreate: (bot: Bot, message: Message) => unknown
messageDelete: (
bot: Bot,
payload: { id: bigint, channelId: bigint, guildId?: bigint },
message?: Message,
message?: Message
) => unknown
messageDeleteBulk: (bot: Bot, payload: { ids: bigint[], channelId: bigint, guildId?: bigint }) => unknown
messageUpdate: (
messageDeleteBulk: (
bot: Bot,
message: Message,
oldMessage?: Message,
payload: { ids: bigint[], channelId: bigint, guildId?: bigint }
) => unknown
messageUpdate: (bot: Bot, message: Message, oldMessage?: Message) => unknown
reactionAdd: (
bot: Bot,
payload: {
@@ -520,7 +744,7 @@ export interface EventHandlers {
member?: Member
user?: User
emoji: Emoji
},
}
) => unknown
reactionRemove: (
bot: Bot,
@@ -530,7 +754,7 @@ export interface EventHandlers {
messageId: bigint
guildId?: bigint
emoji: Emoji
},
}
) => unknown
reactionRemoveEmoji: (
bot: Bot,
@@ -539,7 +763,7 @@ export interface EventHandlers {
messageId: bigint
guildId?: bigint
emoji: Emoji
},
}
) => unknown
reactionRemoveAll: (
bot: Bot,
@@ -547,31 +771,28 @@ export interface EventHandlers {
channelId: bigint
messageId: bigint
guildId?: bigint
},
}
) => unknown
presenceUpdate: (
bot: Bot,
presence: PresenceUpdate,
oldPresence?: PresenceUpdate,
oldPresence?: PresenceUpdate
) => unknown
voiceServerUpdate: (
bot: Bot,
payload: { token: string, endpoint?: string, guildId: bigint },
) => unknown
voiceStateUpdate: (
bot: Bot,
voiceState: VoiceState,
payload: { token: string, endpoint?: string, guildId: bigint }
) => unknown
voiceStateUpdate: (bot: Bot, voiceState: VoiceState) => unknown
channelCreate: (bot: Bot, channel: Channel) => unknown
dispatchRequirements: (
bot: Bot,
data: DiscordGatewayPayload,
shardId: number,
shardId: number
) => unknown
channelDelete: (bot: Bot, channel: Channel) => unknown
channelPinsUpdate: (
bot: Bot,
data: { guildId?: bigint, channelId: bigint, lastPinTimestamp?: number },
data: { guildId?: bigint, channelId: bigint, lastPinTimestamp?: number }
) => unknown
channelUpdate: (bot: Bot, channel: Channel) => unknown
stageInstanceCreate: (
@@ -581,7 +802,7 @@ export interface EventHandlers {
guildId: bigint
channelId: bigint
topic: string
},
}
) => unknown
stageInstanceDelete: (
bot: Bot,
@@ -590,7 +811,7 @@ export interface EventHandlers {
guildId: bigint
channelId: bigint
topic: string
},
}
) => unknown
stageInstanceUpdate: (
bot: Bot,
@@ -599,14 +820,14 @@ export interface EventHandlers {
guildId: bigint
channelId: bigint
topic: string
},
}
) => unknown
guildEmojisUpdate: (
bot: Bot,
payload: {
guildId: bigint
emojis: Collection<bigint, DiscordEmoji>
},
}
) => unknown
guildBanAdd: (bot: Bot, user: User, guildId: bigint) => unknown
guildBanRemove: (bot: Bot, user: User, guildId: bigint) => unknown
@@ -615,11 +836,14 @@ export interface EventHandlers {
guildUpdate: (bot: Bot, guild: Guild) => unknown
raw: (bot: Bot, data: DiscordGatewayPayload, shardId: number) => unknown
roleCreate: (bot: Bot, role: Role) => unknown
roleDelete: (bot: Bot, payload: { guildId: bigint, roleId: bigint }) => unknown
roleDelete: (
bot: Bot,
payload: { guildId: bigint, roleId: bigint }
) => unknown
roleUpdate: (bot: Bot, role: Role) => unknown
webhooksUpdate: (
bot: Bot,
payload: { channelId: bigint, guildId: bigint },
payload: { channelId: bigint, guildId: bigint }
) => unknown
botUpdate: (bot: Bot, user: User) => unknown
typingStart: (
@@ -630,7 +854,7 @@ export interface EventHandlers {
userId: bigint
timestamp: number
member: Member | undefined
},
}
) => unknown
}
@@ -719,98 +943,109 @@ export function createBotGatewayHandlers (
// channels
CHANNEL_CREATE: options.CHANNEL_CREATE ?? handlers.handleChannelCreate,
CHANNEL_DELETE: options.CHANNEL_DELETE ?? handlers.handleChannelDelete,
CHANNEL_PINS_UPDATE: options.CHANNEL_PINS_UPDATE ??
handlers.handleChannelPinsUpdate,
CHANNEL_PINS_UPDATE:
options.CHANNEL_PINS_UPDATE ?? handlers.handleChannelPinsUpdate,
CHANNEL_UPDATE: options.CHANNEL_UPDATE ?? handlers.handleChannelUpdate,
THREAD_CREATE: options.THREAD_CREATE ?? handlers.handleThreadCreate,
THREAD_UPDATE: options.THREAD_UPDATE ?? handlers.handleThreadUpdate,
THREAD_DELETE: options.THREAD_DELETE ?? handlers.handleThreadDelete,
THREAD_LIST_SYNC: options.THREAD_LIST_SYNC ?? handlers.handleThreadListSync,
THREAD_MEMBERS_UPDATE: options.THREAD_MEMBERS_UPDATE ?? handlers.handleThreadMembersUpdate,
STAGE_INSTANCE_CREATE: options.STAGE_INSTANCE_CREATE ??
handlers.handleStageInstanceCreate,
STAGE_INSTANCE_UPDATE: options.STAGE_INSTANCE_UPDATE ??
handlers.handleStageInstanceUpdate,
STAGE_INSTANCE_DELETE: options.STAGE_INSTANCE_DELETE ??
handlers.handleStageInstanceDelete,
THREAD_MEMBERS_UPDATE:
options.THREAD_MEMBERS_UPDATE ?? handlers.handleThreadMembersUpdate,
STAGE_INSTANCE_CREATE:
options.STAGE_INSTANCE_CREATE ?? handlers.handleStageInstanceCreate,
STAGE_INSTANCE_UPDATE:
options.STAGE_INSTANCE_UPDATE ?? handlers.handleStageInstanceUpdate,
STAGE_INSTANCE_DELETE:
options.STAGE_INSTANCE_DELETE ?? handlers.handleStageInstanceDelete,
// guilds
GUILD_BAN_ADD: options.GUILD_BAN_ADD ?? handlers.handleGuildBanAdd,
GUILD_BAN_REMOVE: options.GUILD_BAN_REMOVE ?? handlers.handleGuildBanRemove,
GUILD_CREATE: options.GUILD_CREATE ?? handlers.handleGuildCreate,
GUILD_DELETE: options.GUILD_DELETE ?? handlers.handleGuildDelete,
GUILD_EMOJIS_UPDATE: options.GUILD_EMOJIS_UPDATE ??
handlers.handleGuildEmojisUpdate,
GUILD_INTEGRATIONS_UPDATE: options.GUILD_INTEGRATIONS_UPDATE ??
GUILD_EMOJIS_UPDATE:
options.GUILD_EMOJIS_UPDATE ?? handlers.handleGuildEmojisUpdate,
GUILD_INTEGRATIONS_UPDATE:
options.GUILD_INTEGRATIONS_UPDATE ??
handlers.handleGuildIntegrationsUpdate,
GUILD_MEMBER_ADD: options.GUILD_MEMBER_ADD ?? handlers.handleGuildMemberAdd,
GUILD_MEMBER_REMOVE: options.GUILD_MEMBER_REMOVE ??
handlers.handleGuildMemberRemove,
GUILD_MEMBER_UPDATE: options.GUILD_MEMBER_UPDATE ??
handlers.handleGuildMemberUpdate,
GUILD_MEMBERS_CHUNK: options.GUILD_MEMBERS_CHUNK ??
handlers.handleGuildMembersChunk,
GUILD_ROLE_CREATE: options.GUILD_ROLE_CREATE ??
handlers.handleGuildRoleCreate,
GUILD_ROLE_DELETE: options.GUILD_ROLE_DELETE ??
handlers.handleGuildRoleDelete,
GUILD_ROLE_UPDATE: options.GUILD_ROLE_UPDATE ??
handlers.handleGuildRoleUpdate,
GUILD_MEMBER_REMOVE:
options.GUILD_MEMBER_REMOVE ?? handlers.handleGuildMemberRemove,
GUILD_MEMBER_UPDATE:
options.GUILD_MEMBER_UPDATE ?? handlers.handleGuildMemberUpdate,
GUILD_MEMBERS_CHUNK:
options.GUILD_MEMBERS_CHUNK ?? handlers.handleGuildMembersChunk,
GUILD_ROLE_CREATE:
options.GUILD_ROLE_CREATE ?? handlers.handleGuildRoleCreate,
GUILD_ROLE_DELETE:
options.GUILD_ROLE_DELETE ?? handlers.handleGuildRoleDelete,
GUILD_ROLE_UPDATE:
options.GUILD_ROLE_UPDATE ?? handlers.handleGuildRoleUpdate,
GUILD_UPDATE: options.GUILD_UPDATE ?? handlers.handleGuildUpdate,
// guild events
GUILD_SCHEDULED_EVENT_CREATE: options.GUILD_SCHEDULED_EVENT_CREATE ??
GUILD_SCHEDULED_EVENT_CREATE:
options.GUILD_SCHEDULED_EVENT_CREATE ??
handlers.handleGuildScheduledEventCreate,
GUILD_SCHEDULED_EVENT_DELETE: options.GUILD_SCHEDULED_EVENT_DELETE ??
GUILD_SCHEDULED_EVENT_DELETE:
options.GUILD_SCHEDULED_EVENT_DELETE ??
handlers.handleGuildScheduledEventDelete,
GUILD_SCHEDULED_EVENT_UPDATE: options.GUILD_SCHEDULED_EVENT_UPDATE ??
GUILD_SCHEDULED_EVENT_UPDATE:
options.GUILD_SCHEDULED_EVENT_UPDATE ??
handlers.handleGuildScheduledEventUpdate,
GUILD_SCHEDULED_EVENT_USER_ADD: options.GUILD_SCHEDULED_EVENT_USER_ADD ??
GUILD_SCHEDULED_EVENT_USER_ADD:
options.GUILD_SCHEDULED_EVENT_USER_ADD ??
handlers.handleGuildScheduledEventUserAdd,
GUILD_SCHEDULED_EVENT_USER_REMOVE: options.GUILD_SCHEDULED_EVENT_USER_REMOVE ??
GUILD_SCHEDULED_EVENT_USER_REMOVE:
options.GUILD_SCHEDULED_EVENT_USER_REMOVE ??
handlers.handleGuildScheduledEventUserRemove,
// interactions
INTERACTION_CREATE: options.INTERACTION_CREATE ??
handlers.handleInteractionCreate,
INTERACTION_CREATE:
options.INTERACTION_CREATE ?? handlers.handleInteractionCreate,
// invites
INVITE_CREATE: options.INVITE_CREATE ?? handlers.handleInviteCreate,
INVITE_DELETE: options.INVITE_DELETE ?? handlers.handleInviteCreate,
// messages
MESSAGE_CREATE: options.MESSAGE_CREATE ?? handlers.handleMessageCreate,
MESSAGE_DELETE_BULK: options.MESSAGE_DELETE_BULK ??
handlers.handleMessageDeleteBulk,
MESSAGE_DELETE_BULK:
options.MESSAGE_DELETE_BULK ?? handlers.handleMessageDeleteBulk,
MESSAGE_DELETE: options.MESSAGE_DELETE ?? handlers.handleMessageDelete,
MESSAGE_REACTION_ADD: options.MESSAGE_REACTION_ADD ??
handlers.handleMessageReactionAdd,
MESSAGE_REACTION_REMOVE_ALL: options.MESSAGE_REACTION_REMOVE_ALL ??
MESSAGE_REACTION_ADD:
options.MESSAGE_REACTION_ADD ?? handlers.handleMessageReactionAdd,
MESSAGE_REACTION_REMOVE_ALL:
options.MESSAGE_REACTION_REMOVE_ALL ??
handlers.handleMessageReactionRemoveAll,
MESSAGE_REACTION_REMOVE_EMOJI: options.MESSAGE_REACTION_REMOVE_EMOJI ??
MESSAGE_REACTION_REMOVE_EMOJI:
options.MESSAGE_REACTION_REMOVE_EMOJI ??
handlers.handleMessageReactionRemoveEmoji,
MESSAGE_REACTION_REMOVE: options.MESSAGE_REACTION_REMOVE ??
handlers.handleMessageReactionRemove,
MESSAGE_REACTION_REMOVE:
options.MESSAGE_REACTION_REMOVE ?? handlers.handleMessageReactionRemove,
MESSAGE_UPDATE: options.MESSAGE_UPDATE ?? handlers.handleMessageUpdate,
// presence
PRESENCE_UPDATE: options.PRESENCE_UPDATE ?? handlers.handlePresenceUpdate,
TYPING_START: options.TYPING_START ?? handlers.handleTypingStart,
USER_UPDATE: options.USER_UPDATE ?? handlers.handleUserUpdate,
// voice
VOICE_SERVER_UPDATE: options.VOICE_SERVER_UPDATE ??
handlers.handleVoiceServerUpdate,
VOICE_STATE_UPDATE: options.VOICE_STATE_UPDATE ??
handlers.handleVoiceStateUpdate,
VOICE_SERVER_UPDATE:
options.VOICE_SERVER_UPDATE ?? handlers.handleVoiceServerUpdate,
VOICE_STATE_UPDATE:
options.VOICE_STATE_UPDATE ?? handlers.handleVoiceStateUpdate,
// webhooks
WEBHOOKS_UPDATE: options.WEBHOOKS_UPDATE ?? handlers.handleWebhooksUpdate,
// integrations
INTEGRATION_CREATE: options.INTEGRATION_CREATE ??
handlers.handleIntegrationCreate,
INTEGRATION_UPDATE: options.INTEGRATION_UPDATE ??
handlers.handleIntegrationUpdate,
INTEGRATION_DELETE: options.INTEGRATION_DELETE ??
handlers.handleIntegrationDelete
INTEGRATION_CREATE:
options.INTEGRATION_CREATE ?? handlers.handleIntegrationCreate,
INTEGRATION_UPDATE:
options.INTEGRATION_UPDATE ?? handlers.handleIntegrationUpdate,
INTEGRATION_DELETE:
options.INTEGRATION_DELETE ?? handlers.handleIntegrationDelete
}
}
export type RemoveFirstFromTuple<T extends any[]> = T['length'] extends 0 ? []
: ((...b: T) => void) extends (a: any, ...b: infer I) => void ? I
export type RemoveFirstFromTuple<T extends any[]> = T['length'] extends 0
? []
: ((...b: T) => void) extends (a: any, ...b: infer I) => void
? I
: []
export type FinalHelpers = {
[K in keyof Helpers]: (

View File

@@ -1,8 +1,7 @@
import { BigString, DiscordMessage } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import { Collection, hasProperty } from '@discordeno/utils'
import type { Bot } from '../../bot.js'
import { Message } from '../../transformers/message.js'
import { hasProperty } from '../../utils/utils.js'
/**
* Gets multiple messages from a channel.
@@ -67,20 +66,32 @@ export interface GetMessagesAfter extends GetMessagesLimit {
after?: BigString
}
export type GetMessagesOptions = GetMessagesAfter | GetMessagesBefore | GetMessagesAround | GetMessagesLimit
export type GetMessagesOptions =
| GetMessagesAfter
| GetMessagesBefore
| GetMessagesAround
| GetMessagesLimit
export function isGetMessagesAfter (options: GetMessagesOptions): options is GetMessagesAfter {
export function isGetMessagesAfter (
options: GetMessagesOptions
): options is GetMessagesAfter {
return hasProperty(options, 'after')
}
export function isGetMessagesBefore (options: GetMessagesOptions): options is GetMessagesBefore {
export function isGetMessagesBefore (
options: GetMessagesOptions
): options is GetMessagesBefore {
return hasProperty(options, 'before')
}
export function isGetMessagesAround (options: GetMessagesOptions): options is GetMessagesAround {
export function isGetMessagesAround (
options: GetMessagesOptions
): options is GetMessagesAround {
return hasProperty(options, 'around')
}
export function isGetMessagesLimit (options: GetMessagesOptions): options is GetMessagesLimit {
export function isGetMessagesLimit (
options: GetMessagesOptions
): options is GetMessagesLimit {
return hasProperty(options, 'limit')
}

View File

@@ -1,5 +1,5 @@
import { BigString } from '@discordeno/types'
import type { Bot } from '../../../bot'
import type { Bot } from '../../../bot.js'
/**
* Deletes all reactions for all emojis from a message.
@@ -17,7 +17,11 @@ import type { Bot } from '../../../bot'
*
* @see {@link https://discord.com/developers/docs/resources/channel#delete-all-reactions}
*/
export async function deleteReactionsAll (bot: Bot, channelId: BigString, messageId: BigString): Promise<void> {
export async function deleteReactionsAll (
bot: Bot,
channelId: BigString,
messageId: BigString
): Promise<void> {
return await bot.rest.runMethod<void>(
bot.rest,
'DELETE',

View File

@@ -1,5 +1,5 @@
import { BigString } from '@discordeno/types'
import type { Bot } from '../../../bot'
import type { Bot } from '../../../bot.js'
import { processReactionString } from './getReactions.js'
/**
@@ -30,6 +30,10 @@ export async function deleteReactionsEmoji (
return await bot.rest.runMethod<void>(
bot.rest,
'DELETE',
bot.constants.routes.CHANNEL_MESSAGE_REACTION(channelId, messageId, reaction)
bot.constants.routes.CHANNEL_MESSAGE_REACTION(
channelId,
messageId,
reaction
)
)
}

View File

@@ -1,6 +1,6 @@
import { BigString, DiscordUser } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { Bot } from '../../../bot'
import type { Bot } from '../../../bot.js'
import { User } from '../../../transformers/member.js'
/** Get a list of users that reacted with this emoji. */
@@ -28,7 +28,12 @@ export async function getReactions (
const results = await bot.rest.runMethod<DiscordUser[]>(
bot.rest,
'GET',
bot.constants.routes.CHANNEL_MESSAGE_REACTION(channelId, messageId, reaction, options)
bot.constants.routes.CHANNEL_MESSAGE_REACTION(
channelId,
messageId,
reaction,
options
)
)
return new Collection(

View File

@@ -5,4 +5,3 @@ export * from './handlers/index.js'
export * from './helpers/index.js'
export * from './transformers/index.js'
export * from './types.js'
export * from './utils/index.js'

View File

@@ -1,2 +1 @@
export * from './routes.js'
export * from './utils.js'

View File

@@ -1,25 +0,0 @@
import { ImageFormat, ImageSize } from '@discordeno/types'
/** Help format an image url. */
export function formatImageURL (
url: string,
size: ImageSize = 128,
format?: ImageFormat
): string {
return `${url}.${
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
format ?? (url.includes('/a_') ? 'gif' : 'jpg')
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
}?size=${size}`
}
// Typescript is not so good as we developers so we need this little utility function to help it out
// Taken from https://fettblog.eu/typescript-hasownproperty/
/** TS save way to check if a property exists in an object */
export function hasProperty<T extends {}, Y extends PropertyKey = string> (
obj: T,
prop: Y
): obj is T & Record<Y, unknown> {
// eslint-disable-next-line no-prototype-builtins
return obj.hasOwnProperty(prop)
}

View File

@@ -62,6 +62,7 @@ import {
delay,
DISCORDENO_VERSION,
DISCORD_SNOWFLAKE_REGEX,
formatImageURL,
getBotIdFromToken,
iconBigintToHash,
iconHashToBigInt,
@@ -170,7 +171,6 @@ import {
WelcomeScreen
} from './transformers/index.js'
import { CreateApplicationCommand, InteractionResponse } from './types.js'
import { formatImageURL } from './utils/utils.js'
export function createClient (options: CreateClientOptions): Client {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions

View File

@@ -4,4 +4,3 @@ export * from './client.js'
export * from './handlers/index.js'
export * from './transformers/index.js'
export * from './types.js'
export * from './utils/index.js'

View File

@@ -1 +0,0 @@
export * from './utils.js'

View File

@@ -1,25 +0,0 @@
import { ImageFormat, ImageSize } from '@discordeno/types'
/** Help format an image url. */
export function formatImageURL (
url: string,
size: ImageSize = 128,
format?: ImageFormat
): string {
return `${url}.${
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
format ?? (url.includes('/a_') ? 'gif' : 'jpg')
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
}?size=${size}`
}
// Typescript is not so good as we developers so we need this little utility function to help it out
// Taken from https://fettblog.eu/typescript-hasownproperty/
/** TS save way to check if a property exists in an object */
export function hasProperty<T extends {}, Y extends PropertyKey = string> (
obj: T,
prop: Y
): obj is T & Record<Y, unknown> {
// eslint-disable-next-line no-prototype-builtins
return obj.hasOwnProperty(prop)
}

View File

@@ -1,5 +1,6 @@
import { calculateShardId } from './utils/index.js'
export * from '@discordeno/types'
export * from '@discordeno/utils'
export * from './manager/index.js'
export * from './shard/index.js'
export * from './utils/index.js'
export { calculateShardId }

View File

@@ -0,0 +1,34 @@
import { BigString, DiscordFollowedChannel } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
/**
* Follows an announcement channel, allowing messages posted within it to be cross-posted into the target channel.
*
* @param bot - The bot instance to use to make the request.
* @param sourceChannelId - The ID of the announcement channel to follow.
* @param targetChannelId - The ID of the target channel - the channel to cross-post to.
* @returns An instance of {@link FollowedChannel}.
*
* @remarks
* Requires the `MANAGE_WEBHOOKS` permission in the __target channel__.
*
* Fires a _Webhooks Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#follow-announcement-channel}
*/
export async function followAnnouncementChannel (
rest: RestManager,
sourceChannelId: BigString,
targetChannelId: BigString
): Promise<bigint> {
const result = await rest.runMethod<DiscordFollowedChannel>(
rest,
'POST',
rest.constants.routes.CHANNEL_FOLLOW(sourceChannelId),
{
webhook_channel_id: targetChannelId
}
)
return rest.transformers.snowflake(result.webhook_id)
}

View File

@@ -0,0 +1 @@
export * from './followAnnouncementChannel.js'

View File

@@ -0,0 +1,143 @@
import {
BigString,
ChannelTypes,
DiscordChannel,
OverwriteReadable,
SortOrderTypes
} from '@discordeno/types'
import { calculateBits } from '@discordeno/utils'
import { WithReason } from '../../index.js'
import type { RestManager } from '../../restManager.js'
import { Channel } from '../../transformers/channel.js'
/**
* Creates a channel within a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to create the channel within.
* @param options - The parameters for the creation of the channel.
* @returns An instance of the created {@link Channel}.
*
* @remarks
* Requires the `MANAGE_CHANNELS` permission.
*
* If setting permission overwrites, only the permissions the bot user has in the guild can be allowed or denied.
*
* Setting the `MANAGE_ROLES` permission is only possible for guild administrators.
*
* Fires a _Channel Create_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/guild#create-guild-channel}
*/
export async function createChannel (
rest: RestManager,
guildId: BigString,
options: CreateGuildChannel
): Promise<Channel> {
// BITRATE IS IN THOUSANDS SO IF USER PROVIDES 32 WE CONVERT TO 32000
if (options?.bitrate && options.bitrate < 1000) options.bitrate *= 1000
const result = await rest.runMethod<DiscordChannel>(
rest,
'POST',
rest.constants.routes.GUILD_CHANNELS(guildId),
options
? {
name: options.name,
topic: options.topic,
bitrate: options.bitrate,
user_limit: options.userLimit,
rate_limit_per_user: options.rateLimitPerUser,
position: options.position,
parent_id: options.parentId?.toString(),
nsfw: options.nsfw,
permission_overwrites: options?.permissionOverwrites?.map(
(overwrite) => ({
id: overwrite.id.toString(),
type: overwrite.type,
allow: overwrite.allow ? calculateBits(overwrite.allow) : null,
deny: overwrite.deny ? calculateBits(overwrite.deny) : null
})
),
type: options?.type ?? ChannelTypes.GuildText,
default_sort_order: options.defaultSortOrder,
reason: options.reason,
default_auto_archive_duration: options?.defaultAutoArchiveDuration,
default_reaction_emoji: options.defaultReactionEmoji
? {
emoji_id: options.defaultReactionEmoji.emojiId
? rest.transformers.reverse.snowflake(
options.defaultReactionEmoji.emojiId
)
: options.defaultReactionEmoji.emojiId,
emoji_name: options.defaultReactionEmoji.emojiName
}
: undefined,
available_tags: options.availableTags
? options.availableTags.map((availableTag) => ({
id: rest.transformers.reverse.snowflake(availableTag.id),
name: availableTag.name,
moderated: availableTag.moderated,
emoji_name: availableTag.emojiName,
emoji_id: availableTag.emojiId
? rest.transformers.reverse.snowflake(availableTag.emojiId)
: undefined
}))
: undefined
}
: {}
)
return rest.transformers.channel(rest, {
channel: result,
guildId: rest.transformers.snowflake(guildId)
})
}
export interface CreateGuildChannel extends WithReason {
/** Channel name (1-100 characters) */
name: string
/** The type of channel */
type?: ChannelTypes
/** Channel topic (0-1024 characters) */
topic?: string
/** The bitrate (in bits) of the voice channel (voice only) */
bitrate?: number
/** The user limit of the voice channel (voice only) */
userLimit?: number
/** Amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission `manage_messages` or `manage_channel`, are unaffected */
rateLimitPerUser?: number
/** Sorting position of the channel */
position?: number
/** The channel's permission overwrites */
permissionOverwrites?: OverwriteReadable[]
/** Id of the parent category for a channel */
parentId?: BigString
/** Whether the channel is nsfw */
nsfw?: boolean
/** Default duration (in minutes) that clients (not the API) use for newly created threads in this channel, to determine when to automatically archive the thread after the last activity */
defaultAutoArchiveDuration?: number
/** Emoji to show in the add reaction button on a thread in a forum channel */
defaultReactionEmoji?: {
/** The id of a guild's custom emoji. Exactly one of `emojiId` and `emojiName` must be set. */
emojiId?: BigString | null
/** The unicode character of the emoji. Exactly one of `emojiId` and `emojiName` must be set. */
emojiName?: string | null
}
/** Set of tags that can be used in a forum channel */
availableTags?: Array<{
/** The id of the tag */
id: BigString
/** The name of the tag (0-20 characters) */
name: string
/** whether this tag can only be added to or removed from threads by a member with the MANAGE_THREADS permission */
moderated: boolean
/** The id of a guild's custom emoji */
emojiId: BigString
/** The unicode character of the emoji */
emojiName?: string
}>
/** the default sort order type used to order posts in forum channels */
defaultSortOrder?: SortOrderTypes | null
}

View File

@@ -0,0 +1,42 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
/**
* Deletes a channel from within a guild.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel to delete.
* @returns An instance of the deleted {@link Channel}.
*
* @remarks
* For community guilds, the _Rules_, _Guidelines_ and _Community Update_ channels cannot be deleted.
*
* If the channel is a thread:
* - Requires the `MANAGE_THREADS` permission.
*
* - Fires a _Thread Delete_ gateway event.
*
* Otherwise:
* - Requires the `MANAGE_CHANNELS` permission.
*
* - ⚠️ Deleting a category channel does not delete its child channels.
* Instead, they will have their `parent_id` property removed, and a `Channel Update` gateway event will fire for each of them.
*
* - Fires a _Channel Delete_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#deleteclose-channel}
*/
export async function deleteChannel (
rest: RestManager,
channelId: BigString,
reason?: string
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.CHANNEL(channelId),
{
reason
}
)
}

View File

@@ -0,0 +1,30 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
/**
* Deletes a permission override for a user or role in a channel.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel to delete the permission override of.
* @param overwriteId - The ID of the permission override to delete.
*
* @remarks
* Requires the `MANAGE_ROLES` permission.
*
* Fires a _Channel Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#delete-channel-permission}
*/
export async function deleteChannelPermissionOverride (
rest: RestManager,
channelId: BigString,
overwriteId: BigString,
reason?: string
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.CHANNEL_OVERWRITE(channelId, overwriteId),
reason ? { reason } : undefined
)
}

View File

@@ -0,0 +1,250 @@
import {
BigString,
ChannelTypes,
DiscordChannel,
OverwriteReadable,
SortOrderTypes,
VideoQualityModes
} from '@discordeno/types'
import { calculateBits } from '@discordeno/utils'
import { WithReason } from '../../index.js'
import type { RestManager } from '../../restManager.js'
import { Channel } from '../../transformers/channel.js'
/**
* Edits a channel's settings.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel to edit.
* @param options - The parameters for the edit of the channel.
* @returns An instance of the edited {@link Channel}.
*
* @remarks
* If editing a channel of type {@link ChannelTypes.GroupDm}:
* - Fires a _Channel Update_ gateway event.
*
* If editing a thread channel:
* - Requires the `MANAGE_THREADS` permission __unless__ if setting the `archived` property to `false` when the `locked` property is also `false`, in which case only the `SEND_MESSAGES` permission is required.
*
* - Fires a _Thread Update_ gateway event.
*
* If editing a guild channel:
* - Requires the `MANAGE_CHANNELS` permission.
*
* - If modifying permission overrides:
* - Requires the `MANAGE_ROLES` permission.
*
* - Only permissions the bot user has in the guild or parent channel can be allowed/denied __unless__ the bot user has a `MANAGE_ROLES` permission override in the channel.
*
* - If modifying a channel of type {@link ChannelTypes.GuildCategory}:
* - Fires a _Channel Update_ gateway event for each child channel impacted in this change.
* - Otherwise:
* - Fires a _Channel Update_ gateway event.
*/
export async function editChannel (
rest: RestManager,
channelId: BigString,
options: ModifyChannel
): Promise<Channel> {
if (options.name ?? options.topic) {
const request = editChannelNameTopicQueue.get(channelId)
if (request == null) {
// If this hasn't been done before simply add 1 for it
editChannelNameTopicQueue.set(channelId, {
channelId,
amount: 1,
// 10 minutes from now
timestamp: Date.now() + 600000,
items: []
})
} else if (request.amount === 1) {
// Start queuing future requests to this channel
request.amount = 2
request.timestamp = Date.now() + 600000
} else {
return await new Promise<Channel>((resolve, reject) => {
// 2 have already been used add to queue
request.items.push({ channelId, options, resolve, reject })
if (editChannelProcessing) return
editChannelProcessing = true
processEditChannelQueue(rest)
})
}
}
const result = await rest.runMethod<DiscordChannel>(
rest,
'PATCH',
rest.constants.routes.CHANNEL(channelId),
{
name: options.name,
topic: options.topic,
bitrate: options.bitrate,
user_limit: options.userLimit,
rate_limit_per_user: options.rateLimitPerUser,
position: options.position,
parent_id:
options.parentId === null ? null : options.parentId?.toString(),
nsfw: options.nsfw,
type: options.type,
archived: options.archived,
auto_archive_duration: options.autoArchiveDuration,
locked: options.locked,
invitable: options.invitable,
permission_overwrites: options.permissionOverwrites
? options.permissionOverwrites?.map((overwrite) => ({
id: overwrite.id.toString(),
type: overwrite.type,
allow: overwrite.allow ? calculateBits(overwrite.allow) : null,
deny: overwrite.deny ? calculateBits(overwrite.deny) : null
}))
: undefined,
available_tags: options.availableTags
? options.availableTags.map((availableTag) => ({
id: availableTag.id,
name: availableTag.name,
moderated: availableTag.moderated,
emoji_id: availableTag.emojiId,
emoji_name: availableTag.emojiName
}))
: undefined,
applied_tags: options.appliedTags?.map((appliedTag) =>
appliedTag.toString()
),
default_reaction_emoji: options.defaultReactionEmoji
? {
emoji_id: options.defaultReactionEmoji.emojiId,
emoji_name: options.defaultReactionEmoji.emojiName
}
: undefined,
default_sort_order: options.defaultSortOrder,
reason: options.reason
}
)
return rest.transformers.channel(rest, {
channel: result,
guildId: rest.transformers.snowflake(result.guild_id!)
})
}
interface EditChannelRequest {
amount: number
timestamp: number
channelId: BigString
items: Array<{
channelId: BigString
options: ModifyChannel
resolve: (channel: Channel) => void
// deno-lint-ignore no-explicit-any
reject: (error: any) => void
}>
}
const editChannelNameTopicQueue = new Map<BigString, EditChannelRequest>()
let editChannelProcessing = false
function processEditChannelQueue (rest: RestManager): void {
if (!editChannelProcessing) return
const now = Date.now()
editChannelNameTopicQueue.forEach((request) => {
(async () => {
rest.debug('Running forEach loop in edit_channel file.')
if (now < request.timestamp) return
// 10 minutes have passed so we can reset this channel again
if (request.items.length === 0) {
editChannelNameTopicQueue.delete(request.channelId)
return
}
request.amount = 0
// There are items to process for this request
const details = request.items.shift()
if (details == null) return
await rest.helpers
.editChannel(details.channelId, details.options)
.then((result) => details.resolve(result))
.catch(details.reject)
const secondDetails = request.items.shift()
if (secondDetails == null) return
await rest.helpers
.editChannel(secondDetails.channelId, secondDetails.options)
.then((result) => secondDetails.resolve(result))
.catch(secondDetails.reject)
})()
})
if (editChannelNameTopicQueue.size) {
setTimeout(() => {
rest.debug('Running setTimeout in EDIT_CHANNEL file.')
processEditChannelQueue(rest)
}, 60000)
} else {
editChannelProcessing = false
}
}
export interface ModifyChannel extends WithReason {
/** 1-100 character channel name */
name?: string
/** The type of channel; only conversion between text and news is supported and only in guilds with the "NEWS" feature */
type?: ChannelTypes
/** The position of the channel in the left-hand listing */
position?: number | null
/** 0-1024 character channel topic */
topic?: string | null
/** Whether the channel is nsfw */
nsfw?: boolean | null
/** Amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission `manage_messages` or `manage_channel`, are unaffected */
rateLimitPerUser?: number | null
/** The bitrate (in bits) of the voice channel; 8000 to 96000 (128000 for VIP servers) */
bitrate?: number | null
/** The user limit of the voice channel; 0 refers to no limit, 1 to 99 refers to a user limit */
userLimit?: number | null
/** Channel or category-specific permissions */
permissionOverwrites?: OverwriteReadable[] | null
/** Id of the new parent category for a channel */
parentId?: BigString | null
/** Voice region id for the voice channel, automatic when set to null */
rtcRegion?: string | null
/** The camera video quality mode of the voice channel */
videoQualityMode?: VideoQualityModes
/** Whether the thread is archived */
archived?: boolean
/** Duration in minutes to automatically archive the thread after recent activity */
autoArchiveDuration?: 60 | 1440 | 4320 | 10080
/** When a thread is locked, only users with `MANAGE_THREADS` can unarchive it */
locked?: boolean
/** whether non-moderators can add other non-moderators to a thread; only available on private threads */
invitable?: boolean
/** The set of tags that can be used in a GUILD_FORUM channel */
availableTags?: Array<{
/** The id of the tag */
id: string
/** The name of the tag (0-20 characters) */
name: string
/** Whether this tag can only be added to or removed from threads by a member with the MANAGE_THREADS permission */
moderated: boolean
/** The id of a guild's custom emoji At most one of emoji_id and emoji_name may be set. */
emojiId: string
/** The unicode character of the emoji */
emojiName: string
}>
/** The IDs of the set of tags that have been applied to a thread in a GUILD_FORUM channel; limited to 5 */
appliedTags?: BigString[]
/** the emoji to show in the add reaction button on a thread in a GUILD_FORUM channel */
defaultReactionEmoji?: {
/** The id of a guild's custom emoji */
emojiId: string
/** The unicode character of the emoji */
emojiName: string | null
}
/** the initial rate_limit_per_user to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. */
defaultThreadRateLimitPerUser?: number
/** the default sort order type used to order posts in forum channels */
defaultSortOrder?: SortOrderTypes | null
}

View File

@@ -0,0 +1,42 @@
import { OverwriteReadable } from '@discordeno/types'
import { calculateBits } from '@discordeno/utils'
import { BigString, WithReason } from '../../index.js'
import type { RestManager } from '../../restManager.js'
/**
* Edits the permission overrides for a user or role in a channel.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel to edit the permission overrides of.
* @param options - The permission override.
*
* @remarks
* Requires the `MANAGE_ROLES` permission.
*
* Only permissions the bot user has in the guild or parent channel can be allowed/denied __unless__ the bot user has a `MANAGE_ROLES` permission override in the channel.
*
* Fires a _Channel Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#edit-channel-permissions}
*/
export async function editChannelPermissionOverrides (
rest: RestManager,
channelId: BigString,
options: EditChannelPermissionOverridesOptions
): Promise<void> {
return await rest.runMethod<void>(
rest,
'PUT',
rest.constants.routes.CHANNEL_OVERWRITE(channelId, options.id),
{
allow: options.allow ? calculateBits(options.allow) : '0',
deny: options.deny ? calculateBits(options.deny) : '0',
type: options.type,
reason: options.reason
}
)
}
export interface EditChannelPermissionOverridesOptions
extends OverwriteReadable,
WithReason {}

View File

@@ -0,0 +1,52 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
export const swapChannels = editChannelPositions
/**
* Edits the positions of a set of channels in a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild in which to edit the positions of the channels.
* @param channelPositions - A set of objects defining the updated positions of the channels.
*
* @remarks
* Requires the `MANAGE_CHANNELS` permission.
*
* Fires a _Channel Update_ gateway event for every channel impacted in this change.
*
* @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-channel-positions}
*/
export async function editChannelPositions (
rest: RestManager,
guildId: BigString,
channelPositions: ModifyGuildChannelPositions[]
): Promise<void> {
if (channelPositions.length === 0) {
throw new Error('You must provide at least one channels to be moved.')
}
return await rest.runMethod<void>(
rest,
'PATCH',
rest.constants.routes.GUILD_CHANNELS(guildId),
channelPositions.map((channelPosition) => ({
id: channelPosition.id,
position: channelPosition.position,
lock_positions: channelPosition.lockPositions,
parent_id: channelPosition.parentId
}))
)
}
/** https://discord.com/developers/docs/resources/guild#modify-guild-channel-positions */
export interface ModifyGuildChannelPositions {
/** Channel id */
id: string
/** Sorting position of the channel */
position: number | null
/** Syncs the permission overwrites with the new parent, if moving to a new category */
lockPositions?: boolean | null
/** The new parent ID for the channel that is moved */
parentId?: string | null
}

View File

@@ -0,0 +1,88 @@
import {
AllowedMentions,
BigString,
DiscordChannel,
FileContent,
MessageComponents,
WithReason
} from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
import { Channel } from '../../../transformers/channel.js'
import { Embed } from '../../../transformers/embed.js'
/**
* Creates a new thread in a forum channel, and sends a message within the created thread.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the forum channel to create the thread within.
* @param options - The parameters for the creation of the thread.
* @returns An instance of {@link Channel} with a nested {@link Message} object.
*
* @remarks
* Requires the `CREATE_MESSAGES` permission.
*
* Fires a _Thread Create_ gateway event.
* Fires a _Message Create_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#start-thread-in-forum-channel}
*
* @experimental
*/
export async function createForumThread (
rest: RestManager,
channelId: BigString,
options: CreateForumPostWithMessage
): Promise<Channel> {
const result = await rest.runMethod<DiscordChannel>(
rest,
'POST',
rest.constants.routes.FORUM_START(channelId),
{
name: options.name,
auto_archive_duration: options.autoArchiveDuration,
rate_limit_per_user: options.rateLimitPerUser,
reason: options.reason,
content: options.content,
embeds: options.embeds?.map((embed) =>
rest.transformers.reverse.embed(rest, embed)
),
allowed_mentions: options.allowedMentions
? {
parse: options.allowedMentions?.parse,
roles: options.allowedMentions?.roles?.map((id) => id.toString()),
users: options.allowedMentions?.users?.map((id) => id.toString()),
replied_user: options.allowedMentions?.repliedUser
}
: undefined,
file: options.file,
components: options.components?.map((component) =>
rest.transformers.reverse.component(rest, component)
)
}
)
return rest.transformers.channel(rest, {
channel: result,
guildId: rest.transformers.snowflake(result.guild_id!)
})
}
export interface CreateForumPostWithMessage extends WithReason {
/** 1-100 character thread name */
name: string
/** Duration in minutes to automatically archive the thread after recent activity */
autoArchiveDuration: 60 | 1440 | 4320 | 10080
/** Amount of seconds a user has to wait before sending another message (0-21600) */
rateLimitPerUser?: number | null
/** The message contents (up to 2000 characters) */
content?: string
/** Embedded `rich` content (up to 6000 characters) */
embeds?: Embed[]
/** Allowed mentions for the message */
allowedMentions?: AllowedMentions
/** The contents of the file being sent */
file?: FileContent | FileContent[]
/** The components you would like to have sent in this message */
components?: MessageComponents
}

View File

@@ -0,0 +1 @@
export * from './createForumThread.js'

View File

@@ -0,0 +1,34 @@
import { BigString, DiscordChannel } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
import { Channel } from '../../transformers/channel.js'
/**
* Gets a channel by its ID.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel to get.
* @returns An instance of {@link Channel}.
*
* @remarks
* If the channel is a thread, a {@link ThreadMember} object is included in the result.
*
* @see {@link https://discord.com/developers/docs/resources/channel#get-channel}
*/
export async function getChannel (
rest: RestManager,
channelId: BigString
): Promise<Channel> {
const result = await rest.runMethod<DiscordChannel>(
rest,
'GET',
rest.constants.routes.CHANNEL(channelId)
)
// IF A CHANNEL DOESN'T EXIST, DISCORD RETURNS `{}`
return rest.transformers.channel(rest, {
channel: result,
guildId: result.guild_id
? rest.transformers.snowflake(result.guild_id)
: undefined
})
}

View File

@@ -0,0 +1,76 @@
import {
BigString,
DiscordInviteMetadata,
TargetTypes
} from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../restManager.js'
import { InviteMetadata } from '../guilds/invites/index.js'
/**
* Gets the list of invites for a channel.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel to get the invites of.
* @returns A collection of {@link InviteMetadata} objects assorted by invite code.
*
* @remarks
* Requires the `MANAGE_CHANNELS` permission.
*
* Only usable for guild channels.
*
* @see {@link https://discord.com/developers/docs/resources/channel#get-channel-invites}
*/
export async function getChannelInvites (
rest: RestManager,
channelId: BigString
): Promise<Collection<string, InviteMetadata>> {
const results = await rest.runMethod<DiscordInviteMetadata[]>(
rest,
'GET',
rest.constants.routes.CHANNEL_INVITES(channelId)
)
return new Collection(
results.map<[string, InviteMetadata]>((result) => {
const invite = {
code: result.code,
guildId: result.guild?.id
? rest.transformers.snowflake(result.guild.id)
: undefined,
channelId: result.channel?.id
? rest.transformers.snowflake(result.channel.id)
: undefined,
inviter: result.inviter
? rest.transformers.user(rest, result.inviter)
: undefined,
targetType: result.target_type
? result.target_type === 1
? TargetTypes.Stream
: TargetTypes.EmbeddedApplication
: undefined,
targetUser: result.target_user
? rest.transformers.user(rest, result.target_user)
: undefined,
targetApplicationId: result.target_application?.id
? rest.transformers.snowflake(result.target_application.id)
: undefined,
approximatePresenceCount: result.approximate_presence_count,
approximateMemberCount: result.approximate_member_count,
expiresAt: result.expires_at
? Date.parse(result.expires_at)
: undefined,
guildScheduledEvent: result.guild_scheduled_event
? rest.transformers.scheduledEvent(rest, result.guild_scheduled_event)
: undefined,
// Metadata structure
uses: result.uses,
maxUses: result.max_uses,
maxAge: result.max_age,
temporary: result.temporary,
createdAt: Date.parse(result.created_at)
}
return [invite.code, invite]
})
)
}

View File

@@ -0,0 +1,39 @@
import { BigString, DiscordChannel } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../restManager.js'
import { Channel } from '../../transformers/channel.js'
/**
* Gets the list of channels for a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the channels of.
* @returns A collection of {@link Channel} objects assorted by channel ID.
*
* @remarks
* Excludes threads.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-channels}
*/
export async function getChannels (
rest: RestManager,
guildId: BigString
): Promise<Collection<bigint, Channel>> {
const results = await rest.runMethod<DiscordChannel[]>(
rest,
'GET',
rest.constants.routes.GUILD_CHANNELS(guildId)
)
const id = rest.transformers.snowflake(guildId)
return new Collection(
results.map((result) => {
const channel = rest.transformers.channel(rest, {
channel: result,
guildId: id
})
return [channel.id, channel]
})
)
}

View File

@@ -0,0 +1,14 @@
export * from './announcements/index.js'
export * from './createChannel.js'
export * from './deleteChannel.js'
export * from './deleteChannelPermissionOverride.js'
export * from './editChannel.js'
export * from './editChannelPermissionOverrides.js'
export * from './editChannelPositions.js'
export * from './forums/index.js'
export * from './getChannel.js'
export * from './getChannelInvites.js'
export * from './getChannels.js'
export * from './stages/index.js'
export * from './threads/index.js'
export * from './triggerTypingIndicator.js'

View File

@@ -0,0 +1,44 @@
import { DiscordStageInstance } from '@discordeno/types'
import { BigString, WithReason } from '../../../index.js'
import type { RestManager } from '../../../restManager.js'
import { StageInstance } from '../../../transformers/stageInstance.js'
/**
* Creates a stage instance associated with a stage channel.
*
* @param bot - The bot instance to use to make the request.
* @param options - The parameters for the creation of the stage instance.
* @returns An instance of the created {@link StageInstance}.
*
* @remarks
* Requires the user to be a moderator of the stage channel.
*
* Fires a _Stage Instance Create_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/stage-instance#create-stage-instance}
*/
export async function createStageInstance (
rest: RestManager,
options: CreateStageInstance
): Promise<StageInstance> {
const result = await rest.runMethod<DiscordStageInstance>(
rest,
'POST',
rest.constants.routes.STAGE_INSTANCES(),
{
channel_id: options.channelId.toString(),
topic: options.topic,
send_start_notification: options.sendStartNotification,
reason: options.reason
}
)
return rest.transformers.stageInstance(rest, result)
}
export interface CreateStageInstance extends WithReason {
channelId: BigString
topic: string
/** Notify @everyone that the stage instance has started. Requires the MENTION_EVERYONE permission. */
sendStartNotification?: boolean
}

View File

@@ -0,0 +1,28 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
/**
* Deletes the stage instance associated with a stage channel, if one exists.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the stage channel the stage instance is associated with.
*
* @remarks
* Requires the user to be a moderator of the stage channel.
*
* Fires a _Stage Instance Delete_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/stage-instance#delete-stage-instance}
*/
export async function deleteStageInstance (
rest: RestManager,
channelId: BigString,
reason?: string
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.STAGE_INSTANCE(channelId),
reason ? { reason } : undefined
)
}

View File

@@ -0,0 +1,40 @@
import { DiscordStageInstance } from '@discordeno/types'
import { BigString, WithReason } from '../../../index.js'
import type { RestManager } from '../../../restManager.js'
import { StageInstance } from '../../../transformers/stageInstance.js'
/**
* Edits a stage instance.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the stage channel the stage instance is associated with.
* @returns An instance of the updated {@link StageInstance}.
*
* @remarks
* Requires the user to be a moderator of the stage channel.
*
* Fires a _Stage Instance Update_ event.
*
* @see {@link https://discord.com/developers/docs/resources/stage-instance#modify-stage-instance}
*/
export async function editStageInstance (
rest: RestManager,
channelId: BigString,
data: EditStageInstanceOptions
): Promise<StageInstance> {
const result = await rest.runMethod<DiscordStageInstance>(
rest,
'PATCH',
rest.constants.routes.STAGE_INSTANCE(channelId),
{
topic: data.topic
}
)
return rest.transformers.stageInstance(rest, result)
}
export interface EditStageInstanceOptions extends WithReason {
/** The topic of the Stage instance (1-120 characters) */
topic: string
}

View File

@@ -0,0 +1,25 @@
import { BigString, DiscordStageInstance } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
import { StageInstance } from '../../../transformers/stageInstance.js'
/**
* Gets the stage instance associated with a stage channel, if one exists.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the stage channel the stage instance is associated with.
* @returns An instance of {@link StageInstance}.
*
* @see {@link https://discord.com/developers/docs/resources/stage-instance#get-stage-instance}
*/
export async function getStageInstance (
rest: RestManager,
channelId: BigString
): Promise<StageInstance> {
const result = await rest.runMethod<DiscordStageInstance>(
rest,
'GET',
rest.constants.routes.STAGE_INSTANCE(channelId)
)
return rest.transformers.stageInstance(rest, result)
}

View File

@@ -0,0 +1,4 @@
export * from './createStageInstance.js'
export * from './deleteStageInstance.js'
export * from './editStageInstance.js'
export * from './getStageInstance.js'

View File

@@ -0,0 +1,29 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
/**
* Adds a member to a thread.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the thread to add the member to.
* @param userId - The user ID of the member to add to the thread.
*
* @remarks
* Requires the ability to send messages in the thread.
* Requires the thread not be archived.
*
* Fires a _Thread Members Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#add-thread-member}
*/
export async function addThreadMember (
rest: RestManager,
channelId: BigString,
userId: BigString
): Promise<void> {
return await rest.runMethod<void>(
rest,
'PUT',
rest.constants.routes.THREAD_USER(channelId, userId)
)
}

View File

@@ -0,0 +1,50 @@
import { BigString, DiscordListActiveThreads } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../../restManager.js'
import { Channel } from '../../../transformers/channel.js'
import { ThreadMember } from '../../../transformers/threadMember.js'
/**
* Gets the list of all active threads for a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the threads of.
* @returns An instance of {@link ActiveThreads}.
*
* @remarks
* Returns both public and private threads.
*
* Threads are ordered by the `id` property in descending order.
*
* @see {@link https://discord.com/developers/docs/resources/guild#list-active-guild-threads}
*/
export async function getActiveThreads (
rest: RestManager,
guildId: BigString
): Promise<ActiveThreads> {
const results = await rest.runMethod<DiscordListActiveThreads>(
rest,
'GET',
rest.constants.routes.THREAD_ACTIVE(guildId)
)
return {
threads: new Collection(
results.threads.map((result) => {
const thread = rest.transformers.channel(rest, { channel: result })
return [thread.id, thread]
})
),
members: new Collection(
results.members.map((result) => {
const member = rest.transformers.threadMember(rest, result)
return [member.id!, member]
})
)
}
}
export interface ActiveThreads {
threads: Collection<bigint, Channel>
members: Collection<bigint, ThreadMember>
}

View File

@@ -0,0 +1,53 @@
import { BigString, DiscordListArchivedThreads } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../../restManager.js'
import {
ArchivedThreads,
ListArchivedThreads
} from './getPublicArchivedThreads.js'
/**
* Gets the list of private archived threads for a channel.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel to get the archived threads for.
* @param options - The parameters for the fetching of threads.
* @returns An instance of {@link ArchivedThreads}.
*
* @remarks
* Requires the `READ_MESSAGE_HISTORY` permission.
* Requires the `MANAGE_THREADS` permission.
*
* Returns threads of type {@link ChannelTypes.GuildPrivateThread}.
*
* Threads are ordered by the `archive_timestamp` property included in the metadata of the object in descending order.
*
* @see {@link https://discord.com/developers/docs/resources/channel#list-private-archived-threads}
*/
export async function getPrivateArchivedThreads (
rest: RestManager,
channelId: BigString,
options?: ListArchivedThreads
): Promise<ArchivedThreads> {
const results = await rest.runMethod<DiscordListArchivedThreads>(
rest,
'GET',
rest.constants.routes.THREAD_ARCHIVED_PRIVATE(channelId, options)
)
return {
threads: new Collection(
results.threads.map((result) => {
const thread = rest.transformers.channel(rest, { channel: result })
return [thread.id, thread]
})
),
members: new Collection(
results.members.map((result) => {
const member = rest.transformers.threadMember(rest, result)
return [member.id!, member]
})
),
hasMore: results.has_more
}
}

View File

@@ -0,0 +1,52 @@
import { BigString, DiscordListArchivedThreads } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../../restManager.js'
import {
ArchivedThreads,
ListArchivedThreads
} from './getPublicArchivedThreads.js'
/**
* Gets the list of private archived threads the bot is a member of for a channel.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel to get the archived threads for.
* @param options - The parameters for the fetching of threads.
* @returns An instance of {@link ArchivedThreads}.
*
* @remarks
* Requires the `READ_MESSAGE_HISTORY` permission.
*
* Returns threads of type {@link ChannelTypes.GuildPrivateThread}.
*
* Threads are ordered by the `id` property in descending order.
*
* @see {@link https://discord.com/developers/docs/resources/channel#list-joined-private-archived-threads}
*/
export async function getPrivateJoinedArchivedThreads (
rest: RestManager,
channelId: BigString,
options?: ListArchivedThreads
): Promise<ArchivedThreads> {
const results = await rest.runMethod<DiscordListArchivedThreads>(
rest,
'GET',
rest.constants.routes.THREAD_ARCHIVED_PRIVATE_JOINED(channelId, options)
)
return {
threads: new Collection(
results.threads.map((result) => {
const thread = rest.transformers.channel(rest, { channel: result })
return [thread.id, thread]
})
),
members: new Collection(
results.members.map((result) => {
const member = rest.transformers.threadMember(rest, result)
return [member.id!, member]
})
),
hasMore: results.has_more
}
}

View File

@@ -0,0 +1,62 @@
import { BigString, DiscordListArchivedThreads } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../../restManager.js'
import { ActiveThreads } from './getActiveThreads.js'
/**
* Gets the list of public archived threads for a channel.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel to get the archived threads for.
* @param options - The parameters for the fetching of threads.
* @returns An instance of {@link ArchivedThreads}.
*
* @remarks
* Requires the `READ_MESSAGE_HISTORY` permission.
*
* If called on a channel of type {@link ChannelTypes.GuildText}, returns threads of type {@link ChannelTypes.GuildPublicThread}.
* If called on a channel of type {@link ChannelTypes.GuildNews}, returns threads of type {@link ChannelTypes.GuildNewsThread}.
*
* Threads are ordered by the `archive_timestamp` property included in the metadata of the object in descending order.
*
* @see {@link https://discord.com/developers/docs/resources/channel#list-public-archived-threads}
*/
export async function getPublicArchivedThreads (
rest: RestManager,
channelId: BigString,
options?: ListArchivedThreads
): Promise<ArchivedThreads> {
const results = await rest.runMethod<DiscordListArchivedThreads>(
rest,
'GET',
rest.constants.routes.THREAD_ARCHIVED_PUBLIC(channelId, options)
)
return {
threads: new Collection(
results.threads.map((result) => {
const thread = rest.transformers.channel(rest, { channel: result })
return [thread.id, thread]
})
),
members: new Collection(
results.members.map((result) => {
const member = rest.transformers.threadMember(rest, result)
return [member.id!, member]
})
),
hasMore: results.has_more
}
}
/** https://discord.com/developers/docs/resources/channel#list-public-archived-threads-query-string-params */
export interface ListArchivedThreads {
/** Returns threads before this timestamp */
before?: number
/** Optional maximum number of threads to return */
limit?: number
}
export type ArchivedThreads = ActiveThreads & {
hasMore: boolean
}

View File

@@ -0,0 +1,27 @@
import { BigString, DiscordThreadMember } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
import { ThreadMember } from '../../../transformers/threadMember.js'
/**
* Gets a thread member by their user ID.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the thread to get the thread member of.
* @param userId - The user ID of the thread member to get.
* @returns An instance of {@link ThreadMember}.
*
* @see {@link https://discord.com/developers/docs/resources/channel#get-thread-member}
*/
export async function getThreadMember (
rest: RestManager,
channelId: BigString,
userId: BigString
): Promise<ThreadMember> {
const result = await rest.runMethod<DiscordThreadMember>(
rest,
'GET',
rest.constants.routes.THREAD_USER(channelId, userId)
)
return rest.transformers.threadMember(rest, result)
}

View File

@@ -0,0 +1,34 @@
import { BigString, DiscordThreadMember } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../../restManager.js'
import { ThreadMember } from '../../../transformers/threadMember.js'
/**
* Gets the list of thread members for a thread.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the thread to get the thread members of.
* @returns A collection of {@link ThreadMember} assorted by user ID.
*
* @remarks
* Requires the application to have the `GUILD_MEMBERS` privileged intent enabled.
*
* @see {@link https://discord.com/developers/docs/resources/channel#list-thread-members}
*/
export async function getThreadMembers (
rest: RestManager,
channelId: BigString
): Promise<Collection<bigint, ThreadMember>> {
const results = await rest.runMethod<DiscordThreadMember[]>(
rest,
'GET',
rest.constants.routes.THREAD_MEMBERS(channelId)
)
return new Collection(
results.map((result) => {
const member = rest.transformers.threadMember(rest, result)
return [member.id!, member]
})
)
}

View File

@@ -0,0 +1,12 @@
export * from './addThreadMember.js'
export * from './getActiveThreads.js'
export * from './getPrivateArchivedThreads.js'
export * from './getPrivateJoinedArchivedThreads.js'
export * from './getPublicArchivedThreads.js'
export * from './getThreadMember.js'
export * from './getThreadMembers.js'
export * from './joinThread.js'
export * from './leaveThread.js'
export * from './removeThreadMember.js'
export * from './startThreadWithMessage.js'
export * from './startThreadWithoutMessage.js'

View File

@@ -0,0 +1,26 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
/**
* Adds the bot user to a thread.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the thread to add the bot user to.
*
* @remarks
* Requires the thread not be archived.
*
* Fires a _Thread Members Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#join-thread}
*/
export async function joinThread (
rest: RestManager,
channelId: BigString
): Promise<void> {
return await rest.runMethod<void>(
rest,
'PUT',
rest.constants.routes.THREAD_ME(channelId)
)
}

View File

@@ -0,0 +1,26 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
/**
* Removes the bot user from a thread.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the thread to remove the bot user from.
*
* @remarks
* Requires the thread not be archived.
*
* Fires a _Thread Members Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#leave-thread}
*/
export async function leaveThread (
rest: RestManager,
channelId: BigString
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.THREAD_ME(channelId)
)
}

View File

@@ -0,0 +1,31 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
/**
* Removes a member from a thread.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the thread to remove the thread member of.
* @param userId - The user ID of the thread member to remove.
*
* @remarks
* If the thread is of type {@link ChannelTypes.GuildPrivateThread}, requires to be the creator of the thread.
* Otherwise, requires the `MANAGE_THREADS` permission.
*
* Requires the thread not be archived.
*
* Fires a _Thread Members Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#remove-thread-member}
*/
export async function removeThreadMember (
rest: RestManager,
channelId: BigString,
userId: BigString
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.THREAD_USER(channelId, userId)
)
}

View File

@@ -0,0 +1,57 @@
import { DiscordChannel } from '@discordeno/types'
import { BigString, WithReason } from '../../../index.js'
import type { RestManager } from '../../../restManager.js'
import { Channel } from '../../../transformers/channel.js'
/**
* Creates a thread, using an existing message as its point of origin.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel in which to create the thread.
* @param messageId - The ID of the message to use as the thread's point of origin.
* @param options - The parameters to use for the creation of the thread.
* @returns An instance of the created {@link Channel | Thread}.
*
* @remarks
* If called on a channel of type {@link ChannelTypes.GuildText}, creates a {@link ChannelTypes.GuildPublicThread}.
* If called on a channel of type {@link ChannelTypes.GuildNews}, creates a {@link ChannelTypes.GuildNewsThread}.
* Does not work on channels of type {@link ChannelTypes.GuildForum}.
*
* The ID of the created thread will be the same as the ID of the source message.
*
* Fires a _Thread Create_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#start-thread-from-message}
*/
export async function startThreadWithMessage (
rest: RestManager,
channelId: BigString,
messageId: BigString,
options: StartThreadWithMessage
): Promise<Channel> {
const result = await rest.runMethod<DiscordChannel>(
rest,
'POST',
rest.constants.routes.THREAD_START_PUBLIC(channelId, messageId),
{
name: options.name,
auto_archive_duration: options.autoArchiveDuration,
rate_limit_per_user: options.rateLimitPerUser,
reason: options.reason
}
)
return rest.transformers.channel(rest, {
channel: result,
guildId: rest.transformers.snowflake(result.guild_id!)
})
}
export interface StartThreadWithMessage extends WithReason {
/** 1-100 character thread name */
name: string
/** Duration in minutes to automatically archive the thread after recent activity */
autoArchiveDuration: 60 | 1440 | 4320 | 10080
/** Amount of seconds a user has to wait before sending another message (0-21600) */
rateLimitPerUser?: number | null
}

View File

@@ -0,0 +1,62 @@
import { BigString, ChannelTypes, DiscordChannel } from '@discordeno/types'
import { WithReason } from '../../../index.js'
import type { RestManager } from '../../../restManager.js'
import { Channel } from '../../../transformers/channel.js'
/**
* Creates a thread without using a message as the thread's point of origin.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel in which to create the thread.
* @param options - The parameters to use for the creation of the thread.
* @returns An instance of the created {@link Channel | Thread}.
*
* @remarks
* Creating a private thread requires the server to be boosted.
*
* Fires a _Thread Create_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#start-thread-without-message}
*/
export async function startThreadWithoutMessage (
rest: RestManager,
channelId: BigString,
options: StartThreadWithoutMessage
): Promise<Channel> {
const result = await rest.runMethod<DiscordChannel>(
rest,
'POST',
rest.constants.routes.THREAD_START_PRIVATE(channelId),
{
name: options.name,
auto_archive_duration: options.autoArchiveDuration,
rate_limit_per_user: options.rateLimitPerUser,
type: options.type,
invitable: options.invitable,
reason: options.reason
}
)
return rest.transformers.channel(rest, {
channel: result,
guildId: result.guild_id
? rest.transformers.snowflake(result.guild_id)
: undefined
})
}
export interface StartThreadWithoutMessage extends WithReason {
/** 1-100 character thread name */
name: string
/** Duration in minutes to automatically archive the thread after recent activity */
autoArchiveDuration: 60 | 1440 | 4320 | 10080
/** Amount of seconds a user has to wait before sending another message (0-21600) */
rateLimitPerUser?: number | null
/** the type of thread to create */
type:
| ChannelTypes.AnnouncementThread
| ChannelTypes.PublicThread
| ChannelTypes.PrivateThread
/** whether non-moderators can add other non-moderators to a thread; only available when creating a private thread */
invitable?: boolean
}

View File

@@ -0,0 +1,28 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
export const startTyping = triggerTypingIndicator
/**
* Triggers a typing indicator for the bot user.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel in which to trigger the typing indicator.
*
* @remarks
* Generally, bots should _not_ use this route.
*
* Fires a _Typing Start_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#trigger-typing-indicator}
*/
export async function triggerTypingIndicator (
rest: RestManager,
channelId: BigString
): Promise<void> {
return await rest.runMethod<void>(
rest,
'POST',
rest.constants.routes.CHANNEL_TYPING(channelId)
)
}

View File

@@ -0,0 +1,56 @@
import { DiscordEmoji } from '@discordeno/types'
import { urlToBase64 } from '@discordeno/utils'
import { BigString, WithReason } from '../../index.js'
import type { RestManager } from '../../restManager.js'
import { Emoji } from '../../transformers/emoji.js'
/**
* Creates an emoji in a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild in which to create the emoji.
* @param options - The parameters for the creation of the emoji.
* @returns An instance of the created {@link Emoji}.
*
* @remarks
* Requires the `MANAGE_EMOJIS_AND_STICKERS` permission.
*
* Emojis have a maximum file size of 256 kilobits. Attempting to upload a larger emoji will cause the route to return 400 Bad Request.
*
* Fires a _Guild Emojis Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/emoji#create-guild-emoji}
*/
export async function createEmoji (
rest: RestManager,
guildId: BigString,
options: CreateGuildEmoji
): Promise<Emoji> {
if (options.image && !options.image.startsWith('data:image/')) {
options.image = await urlToBase64(options.image)
}
const result = await rest.runMethod<DiscordEmoji>(
rest,
'POST',
rest.constants.routes.GUILD_EMOJIS(guildId),
{
name: options.name,
image: options.image,
roles: options.roles?.map((role) => role.toString()),
reason: options.reason
}
)
return rest.transformers.emoji(rest, result)
}
/** https://discord.com/developers/docs/resources/emoji#create-guild-emoji */
export interface CreateGuildEmoji extends WithReason {
/** Name of the emoji */
name: string
/** The 128x128 emoji image. Emojis and animated emojis have a maximum file size of 256kb. Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request and an error message, but not a JSON status code. If a URL is provided to the image parameter, Discordeno will automatically convert it to a base64 string internally. */
image: string
/** Roles allowed to use this emoji */
roles?: BigString[]
}

View File

@@ -0,0 +1,32 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
/**
* Deletes an emoji from a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild from which to delete the emoji.
* @param id - The ID of the emoji to delete.
*
* @remarks
* Requires the `MANAGE_EMOJIS_AND_STICKERS` permission.
*
* Fires a _Guild Emojis Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/emoji#delete-guild-emoji}
*/
export async function deleteEmoji (
rest: RestManager,
guildId: BigString,
id: BigString,
reason?: string
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.GUILD_EMOJI(guildId, id),
{
reason
}
)
}

View File

@@ -0,0 +1,51 @@
import { DiscordEmoji } from '@discordeno/types'
import { BigString, WithReason } from '../../index.js'
import type { RestManager } from '../../restManager.js'
import { Emoji } from '../../transformers/emoji.js'
/**
* Edits an emoji.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild in which to edit the emoji.
* @param id - The ID of the emoji to edit.
* @param options - The parameters for the edit of the emoji.
* @returns An instance of the updated {@link Emoji}.
*
* @remarks
* Requires the `MANAGE_EMOJIS_AND_STICKERS` permission.
*
* Fires a `Guild Emojis Update` gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/emoji#modify-guild-emoji}
*/
export async function editEmoji (
rest: RestManager,
guildId: BigString,
id: BigString,
options: ModifyGuildEmoji
): Promise<Emoji> {
const result = await rest.runMethod<DiscordEmoji>(
rest,
'PATCH',
rest.constants.routes.GUILD_EMOJI(guildId, id),
{
name: options.name,
// NEED TERNARY TO SUPPORT NULL AS VALID
roles: options.roles
? options.roles.map((role) => role.toString())
: options.roles,
reason: options.reason
}
)
return rest.transformers.emoji(rest, result)
}
/** https://discord.com/developers/docs/resources/emoji#modify-guild-emoji */
export interface ModifyGuildEmoji extends WithReason {
/** Name of the emoji */
name?: string
/** Roles allowed to use this emoji */
roles?: BigString[] | null
}

View File

@@ -0,0 +1,27 @@
import { BigString, DiscordEmoji } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
import { Emoji } from '../../transformers/emoji.js'
/**
* Gets an emoji by its ID.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild from which to get the emoji.
* @param emojiId - The ID of the emoji to get.
* @returns An instance of {@link Emoji}.
*
* @see {@link https://discord.com/developers/docs/resources/emoji#get-guild-emoji}
*/
export async function getEmoji (
rest: RestManager,
guildId: BigString,
emojiId: BigString
): Promise<Emoji> {
const result = await rest.runMethod<DiscordEmoji>(
rest,
'GET',
rest.constants.routes.GUILD_EMOJI(guildId, emojiId)
)
return rest.transformers.emoji(rest, result)
}

View File

@@ -0,0 +1,19 @@
import { BigString } from '@discordeno/types'
import { RestManager } from '../../restManager.js'
/**
* Builds a URL to an emoji in the Discord CDN.
*
* @param emojiId - The ID of the emoji to access.
* @param animated - Whether the emoji is animated or static.
* @returns The link to the resource.
*/
export function getEmojiURL (
_rest: RestManager,
emojiId: BigString,
animated = false
): string {
return `https://cdn.discordapp.com/emojis/${emojiId}.${
animated ? 'gif' : 'png'
}`
}

View File

@@ -0,0 +1,31 @@
import { BigString, DiscordEmoji } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../restManager.js'
import { Emoji } from '../../transformers/emoji.js'
/**
* Gets the list of emojis for a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild which to get the emojis of.
* @returns A collection of {@link Emoji} objects assorted by emoji ID.
*
* @see {@link https://discord.com/developers/docs/resources/emoji#list-guild-emojis}
*/
export async function getEmojis (
rest: RestManager,
guildId: BigString
): Promise<Collection<bigint, Emoji>> {
const results = await rest.runMethod<DiscordEmoji[]>(
rest,
'GET',
rest.constants.routes.GUILD_EMOJIS(guildId)
)
return new Collection(
results.map((result) => {
const emoji = rest.transformers.emoji(rest, result)
return [emoji.id!, emoji]
})
)
}

View File

@@ -0,0 +1,6 @@
export * from './createEmoji.js'
export * from './deleteEmoji.js'
export * from './editEmoji.js'
export * from './getEmoji.js'
export * from './getEmojis.js'
export * from './getEmojiUrl.js'

View File

@@ -0,0 +1,102 @@
import {
AutoModerationActionType,
AutoModerationEventTypes,
AutoModerationTriggerTypes,
DiscordAutoModerationRule,
DiscordAutoModerationRuleTriggerMetadataPresets,
DiscordCreateAutomoderationRule
} from '@discordeno/types'
import { BigString, WithReason } from '../../../index.js'
import { RestManager } from '../../../restManager.js'
import { AutoModerationRule } from '../../../transformers/automodRule.js'
/**
* Creates an automod rule in a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to create the rule in.
* @param options - The parameters for the creation of the rule.
* @returns An instance of the created {@link AutoModerationRule}.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* Fires an _Auto Moderation Rule Create_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/auto-moderation#create-auto-moderation-rule}
*/
export async function createAutomodRule (
rest: RestManager,
guildId: BigString,
options: CreateAutoModerationRuleOptions
): Promise<AutoModerationRule> {
const result = await rest.runMethod<DiscordAutoModerationRule>(
rest,
'POST',
rest.constants.routes.AUTOMOD_RULES(guildId),
{
name: options.name,
event_type: options.eventType,
trigger_type: options.triggerType,
trigger_metadata: {
keyword_filter: options.triggerMetadata.keywordFilter,
presets: options.triggerMetadata.presets,
allow_list: options.triggerMetadata.allowList,
mention_total_limit: options.triggerMetadata.mentionTotalLimit
},
actions: options.actions.map((action) => ({
type: action.type,
metadata: action.metadata
? {
channel_id: action.metadata.channelId?.toString(),
duration_seconds: action.metadata.durationSeconds
}
: undefined
})),
enabled: options.enabled ?? true,
exempt_roles: options.exemptRoles?.map((id) => id.toString()),
exempt_channels: options.exemptChannels?.map((id) => id.toString()),
reason: options.reason
} as DiscordCreateAutomoderationRule
)
return rest.transformers.automodRule(rest, result)
}
export interface CreateAutoModerationRuleOptions extends WithReason {
/** The name of the rule. */
name: string
/** The type of event to trigger the rule on. */
eventType: AutoModerationEventTypes
/** The type of trigger to use for the rule. */
triggerType: AutoModerationTriggerTypes
/** The metadata to use for the trigger. */
triggerMetadata: {
/** The keywords needed to match. Only present when TriggerType.Keyword */
keywordFilter?: string[]
/** The pre-defined lists of words to match from. Only present when TriggerType.KeywordPreset */
presets?: DiscordAutoModerationRuleTriggerMetadataPresets[]
/** The substrings which will exempt from triggering the preset trigger type. Only present when TriggerType.KeywordPreset */
allowList?: string[]
/** Total number of mentions (role & user) allowed per message (Maximum of 50). Only present when TriggerType.MentionSpam */
mentionTotalLimit?: number
}
/** The actions that will trigger for this rule */
actions: Array<{
/** The type of action to take when a rule is triggered */
type: AutoModerationActionType
/** additional metadata needed during execution for this specific action type */
metadata?: {
/** The id of channel to which user content should be logged. Only in SendAlertMessage */
channelId?: BigString
/** Timeout duration in seconds. Max is 2419200(4 weeks). Only supported for TriggerType.Keyword */
durationSeconds?: number
}
}>
/** Whether the rule should be enabled, true by default. */
enabled?: boolean
/** The role ids that should not be effected by the rule */
exemptRoles?: BigString[]
/** The channel ids that should not be effected by the rule. */
exemptChannels?: BigString[]
}

View File

@@ -0,0 +1,30 @@
import { BigString } from '@discordeno/types'
import { RestManager } from '../../../restManager.js'
/**
* Deletes an automod rule.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to delete the rule from.
* @param ruleId - The ID of the automod rule to delete.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* Fires an _Auto Moderation Rule Delete_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/auto-moderation#delete-auto-moderation-rule}
*/
export async function deleteAutomodRule (
rest: RestManager,
guildId: BigString,
ruleId: BigString,
reason?: string
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.AUTOMOD_RULE(guildId, ruleId),
{ reason }
)
}

View File

@@ -0,0 +1,100 @@
import {
AutoModerationActionType,
AutoModerationEventTypes,
DiscordAutoModerationRule,
DiscordAutoModerationRuleTriggerMetadataPresets
} from '@discordeno/types'
import { BigString, WithReason } from '../../../index.js'
import { RestManager } from '../../../restManager.js'
import { AutoModerationRule } from '../../../transformers/automodRule.js'
/**
* Edits an automod rule.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to edit the rule in.
* @param ruleId - The ID of the rule to edit.
* @param options - The parameters for the edit of the rule.
* @returns An instance of the edited {@link AutoModerationRule}.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* Fires an _Auto Moderation Rule Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/auto-moderation#modify-auto-moderation-rule}
*/
export async function editAutomodRule (
rest: RestManager,
guildId: BigString,
ruleId: BigString,
options: Partial<EditAutoModerationRuleOptions>
): Promise<AutoModerationRule> {
const result = await rest.runMethod<DiscordAutoModerationRule>(
rest,
'PATCH',
rest.constants.routes.AUTOMOD_RULE(guildId, ruleId),
{
name: options.name,
event_type: options.eventType,
trigger_metadata: options.triggerMetadata
? {
keyword_filter: options.triggerMetadata.keywordFilter,
presets: options.triggerMetadata.presets,
allow_list: options.triggerMetadata.allowList,
mention_total_limit: options.triggerMetadata.mentionTotalLimit
}
: undefined,
actions: options.actions?.map((action) => ({
type: action.type,
metadata: {
channel_id: action.metadata.channelId?.toString(),
duration_seconds: action.metadata.durationSeconds
}
})),
enabled: options.enabled ?? true,
exempt_roles: options.exemptRoles?.map((id) => id.toString()),
exempt_channels: options.exemptChannels?.map((id) => id.toString()),
reason: options.reason
}
)
return rest.transformers.automodRule(rest, result)
}
export interface EditAutoModerationRuleOptions extends WithReason {
/** The name of the rule. */
name: string
/** The type of event to trigger the rule on. */
eventType: AutoModerationEventTypes
/** The metadata to use for the trigger. */
triggerMetadata: {
/** The keywords needed to match. Only present when TriggerType.Keyword */
keywordFilter?: string[]
// TODO: This may need a special type or enum
/** The pre-defined lists of words to match from. Only present when TriggerType.KeywordPreset */
presets?: DiscordAutoModerationRuleTriggerMetadataPresets[]
/** The substrings which will exempt from triggering the preset trigger type. Only present when TriggerType.KeywordPreset */
allowList?: string[]
/** Total number of mentions (role & user) allowed per message (Maximum of 50) */
mentionTotalLimit: number
}
/** The actions that will trigger for this rule */
actions: Array<{
/** The type of action to take when a rule is triggered */
type: AutoModerationActionType
/** additional metadata needed during execution for this specific action type */
metadata: {
/** The id of channel to which user content should be logged. Only in SendAlertMessage */
channelId?: BigString
/** Timeout duration in seconds. Only supported for TriggerType.Keyword */
durationSeconds?: number
}
}>
/** Whether the rule should be enabled. */
enabled?: boolean
/** The role ids that should not be effected by the rule */
exemptRoles?: BigString[]
/** The channel ids that should not be effected by the rule. */
exemptChannels?: BigString[]
}

View File

@@ -0,0 +1,30 @@
import { BigString, DiscordAutoModerationRule } from '@discordeno/types'
import { RestManager } from '../../../restManager.js'
import { AutoModerationRule } from '../../../transformers/automodRule.js'
/**
* Gets an automod rule by its ID.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the rule of.
* @param ruleId - The ID of the rule to get.
* @returns An instance of {@link AutoModerationRule}.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* @see {@link https://discord.com/developers/docs/resources/auto-moderation#get-auto-moderation-rule}
*/
export async function getAutomodRule (
rest: RestManager,
guildId: BigString,
ruleId: BigString
): Promise<AutoModerationRule> {
const result = await rest.runMethod<DiscordAutoModerationRule>(
rest,
'GET',
rest.constants.routes.AUTOMOD_RULE(guildId, ruleId)
)
return rest.transformers.automodRule(rest, result)
}

View File

@@ -0,0 +1,34 @@
import { BigString, DiscordAutoModerationRule } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import { RestManager } from '../../../restManager.js'
import { AutoModerationRule } from '../../../transformers/automodRule.js'
/**
* Gets the list of automod rules for a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the rules from.
* @returns A collection of {@link AutoModerationRule} objects assorted by rule ID.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* @see {@link https://discord.com/developers/docs/resources/auto-moderation#list-auto-moderation-rules-for-guild}
*/
export async function getAutomodRules (
rest: RestManager,
guildId: BigString
): Promise<Collection<bigint, AutoModerationRule>> {
const results = await rest.runMethod<DiscordAutoModerationRule[]>(
rest,
'GET',
rest.constants.routes.AUTOMOD_RULES(guildId)
)
return new Collection(
results.map((result) => {
const rule = rest.transformers.automodRule(rest, result)
return [rule.id, rule]
})
)
}

View File

@@ -0,0 +1,5 @@
export * from './createAutomodRule.js'
export * from './deleteAutomodRule.js'
export * from './editAutomodRule.js'
export * from './getAutomodRule.js'
export * from './getAutomodRules.js'

View File

@@ -0,0 +1,77 @@
import {
DefaultMessageNotificationLevels,
DiscordGuild,
ExplicitContentFilterLevels,
SystemChannelFlags,
VerificationLevels
} from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
import { Channel } from '../../transformers/channel.js'
import { Guild } from '../../transformers/guild.js'
import { Role } from '../../transformers/role.js'
/**
* Creates a guild.
*
* @param bot - The bot instance to use to make the request.
* @param options - The parameters for the creation of the guild.
* @returns An instance of the created {@link Guild}.
*
* @remarks
* ⚠️ This route can only be used by bots in __fewer than 10 guilds__.
*
* Fires a _Guild Create_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/guild#create-guild}
*/
export async function createGuild (
rest: RestManager,
options: CreateGuild
): Promise<Guild> {
const result = await rest.runMethod<DiscordGuild>(
rest,
'POST',
rest.constants.routes.GUILDS(),
{
name: options.name,
afk_channel_id: options.afkChannelId,
afk_timeout: options.afkTimeout,
channels: options.channels,
default_message_notifications: options.defaultMessageNotifications,
explicit_content_filter: options.explicitContentFilter,
icon: options.icon,
roles: options.roles,
system_channel_flags: options.systemChannelFlags,
system_channel_id: options.systemChannelId,
verification_level: options.verificationLevel
}
)
return rest.transformers.guild(rest, { guild: result, shardId: 0 })
}
/** https://discord.com/developers/docs/resources/guild#create-guild */
export interface CreateGuild {
/** Name of the guild (1-100 characters) */
name: string
/** Base64 128x128 image for the guild icon */
icon?: string
/** Verification level */
verificationLevel?: VerificationLevels
/** Default message notification level */
defaultMessageNotifications?: DefaultMessageNotificationLevels
/** Explicit content filter level */
explicitContentFilter?: ExplicitContentFilterLevels
/** New guild roles (first role is the everyone role) */
roles?: Role[]
/** New guild's channels */
channels?: Array<Partial<Channel>>
/** Id for afk channel */
afkChannelId?: string
/** Afk timeout in seconds */
afkTimeout?: number
/** The id of the channel where guild notices such as welcome messages and boost events are posted */
systemChannelId?: string
/** System channel flags */
systemChannelFlags?: SystemChannelFlags
}

View File

@@ -0,0 +1,26 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
/**
* Deletes a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to delete.
*
* @remarks
* The bot user must be the owner of the guild.
*
* Fires a _Guild Delete_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/guild#delete-guild}
*/
export async function deleteGuild (
rest: RestManager,
guildId: BigString
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.GUILD(guildId)
)
}

View File

@@ -0,0 +1,128 @@
import {
BigString,
DefaultMessageNotificationLevels,
DiscordGuild,
ExplicitContentFilterLevels,
GuildFeatures,
SystemChannelFlags,
VerificationLevels
} from '@discordeno/types'
import { urlToBase64 } from '@discordeno/utils'
import type { RestManager } from '../../restManager.js'
import { Guild } from '../../transformers/guild.js'
// TODO: Put the `shardId` parameter before `options`.
/**
* Edits a guild's settings.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to edit.
* @param shardId - The ID of the shard the guild is in.
* @param options - The parameters for the edit of the guild.
* @returns An instance of the edited {@link Guild}.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* If attempting to add or remove the {@link GuildFeatures.Community} feature:
* - Requires the `ADMINISTRATOR` permission.
*
* Fires a _Guild Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/guild#modify-guild}
*/
export async function editGuild (
rest: RestManager,
guildId: BigString,
options: ModifyGuild,
shardId: number
): Promise<Guild> {
if (options.icon && !options.icon.startsWith('data:image/')) {
options.icon = await urlToBase64(options.icon)
}
if (options.banner && !options.banner.startsWith('data:image/')) {
options.banner = await urlToBase64(options.banner)
}
if (options.splash && !options.splash.startsWith('data:image/')) {
options.splash = await urlToBase64(options.splash)
}
const result = await rest.runMethod<DiscordGuild>(
rest,
'PATCH',
rest.constants.routes.GUILD(guildId),
{
name: options.name,
verification_levels: options.verificationLevel,
default_message_notifications: options.defaultMessageNotifications,
explicit_content_filter: options.explicitContentFilter,
afk_channel_id: options.afkChannelId
? options.afkChannelId.toString()
: options.afkChannelId,
afk_timeout: options.afkTimeout,
icon: options.icon,
owner_id: options.ownerId ? options.ownerId.toString() : options.ownerId,
splash: options.splash,
discovery_splash: options.discoverySplash,
banner: options.banner,
system_channel_id: options.systemChannelId
? options.systemChannelId.toString()
: options.systemChannelId,
system_channel_flags: options.systemChannelFlags,
rules_channel_id: options.rulesChannelId
? options.rulesChannelId.toString()
: options.rulesChannelId,
public_updates_channel_id: options.publicUpdatesChannelId
? options.publicUpdatesChannelId.toString()
: options.publicUpdatesChannelId,
preferred_locale: options.preferredLocale,
features: options.features,
premium_progress_bar_enabled: options.premiumProgressBarEnabled
}
)
return rest.transformers.guild(rest, { guild: result, shardId })
}
/** https://discord.com/developers/docs/resources/guild#modify-guild */
export interface ModifyGuild {
/** Guild name */
name?: string
/** Verification level */
verificationLevel?: VerificationLevels | null
/** Default message notification filter level */
defaultMessageNotifications?: DefaultMessageNotificationLevels | null
/** Explicit content filter level */
explicitContentFilter?: ExplicitContentFilterLevels | null
/** Id for afk channel */
afkChannelId?: BigString | null
/** Afk timeout in seconds */
afkTimeout?: number
/** Base64 1024x1024 png/jpeg/gif image for the guild icon (can be animated gif when the server has the `ANIMATED_ICON` feature) */
icon?: string | null
/** User id to transfer guild ownership to (must be owner) */
ownerId?: BigString
/** Base64 16:9 png/jpeg image for the guild splash (when the server has `INVITE_SPLASH` feature) */
splash?: string | null
/** Base64 16:9 png/jpeg image for the guild discovery spash (when the server has the `DISCOVERABLE` feature) */
discoverySplash?: string | null
/** Base64 16:9 png/jpeg image for the guild banner (when the server has BANNER feature) */
banner?: string | null
/** The id of the channel where guild notices such as welcome messages and boost events are posted */
systemChannelId?: BigString | null
/** System channel flags */
systemChannelFlags?: SystemChannelFlags
/** The id of the channel where Community guilds display rules and/or guidelines */
rulesChannelId?: BigString | null
/** The id of the channel where admins and moderators of Community guilds receive notices from Discord */
publicUpdatesChannelId?: BigString | null
/** The preferred locale of a Community guild used in server discovery and notices from Discord; defaults to "en-US" */
preferredLocale?: string | null
/** Enabled guild features */
features?: GuildFeatures[]
/** Whether the guild's boost progress bar should be enabled */
premiumProgressBarEnabled?: boolean
}

View File

@@ -0,0 +1,17 @@
import type { BigString, MfaLevels } from '@discordeno/types'
import type { RestManager } from '../../index.js'
/** Modify a guild's MFA level. Requires guild ownership. */
export async function editGuildMfaLevel (
rest: RestManager,
guildId: BigString,
mfaLevel: MfaLevels,
reason?: string
): Promise<void> {
return await rest.runMethod<void>(
rest,
'POST',
rest.constants.routes.GUILD_MFA_LEVEL(guildId),
{ level: mfaLevel, reason }
)
}

View File

@@ -0,0 +1,63 @@
import { BigString, DiscordWelcomeScreen } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
import { WelcomeScreen } from '../../transformers/welcomeScreen.js'
/**
* Edits a guild's welcome screen.
*
* @param bot - The bot instance to use to make the request.
* @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}
*/
export async function editWelcomeScreen (
rest: RestManager,
guildId: BigString,
options: ModifyGuildWelcomeScreen
): Promise<WelcomeScreen> {
const result = await rest.runMethod<DiscordWelcomeScreen>(
rest,
'PATCH',
rest.constants.routes.GUILD_WELCOME_SCREEN(guildId),
{
enabled: options.enabled,
welcome_screen: options.welcomeScreen?.map((welcomeScreen) => ({
channel_id: welcomeScreen.channelId,
description: welcomeScreen.description,
emoji_id: welcomeScreen.emojiId,
emoji_name: welcomeScreen.emojiName
})),
description: options.description
}
)
return rest.transformers.welcomeScreen(rest, result)
}
/** https://discord.com/developers/docs/resources/guild#modify-guild-welcome-screen */
export interface ModifyGuildWelcomeScreen {
/** Whether the welcome screen is enabled */
enabled?: boolean | null
/** Channels linked in the welcome screen and their display options */
welcomeScreen?: WelcomeScreenChannel[] | null
/** The server description to show in the welcome screen */
description?: string | null
}
export interface WelcomeScreenChannel {
/** The channel's id */
channelId: BigString
/** The emoji id, if the emoji is custom */
emojiId?: BigString
/** The emoji name if custom, the unicode character if standard, or `null` if no emoji is set */
emojiName?: string
/** The description shown for the channel */
description: string
}

View File

@@ -0,0 +1,111 @@
import {
BigString,
DiscordScheduledEvent,
ScheduledEventEntityType,
ScheduledEventPrivacyLevel
} from '@discordeno/types'
import { validateLength } from '@discordeno/utils'
import { WithReason } from '../../../index.js'
import { RestManager } from '../../../restManager.js'
import { ScheduledEvent } from '../../../transformers/scheduledEvent.js'
/**
* Creates a scheduled event in a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to create the scheduled event in.
* @param options - The parameters for the creation of the scheduled event.
* @returns An instance of the created {@link ScheduledEvent}.
*
* @remarks
* Requires the `MANAGE_EVENTS` permission.
*
* A guild can only have a maximum of 100 events with a status of {@link ScheduledEventStatus.Active} or {@link ScheduledEventStatus.Scheduled} (inclusive).
*
* Fires a _Guild Scheduled Event Create_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#create-guild-scheduled-event}
*/
export async function createScheduledEvent (
rest: RestManager,
guildId: BigString,
options: CreateScheduledEvent
): Promise<ScheduledEvent> {
if (!validateLength(options.name, { min: 1, max: 100 })) {
throw new Error('Name must be between 1-100 characters.')
}
if (
options.description &&
!validateLength(options.description, { max: 1000 })
) {
throw new Error('Description must be below 1000 characters.')
}
if (options.location) {
if (!validateLength(options.location, { max: 100 })) {
throw new Error('Location must be below 100 characters.')
}
if (options.entityType === ScheduledEventEntityType.Voice) {
throw new Error('Location can not be provided for a Voice event.')
}
}
if (options.entityType === ScheduledEventEntityType.External) {
if (!options.scheduledEndTime) {
throw new Error(
'A scheduled end time is required when making an External event.'
)
}
if (!options.location) {
throw new Error('A location is required when making an External event.')
}
}
if (
options.scheduledStartTime &&
options.scheduledEndTime &&
options.scheduledStartTime > options.scheduledEndTime
) {
throw new Error('Cannot schedule event to end before starting.')
}
const result = await rest.runMethod<DiscordScheduledEvent>(
rest,
'POST',
rest.constants.routes.GUILD_SCHEDULED_EVENTS(guildId),
{
channel_id: options.channelId?.toString(),
entity_metadata: options.location
? { location: options.location }
: undefined,
name: options.name,
description: options.description,
scheduled_start_time: new Date(options.scheduledStartTime).toISOString(),
scheduled_end_time: options.scheduledEndTime
? new Date(options.scheduledEndTime).toISOString()
: undefined,
privacy_level:
options.privacyLevel ?? ScheduledEventPrivacyLevel.GuildOnly,
entity_type: options.entityType,
reason: options.reason
}
)
return rest.transformers.scheduledEvent(rest, result)
}
export interface CreateScheduledEvent extends WithReason {
/** the channel id of the scheduled event. */
channelId?: BigString
/** location of the event. Required for events with `entityType: ScheduledEventEntityType.External` */
location?: string
/** the name of the scheduled event */
name: string
/** the description of the scheduled event */
description: string
/** the time the scheduled event will start */
scheduledStartTime: number
/** the time the scheduled event will end if it does end. Required for events with `entityType: ScheduledEventEntityType.External` */
scheduledEndTime?: number
/** the privacy level of the scheduled event */
privacyLevel?: ScheduledEventPrivacyLevel
/** the type of hosting entity associated with a scheduled event */
entityType: ScheduledEventEntityType
}

View File

@@ -0,0 +1,28 @@
import { BigString } from '@discordeno/types'
import { RestManager } from '../../../restManager.js'
/**
* Deletes a scheduled event from a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to delete the scheduled event from.
* @param eventId - The ID of the scheduled event to delete.
*
* @remarks
* Requires the `MANAGE_EVENTS` permission.
*
* Fires a _Guild Scheduled Event Delete_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#delete-guild-scheduled-event}
*/
export async function deleteScheduledEvent (
rest: RestManager,
guildId: BigString,
eventId: BigString
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.GUILD_SCHEDULED_EVENT(guildId, eventId)
)
}

View File

@@ -0,0 +1,103 @@
import {
BigString,
DiscordScheduledEvent,
ScheduledEventEntityType,
ScheduledEventPrivacyLevel,
ScheduledEventStatus
} from '@discordeno/types'
import { validateLength } from '@discordeno/utils'
import { WithReason } from '../../../index.js'
import { RestManager } from '../../../restManager.js'
import { ScheduledEvent } from '../../../transformers/scheduledEvent.js'
/**
* Edits a scheduled event.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to edit the scheduled event in.
* @param eventId - The ID of the scheduled event to edit.
* @returns An instance of the edited {@link ScheduledEvent}.
*
* @remarks
* Requires the `MANAGE_EVENTS` permission.
*
* To start or end an event, modify the event's `status` property.
*
* The `entity_metadata` property is discarded for events whose `entity_type` is not {@link ScheduledEventEntityType.External}.
*
* Fires a _Guild Scheduled Event Update_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#modify-guild-scheduled-event}
*/
export async function editScheduledEvent (
rest: RestManager,
guildId: BigString,
eventId: BigString,
options: Partial<EditScheduledEvent>
): Promise<ScheduledEvent> {
if (options.name && !validateLength(options.name, { min: 1, max: 100 })) {
throw new Error('Name must be between 1-100 characters.')
}
if (
options.description &&
!validateLength(options.description, { max: 1000 })
) {
throw new Error('Description must be below 1000 characters.')
}
if (options.location && !validateLength(options.location, { max: 100 })) {
throw new Error('Location must be below 100 characters.')
}
if (
options.scheduledStartTime &&
options.scheduledEndTime &&
options.scheduledStartTime > options.scheduledEndTime
) {
throw new Error('Cannot schedule event to end before starting.')
}
const result = await rest.runMethod<DiscordScheduledEvent>(
rest,
'PATCH',
rest.constants.routes.GUILD_SCHEDULED_EVENT(guildId, eventId),
{
channel_id:
options.channelId === null ? null : options.channelId?.toString(),
entity_metadata: options.location ? { location: options.location } : null,
name: options.name,
description: options.description,
scheduled_start_time: options.scheduledStartTime
? new Date(options.scheduledStartTime).toISOString()
: undefined,
scheduled_end_time: options.scheduledEndTime
? new Date(options.scheduledEndTime).toISOString()
: undefined,
privacy_level: options.privacyLevel,
entity_type: options.entityType,
status: options.status,
reason: options.reason
}
)
return rest.transformers.scheduledEvent(rest, result)
}
export interface EditScheduledEvent extends WithReason {
/** the channel id of the scheduled event. null if switching to external event. */
channelId: BigString | null
/** location of the event */
location?: string
/** the name of the scheduled event */
name: string
/** the description of the scheduled event */
description?: string
/** the time the scheduled event will start */
scheduledStartTime: number
/** the time the scheduled event will end if it does end. */
scheduledEndTime?: number
/** the privacy level of the scheduled event */
privacyLevel: ScheduledEventPrivacyLevel
/** the type of hosting entity associated with a scheduled event */
entityType: ScheduledEventEntityType
/** the status of the scheduled event */
status: ScheduledEventStatus
}

View File

@@ -0,0 +1,33 @@
import { BigString, DiscordScheduledEvent } from '@discordeno/types'
import { RestManager } from '../../../restManager.js'
import { ScheduledEvent } from '../../../transformers/scheduledEvent.js'
/**
* Gets a scheduled event by its ID.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the scheduled event from.
* @param eventId - The ID of the scheduled event to get.
* @param options - The parameters for the fetching of the scheduled event.
* @returns An instance of {@link ScheduledEvent}.
*
* @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#get-guild-scheduled-event}
*/
export async function getScheduledEvent (
rest: RestManager,
guildId: BigString,
eventId: BigString,
options?: { withUserCount?: boolean }
): Promise<ScheduledEvent> {
const result = await rest.runMethod<DiscordScheduledEvent>(
rest,
'GET',
rest.constants.routes.GUILD_SCHEDULED_EVENT(
guildId,
eventId,
options?.withUserCount
)
)
return rest.transformers.scheduledEvent(rest, result)
}

View File

@@ -0,0 +1,101 @@
import { BigString, DiscordMember, DiscordUser } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import { RestManager } from '../../../restManager.js'
import { Member, User } from '../../../transformers/member.js'
// TODO: This endpoint discards certain data from the result.
// Create `ScheduledEventUser` type and parse the data to it.
/**
* Gets the list of subscribers to a scheduled event from a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the subscribers to the scheduled event from.
* @param eventId - The ID of the scheduled event to get the subscribers of.
* @param options - The parameters for the fetching of the subscribers.
* @returns A collection of {@link User} objects assorted by user ID.
*
* @remarks
* Requires the `MANAGE_EVENTS` permission.
*
* Users are ordered by their IDs in _ascending_ order.
*
* @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#get-guild-scheduled-event-users}
*/
export async function getScheduledEventUsers (
rest: RestManager,
guildId: BigString,
eventId: BigString,
options?: GetScheduledEventUsers & { withMember?: false }
): Promise<Collection<bigint, User>>
export async function getScheduledEventUsers (
rest: RestManager,
guildId: BigString,
eventId: BigString,
options?: GetScheduledEventUsers & { withMember: true }
): Promise<Collection<bigint, { user: User, member: Member }>>
export async function getScheduledEventUsers (
rest: RestManager,
guildId: BigString,
eventId: BigString,
options?: GetScheduledEventUsers
): Promise<
Collection<bigint, User> | Collection<bigint, { user: User, member: Member }>
> {
let url = rest.constants.routes.GUILD_SCHEDULED_EVENT_USERS(
guildId,
eventId,
options
)
if (options != null) {
url = '?'
if (options.limit) url += `limit=${options.limit}`
if (options.withMember !== undefined) {
url += `&with_member=${options.withMember.toString()}`
}
if (options.after) url += `&after=${options.after}`
if (options.before) url += `&before=${options.before}`
}
const results = await rest.runMethod<
Array<{ user: DiscordUser, member?: DiscordMember }>
>(rest, 'GET', url)
if (!options?.withMember) {
return new Collection(
results.map((result) => {
const user = rest.transformers.user(rest, result.user)
return [user.id, user]
})
)
}
const id = rest.transformers.snowflake(guildId)
return new Collection(
results.map((result) => {
const user = rest.transformers.user(rest, result.user)
const member = rest.transformers.member(
rest,
result.member!,
id,
user.id
)
return [user.id, { member, user }]
})
)
}
export interface GetScheduledEventUsers {
/** number of users to return (up to maximum 100), defaults to 100 */
limit?: number
/** whether to also have member objects provided, defaults to false */
withMember?: boolean
/** consider only users before given user id */
before?: BigString
/** consider only users after given user id. If both before and after are provided, only before is respected. Fetching users in-between before and after is not supported. */
after?: BigString
}

View File

@@ -0,0 +1,41 @@
import { BigString, DiscordScheduledEvent } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import { RestManager } from '../../../restManager.js'
import { ScheduledEvent } from '../../../transformers/scheduledEvent.js'
/**
* Gets the list of scheduled events for a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the scheduled events from.
* @param options - The parameters for the fetching of the scheduled events.
* @returns A collection of {@link ScheduledEvent} objects assorted by event ID.
*
* @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#list-scheduled-events-for-guild}
*/
export async function getScheduledEvents (
rest: RestManager,
guildId: BigString,
options?: GetScheduledEvents
): Promise<Collection<bigint, ScheduledEvent>> {
const results = await rest.runMethod<DiscordScheduledEvent[]>(
rest,
'GET',
rest.constants.routes.GUILD_SCHEDULED_EVENTS(
guildId,
options?.withUserCount
)
)
return new Collection(
results.map((result) => {
const event = rest.transformers.scheduledEvent(rest, result)
return [event.id, event]
})
)
}
export interface GetScheduledEvents {
/** include number of users subscribed to each event */
withUserCount?: boolean
}

View File

@@ -0,0 +1,6 @@
export * from './createScheduledEvent.js'
export * from './deleteScheduledEvent.js'
export * from './editScheduledEvent.js'
export * from './getScheduledEvent.js'
export * from './getScheduledEvents.js'
export * from './getScheduledEventUsers.js'

View File

@@ -0,0 +1,131 @@
import { AuditLogEvents, BigString, DiscordAuditLog } from '@discordeno/types'
import { iconHashToBigInt } from '@discordeno/utils'
import type { RestManager } from '../../restManager.js'
import { ApplicationCommand } from '../../transformers/applicationCommand.js'
import { AuditLogEntry } from '../../transformers/auditLogEntry.js'
import { AutoModerationRule } from '../../transformers/automodRule.js'
import { Channel } from '../../transformers/channel.js'
import { Integration } from '../../transformers/integration.js'
import { User } from '../../transformers/member.js'
import { ScheduledEvent } from '../../transformers/scheduledEvent.js'
import { Webhook } from '../../transformers/webhook.js'
export interface AuditLog {
auditLogEntries: AuditLogEntry[]
autoModerationRules?: AutoModerationRule[]
guildScheduledEvents?: ScheduledEvent[]
integrations: Array<Partial<Omit<Integration, 'guildId'>>>
threads: Channel[]
users: User[]
webhooks: Webhook[]
applicationCommands: ApplicationCommand[]
}
// TODO: Move `AuditLog` into its own transformer file.
/**
* Gets a guild's audit log.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the audit log of.
* @param options - The parameters for the fetching of the audit log.
* @returns An instance of {@link AuditLog}.
*
* @remarks
* Requires the `VIEW_AUDIT_LOG` permission.
*
* @see {@link https://discord.com/developers/docs/resources/audit-log#get-guild-audit-log}
*/
export async function getAuditLog (
rest: RestManager,
guildId: BigString,
options?: GetGuildAuditLog
): Promise<AuditLog> {
if (options?.limit) {
options.limit =
options.limit >= 1 && options.limit <= 100 ? options.limit : 50
}
const result = await rest.runMethod<DiscordAuditLog>(
rest,
'GET',
rest.constants.routes.GUILD_AUDIT_LOGS(guildId, options)
)
const id = rest.transformers.snowflake(guildId)
return {
auditLogEntries: result.audit_log_entries.map((entry) =>
rest.transformers.auditLogEntry(rest, entry)
),
autoModerationRules: result.auto_moderation_rules?.map((rule) =>
rest.transformers.automodRule(rest, rule)
),
guildScheduledEvents: result.guild_scheduled_events?.map((event) =>
rest.transformers.scheduledEvent(rest, event)
),
integrations: result.integrations.map((integration) => ({
id: integration.id
? rest.transformers.snowflake(integration.id)
: undefined,
name: integration.name,
type: integration.type,
enabled: integration.enabled,
syncing: integration.syncing,
roleId: integration.role_id
? rest.transformers.snowflake(integration.role_id)
: undefined,
enableEmoticons: integration.enable_emoticons,
expireBehavior: integration.expire_behavior,
expireGracePeriod: integration.expire_grace_period,
user: integration.user
? rest.transformers.user(rest, integration.user)
: undefined,
account: integration.account
? {
id: rest.transformers.snowflake(integration.account.id),
name: integration.account.name
}
: undefined,
syncedAt: integration.synced_at
? Date.parse(integration.synced_at)
: undefined,
subscriberCount: integration.subscriber_count,
revoked: integration.revoked,
application: integration.application
? {
id: rest.transformers.snowflake(integration.application.id),
name: integration.application.name,
icon: integration.application.icon
? iconHashToBigInt(integration.application.icon)
: undefined,
description: integration.application.description,
bot: integration.application.bot
? rest.transformers.user(rest, integration.application.bot)
: undefined
}
: undefined
})),
threads: result.threads.map((thread) =>
rest.transformers.channel(rest, { channel: thread, guildId: id })
),
users: result.users.map((user) => rest.transformers.user(rest, user)),
webhooks: result.webhooks.map((hook) =>
rest.transformers.webhook(rest, hook)
),
applicationCommands: result.application_commands.map((applicationCommand) =>
rest.transformers.applicationCommand(rest, applicationCommand)
)
}
}
/** https://discord.com/developers/docs/resources/audit-log#get-guild-audit-log-query-string-parameters */
export interface GetGuildAuditLog {
/** Entries from a specific user ID */
userId?: BigString | string
/** Entries for a specific audit log event */
actionType?: AuditLogEvents
/** Entries that preceded a specific audit log entry ID */
before?: BigString | string
/** Maximum number of entries (between 1-100) to return, defaults to 50 */
limit?: number
}

View File

@@ -0,0 +1,40 @@
import { BigString, DiscordBan } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
import { User } from '../../transformers/member.js'
export interface Ban {
reason?: string
user: User
}
// TODO: Move `Ban` into its own transformer file.
/**
* Gets a ban by user ID.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the ban from.
* @param userId - The ID of the user to get the ban for.
* @returns An instance of {@link Ban}.
*
* @remarks
* Requires the `BAN_MEMBERS` permission.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-ban}
*/
export async function getBan (
rest: RestManager,
guildId: BigString,
userId: BigString
): Promise<Ban> {
const result = await rest.runMethod<DiscordBan>(
rest,
'GET',
rest.constants.routes.GUILD_BAN(guildId, userId)
)
return {
reason: result.reason ?? undefined,
user: rest.transformers.user(rest, result.user)
}
}

View File

@@ -0,0 +1,53 @@
import { BigString, DiscordBan } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../restManager.js'
import { Ban } from './getBan.js'
/**
* Gets the list of bans for a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the list of bans for.
* @param options - The parameters for the fetching of the list of bans.
* @returns A collection of {@link Ban} objects assorted by user ID.
*
* @remarks
* Requires the `BAN_MEMBERS` permission.
*
* Users are ordered by their IDs in _ascending_ order.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-bans}
*/
export async function getBans (
rest: RestManager,
guildId: BigString,
options?: GetBans
): Promise<Collection<bigint, Ban>> {
const results = await rest.runMethod<DiscordBan[]>(
rest,
'GET',
rest.constants.routes.GUILD_BANS(guildId, options)
)
return new Collection(
results.map<[bigint, Ban]>((result) => {
const user = rest.transformers.user(rest, result.user)
return [
user.id,
{
reason: result.reason ?? undefined,
user
}
]
})
)
}
export interface GetBans {
/** Number of users to return (up to maximum 1000). Default: 1000 */
limit?: number
/** Consider only users before given user id */
before?: BigString
/** Consider only users after given user id */
after?: BigString
}

View File

@@ -0,0 +1,36 @@
import { BigString, ImageFormat, ImageSize } from '@discordeno/types'
import { formatImageURL, iconBigintToHash } from '@discordeno/utils'
import type { RestManager } from '../../restManager.js'
// TODO: Move `banner` from `options` into the parameters and rename to `imageHash`.
/**
* Builds a URL to the guild banner stored in the Discord CDN.
*
* @param bot - The bot instance to use to build the URL.
* @param guildId - The ID of the guild to get the link to the banner for.
* @param options - The parameters for the building of the URL.
* @returns The link to the resource or `undefined` if no banner has been set.
*/
export function getGuildBannerURL (
rest: RestManager,
guildId: BigString,
options: {
banner?: string | bigint
size?: ImageSize
format?: ImageFormat
}
): string | undefined {
return options.banner
? formatImageURL(
rest.constants.routes.GUILD_BANNER(
guildId,
typeof options.banner === 'string'
? options.banner
: iconBigintToHash(options.banner)
),
options.size ?? 128,
options.format
)
: undefined
}

View File

@@ -0,0 +1,34 @@
import { BigString, ImageFormat, ImageSize } from '@discordeno/types'
import { formatImageURL, iconBigintToHash } from '@discordeno/utils'
import type { RestManager } from '../../restManager.js'
/**
* Builds a URL to the guild icon stored in the Discord CDN.
*
* @param bot - The bot instance to use to build the URL.
* @param guildId - The ID of the guild to get the link to the banner for.
* @param options - The parameters for the building of the URL.
* @returns The link to the resource or `undefined` if no banner has been set.
*/
export function getGuildIconURL (
rest: RestManager,
guildId: BigString,
imageHash: BigString | undefined,
options?: {
size?: ImageSize
format?: ImageFormat
}
): string | undefined {
return imageHash
? formatImageURL(
rest.constants.routes.GUILD_ICON(
guildId,
typeof imageHash === 'string'
? imageHash
: iconBigintToHash(imageHash)
),
options?.size ?? 128,
options?.format
)
: undefined
}

View File

@@ -0,0 +1,63 @@
import {
BigString,
DiscordGuildPreview,
GuildFeatures
} from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
import { Emoji } from '../../transformers/emoji.js'
import { Sticker } from '../../transformers/sticker.js'
export interface GuildPreview {
id: BigString
name?: string
icon?: string
splash?: string
discoverySplash?: string
emojis?: Emoji[]
features: GuildFeatures[]
approximateMemberCount: number
approximatePresenceCount: number
description?: string
stickers: Sticker[]
}
// TODO: Move `GuildPreview` into its own transformer file.
/**
* Gets the preview of a guild by a guild's ID.
*
* @param bot - The bot instance to use to make the request.
* @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}
*/
export async function getGuildPreview (
rest: RestManager,
guildId: BigString
): Promise<GuildPreview> {
const result = await rest.runMethod<DiscordGuildPreview>(
rest,
'GET',
rest.constants.routes.GUILD_PREVIEW(guildId)
)
return {
id: rest.transformers.snowflake(result.id),
name: result.name,
icon: result.icon ?? undefined,
splash: result.splash ?? undefined,
discoverySplash: result.discovery_splash ?? undefined,
emojis: result.emojis.map((emoji) => rest.transformers.emoji(rest, emoji)),
features: result.features,
approximateMemberCount: result.approximate_member_count,
approximatePresenceCount: result.approximate_presence_count,
description: result.description ?? undefined,
stickers: result.stickers.map((sticker) =>
rest.transformers.sticker(rest, sticker)
)
}
}

View File

@@ -0,0 +1,35 @@
import { BigString, ImageFormat, ImageSize } from '@discordeno/types'
import { formatImageURL, iconBigintToHash } from '@discordeno/utils'
import type { RestManager } from '../../restManager.js'
/**
* Builds the URL to a guild splash stored in the Discord CDN.
*
* @param bot - The bot instance to use to build the URL.
* @param guildId - The ID of the guild to get the splash of.
* @param imageHash - The hash identifying the splash image.
* @param options - The parameters for the building of the URL.
* @returns The link to the resource or `undefined` if the guild does not have a splash image set.
*/
export function getGuildSplashURL (
rest: RestManager,
guildId: BigString,
imageHash: BigString | undefined,
options?: {
size?: ImageSize
format?: ImageFormat
}
): string | undefined {
return imageHash
? formatImageURL(
rest.constants.routes.GUILD_SPLASH(
guildId,
typeof imageHash === 'string'
? imageHash
: iconBigintToHash(imageHash)
),
options?.size ?? 128,
options?.format
)
: undefined
}

View File

@@ -0,0 +1,44 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
interface DiscordPrunedCount {
pruned: number
}
/**
* Gets the number of members that would be kicked from a guild during pruning.
*
* @param bot - The bot instance used to make the request
* @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}
*/
export async function getPruneCount (
rest: RestManager,
guildId: BigString,
options?: GetGuildPruneCountQuery
): Promise<number> {
if (options?.days && options.days < 1) { throw new Error(rest.constants.Errors.PRUNE_MIN_DAYS) }
if (options?.days && options.days > 30) { throw new Error(rest.constants.Errors.PRUNE_MAX_DAYS) }
const result = await rest.runMethod<DiscordPrunedCount>(
rest,
'GET',
rest.constants.routes.GUILD_PRUNE(guildId)
)
return result.pruned
}
/** https://discord.com/developers/docs/resources/guild#get-guild-prune-count */
export interface GetGuildPruneCountQuery {
/** Number of days to count prune for (1 or more), default: 7 */
days?: number
/** Role(s) to include, default: none */
includeRoles?: string | string[]
}

View File

@@ -0,0 +1,34 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
export interface VanityUrl {
code: string | null
uses: number
}
// TODO: Move `VanityUrl` into its own transformer file.
/**
* Gets information about the vanity url of a guild.
*
* @param bot - The bot instance used to make the request
* @param guildId - The ID of the guild to get the vanity url information for.
* @returns An instance of {@link VanityUrl}.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* The `code` property will be `null` if the guild does not have a set vanity url.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-vanity-url}
*/
export async function getVanityUrl (
rest: RestManager,
guildId: BigString
): Promise<VanityUrl> {
return await rest.runMethod<VanityUrl>(
rest,
'GET',
rest.constants.routes.GUILD_VANITY_URL(guildId)
)
}

View File

@@ -0,0 +1,29 @@
import { BigString, DiscordWelcomeScreen } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
import { WelcomeScreen } from '../../transformers/welcomeScreen.js'
/**
* Gets the welcome screen for a guild.
*
* @param bot - The bot instance used to make the request
* @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}
*/
export async function getWelcomeScreen (
rest: RestManager,
guildId: BigString
): Promise<WelcomeScreen> {
const result = await rest.runMethod<DiscordWelcomeScreen>(
rest,
'GET',
rest.constants.routes.GUILD_WELCOME_SCREEN(guildId)
)
return rest.transformers.welcomeScreen(rest, result)
}

View File

@@ -0,0 +1,22 @@
export * from './automod/index.js'
export * from './createGuild.js'
export * from './deleteGuild.js'
export * from './editGuild.js'
export * from './editGuildMfaLevel.js'
export * from './editWelcomeScreen.js'
export * from './events/index.js'
export * from './getAuditLog.js'
export * from './getBan.js'
export * from './getBans.js'
export * from './getGuildBannerUrl.js'
export * from './getGuildIconUrl.js'
export * from './getGuildPreview.js'
export * from './getGuildSplashUrl.js'
export * from './getPruneCount.js'
export * from './getVanityUrl.js'
export * from './getWelcomeScreen.js'
export * from './integrations/index.js'
export * from './invites/index.js'
export * from './leaveGuild.js'
export * from './voice/index.js'
export * from './widget/index.js'

View File

@@ -0,0 +1,31 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
/**
* Deletes an integration attached to a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild from which to delete the integration.
* @param integrationId - The ID of the integration to delete from the guild.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* Deletes all webhooks associated with the integration, and kicks the associated bot if there is one.
*
* Fires a _Guild Integrations Update_ gateway event.
* Fires a _Integration Delete_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/guild#delete-guild-integration}
*/
export async function deleteIntegration (
rest: RestManager,
guildId: BigString,
integrationId: BigString
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.GUILD_INTEGRATION(guildId, integrationId)
)
}

View File

@@ -0,0 +1,52 @@
import { BigString, DiscordIntegration } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../../restManager.js'
import { Integration } from '../../../transformers/integration.js'
/**
* Gets the list of integrations attached to a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the list of integrations from.
* @returns A collection of {@link Integration} objects assorted by integration ID.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-integrations}
*/
export async function getIntegrations (
rest: RestManager,
guildId: BigString
): Promise<Collection<bigint, Integration>> {
const results = await rest.runMethod<DiscordIntegration[]>(
rest,
'GET',
rest.constants.routes.GUILD_INTEGRATIONS(guildId)
)
return new Collection(
results.map((result) => {
const integration = rest.transformers.integration(rest, {
guild_id: guildId.toString(),
id: result.id,
name: result.name,
type: result.type,
enabled: result.enabled,
syncing: result.syncing,
role_id: result.role_id,
enable_emoticons: result.enable_emoticons,
expire_behavior: result.expire_behavior,
expire_grace_period: result.expire_grace_period,
user: result.user,
account: result.account,
synced_at: result.synced_at,
subscriber_count: result.subscriber_count,
revoked: result.revoked,
application: result.application,
scopes: result.scopes
})
return [integration.id, integration]
})
)
}

View File

@@ -0,0 +1,2 @@
export * from './deleteIntegration.js'
export * from './getIntegrations.js'

View File

@@ -0,0 +1,84 @@
import { BigString, DiscordInvite, TargetTypes } from '@discordeno/types'
import { WithReason } from '../../../index.js'
import type { RestManager } from '../../../restManager.js'
import { BaseInvite } from './getInvite.js'
/**
* Creates an invite to a channel in a guild.
*
* @param bot - The bot instance to use to make the request.
* @param channelId - The ID of the channel to create the invite to.
* @param options - The parameters for the creation of the invite.
* @returns An instance of the created {@link BaseInvite | Invite}.
*
* @remarks
* Requires the `CREATE_INSTANT_INVITE` permission.
*
* Fires an _Invite Create_ gateway event.
*
* @privateRemarks
* The request body is not optional, and an empty JSON object must be sent regardless of whether any fields are being transmitted.
*
* @see {@link https://discord.com/developers/docs/resources/channel#create-channel-invite}
*/
export async function createInvite (
rest: RestManager,
channelId: BigString,
options: CreateChannelInvite = {}
): Promise<BaseInvite> {
const result = await rest.runMethod<DiscordInvite>(
rest,
'POST',
rest.constants.routes.CHANNEL_INVITES(channelId),
{
max_age: options.maxAge,
max_uses: options.maxUses,
temporary: options.temporary,
unique: options.unique,
target_type: options.targetType,
target_user_id: options.targetUserId?.toString(),
target_application_id: options.targetApplicationId?.toString(),
reason: options.reason
}
)
return {
code: result.code,
guildId: result.guild?.id
? rest.transformers.snowflake(result.guild.id)
: undefined,
channelId: result.channel?.id
? rest.transformers.snowflake(result.channel.id)
: undefined,
inviter: result.inviter
? rest.transformers.user(rest, result.inviter)
: undefined,
targetType: result.target_type,
targetUser: result.target_user
? rest.transformers.user(rest, result.target_user)
: undefined,
targetApplicationId: result.target_application?.id
? rest.transformers.snowflake(result.target_application.id)
: undefined,
approximatePresenceCount: result.approximate_presence_count,
approximateMemberCount: result.approximate_member_count,
expiresAt: result.expires_at ? Date.parse(result.expires_at) : undefined
}
}
export interface CreateChannelInvite extends WithReason {
/** Duration of invite in seconds before expiry, or 0 for never. Between 0 and 604800 (7 days). Default: 86400 (24 hours) */
maxAge?: number
/** Max number of users or 0 for unlimited. Between 0 and 100. Default: 0 */
maxUses?: number
/** Whether this invite only grants temporary membership. Default: false */
temporary?: boolean
/** If true, don't try to reuse similar invite (useful for creating many unique one time use invites). Default: false */
unique?: boolean
/** The type of target for this voice channel invite */
targetType?: TargetTypes
/** The id of the user whose stream to display for this invite, required if `target_type` is 1, the user must be streaming in the channel */
targetUserId?: BigString
/** The id of the embedded application to open for this invite, required if `target_type` is 2, the application must have the `EMBEDDED` flag */
targetApplicationId?: BigString
}

View File

@@ -0,0 +1,27 @@
import type { RestManager } from '../../../restManager.js'
/**
* Deletes an invite to a channel.
*
* @param bot - The bot instance to use to make the request.
* @param inviteCode - The invite code of the invite to delete.
*
* @remarks
* Requires the `MANAGE_CHANNELS` permission.
*
* Fires an _Invite Delete_ gateway event.
*
* @see {@link https://discord.com/developers/docs/resources/channel#delete-channel-invite}
*/
export async function deleteInvite (
rest: RestManager,
inviteCode: string,
reason?: string
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.INVITE(inviteCode),
reason ? { reason } : undefined
)
}

View File

@@ -0,0 +1,89 @@
import {
BigString,
DiscordInviteMetadata,
TargetTypes
} from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
import { User } from '../../../transformers/member.js'
import { ScheduledEvent } from '../../../transformers/scheduledEvent.js'
export interface BaseInvite {
code: string
guildId?: BigString
channelId?: BigString
inviter?: User
targetType?: TargetTypes
targetUser?: User
targetApplicationId?: BigString
approximatePresenceCount?: number
approximateMemberCount?: number
expiresAt?: number
guildScheduledEvent?: ScheduledEvent
}
export type InviteMetadata = BaseInvite & {
uses: number
maxUses: number
maxAge: number
temporary: boolean
createdAt: number
}
/**
* Gets an invite to a channel by its invite code.
*
* @param bot - The bot instance to use to make the request.
* @param inviteCode - The invite code of the invite to get.
* @param options - The parameters for the fetching of the invite.
* @returns An instance of {@link BaseInvite | Invite}.
*
* @see {@link https://discord.com/developers/docs/resources/invite#get-invite}
*/
export async function getInvite (
rest: RestManager,
inviteCode: string,
options?: GetInvite
): Promise<BaseInvite> {
const result = await rest.runMethod<DiscordInviteMetadata>(
rest,
'GET',
rest.constants.routes.INVITE(inviteCode, options)
)
return {
code: result.code,
guildId: result.guild?.id
? rest.transformers.snowflake(result.guild.id)
: undefined,
channelId: result.channel?.id
? rest.transformers.snowflake(result.channel.id)
: undefined,
inviter: result.inviter
? rest.transformers.user(rest, result.inviter)
: undefined,
targetType: result.target_type
? result.target_type === 1
? TargetTypes.Stream
: TargetTypes.EmbeddedApplication
: undefined,
targetUser: result.target_user
? rest.transformers.user(rest, result.target_user)
: undefined,
targetApplicationId: result.target_application?.id
? rest.transformers.snowflake(result.target_application.id)
: undefined,
approximatePresenceCount: result.approximate_presence_count,
approximateMemberCount: result.approximate_member_count,
expiresAt: result.expires_at ? Date.parse(result.expires_at) : undefined
}
}
/** https://discord.com/developers/docs/resources/invite#get-invite */
export interface GetInvite {
/** Whether the invite should contain approximate member counts */
withCounts?: boolean
/** Whether the invite should contain the expiration date */
withExpiration?: boolean
/** the guild scheduled event to include with the invite */
scheduledEventId?: BigString
}

View File

@@ -0,0 +1,74 @@
import {
BigString,
DiscordInviteMetadata,
TargetTypes
} from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../../restManager.js'
import { InviteMetadata } from './getInvite.js'
/**
* Gets the list of invites for a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the invites from.
* @returns A collection of {@link InviteMetadata | Invite} objects assorted by invite code.
*
* @remarks
* Requires the `MANAGE_GUILD` permission.
*
* @see {@link https://discord.com/developers/docs/resources/invite#get-invites}
*/
export async function getInvites (
rest: RestManager,
guildId: BigString
): Promise<Collection<string, InviteMetadata>> {
const results = await rest.runMethod<DiscordInviteMetadata[]>(
rest,
'GET',
rest.constants.routes.GUILD_INVITES(guildId)
)
return new Collection(
results.map<[string, InviteMetadata]>((result) => {
const inviteMetadata = {
code: result.code,
guildId: result.guild?.id
? rest.transformers.snowflake(result.guild.id)
: undefined,
channelId: result.channel?.id
? rest.transformers.snowflake(result.channel.id)
: undefined,
inviter: result.inviter
? rest.transformers.user(rest, result.inviter)
: undefined,
targetType: result.target_type
? result.target_type === 1
? TargetTypes.Stream
: TargetTypes.EmbeddedApplication
: undefined,
targetUser: result.target_user
? rest.transformers.user(rest, result.target_user)
: undefined,
targetApplicationId: result.target_application?.id
? rest.transformers.snowflake(result.target_application.id)
: undefined,
approximatePresenceCount: result.approximate_presence_count,
approximateMemberCount: result.approximate_member_count,
expiresAt: result.expires_at
? Date.parse(result.expires_at)
: undefined,
guildScheduledEvent: result.guild_scheduled_event
? rest.transformers.scheduledEvent(rest, result.guild_scheduled_event)
: undefined,
// Metadata structure
uses: result.uses,
maxUses: result.max_uses,
maxAge: result.max_age,
temporary: result.temporary,
createdAt: Date.parse(result.created_at)
}
return [inviteMetadata.code, inviteMetadata]
})
)
}

View File

@@ -0,0 +1,4 @@
export * from './createInvite.js'
export * from './deleteInvite.js'
export * from './getInvite.js'
export * from './getInvites.js'

View File

@@ -0,0 +1,24 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../restManager.js'
/**
* Leaves a guild.
*
* @param bot - The bot instance used to make the request
* @param guildId - The ID of the guild to leave.
*
* @remarks
* Fires a _Guild Delete_ event.
*
* @see {@link https://discord.com/developers/docs/resources/user#leave-guild}
*/
export async function leaveGuild (
rest: RestManager,
guildId: BigString
): Promise<void> {
return await rest.runMethod<void>(
rest,
'DELETE',
rest.constants.routes.GUILD_LEAVE(guildId)
)
}

View File

@@ -0,0 +1,94 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
export const updateBotVoiceState = editOwnVoiceState
/**
* Edits the voice state of the bot user.
*
* @param bot - The bot instance 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.
*
* @remarks
* The {@link EditOwnVoiceState.channelId | channelId} property of the {@link options} object parameter must point to a stage channel, and the bot user must already have joined it.
*
* If attempting to unmute oneself:
* - Requires the `MUTE_MEMBERS` permission.
*
* If attempting to request to speak:
* - Requires the `REQUEST_TO_SPEAK` permission.
*
* @see {@link https://discord.com/developers/docs/resources/guild#modify-current-user-voice-state}
*/
export async function editOwnVoiceState (
rest: RestManager,
guildId: BigString,
options: EditOwnVoiceState
): Promise<void> {
return await rest.runMethod<void>(
rest,
'PATCH',
rest.constants.routes.UPDATE_VOICE_STATE(guildId),
{
channel_id: options.channelId,
suppress: options.suppress,
request_to_speak_timestamp: options.requestToSpeakTimestamp
? new Date(options.requestToSpeakTimestamp).toISOString()
: options.requestToSpeakTimestamp
}
)
}
// TODO: Make the `userId` property of `options` its own parameter.
/**
* Edits the voice state of another user.
*
* @param bot - The bot instance 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.
*
* @remarks
* The {@link EditOwnVoiceState.channelId | channelId} property of the {@link options} object parameter must point to a stage channel, and the user must already have joined it.
*
* Requires the `MUTE_MEMBERS` permission.
*
* @see {@link https://discord.com/developers/docs/resources/guild#modify-current-user-voice-state}
*/
export async function editUserVoiceState (
rest: RestManager,
guildId: BigString,
options: EditUserVoiceState
): Promise<void> {
return await rest.runMethod<void>(
rest,
'PATCH',
rest.constants.routes.UPDATE_VOICE_STATE(guildId, options.userId),
{
channel_id: options.channelId,
suppress: options.suppress,
user_id: options.userId
}
)
}
/** https://discord.com/developers/docs/resources/guild#update-current-user-voice-state */
export interface EditOwnVoiceState {
/** The id of the channel the user is currently in */
channelId: BigString
/** Toggles the user's suppress state */
suppress?: boolean
/** Sets the user's request to speak */
requestToSpeakTimestamp?: number | null
}
/** https://discord.com/developers/docs/resources/guild#update-user-voice-state */
export interface EditUserVoiceState {
/** The id of the channel the user is currently in */
channelId: BigString
/** Toggles the user's suppress state */
suppress?: boolean
/** The user id to target */
userId: BigString
}

View File

@@ -0,0 +1,27 @@
import { DiscordVoiceRegion } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../../restManager.js'
import { VoiceRegions } from '../../../transformers/voiceRegion.js'
/**
* Gets the list of available voice regions.
*
* @param bot - The bot instance to use to make the request.
* @returns A collection of {@link VoiceRegions | VoiceRegion} objects assorted by voice region ID.
*/
export async function getAvailableVoiceRegions (
rest: RestManager
): Promise<Collection<string, VoiceRegions>> {
const results = await rest.runMethod<DiscordVoiceRegion[]>(
rest,
'GET',
rest.constants.routes.VOICE_REGIONS()
)
return new Collection(
results.map((result) => {
const region = rest.transformers.voiceRegion(rest, result)
return [region.id, region]
})
)
}

View File

@@ -0,0 +1,31 @@
import { BigString, DiscordVoiceRegion } from '@discordeno/types'
import { Collection } from '@discordeno/utils'
import type { RestManager } from '../../../restManager.js'
import { VoiceRegions } from '../../../transformers/voiceRegion.js'
/**
* Gets the list of voice regions for a guild.
*
* @param bot - The bot instance to use to make the request.
* @param guildId - The ID of the guild to get the voice regions for.
* @returns A collection of {@link VoiceRegions | VoiceRegion} objects assorted by voice region ID.
*
* @see {@link https://discord.com/developers/docs/resources/guild#get-guild-voice-regions}
*/
export async function getVoiceRegions (
rest: RestManager,
guildId: BigString
): Promise<Collection<string, VoiceRegions>> {
const results = await rest.runMethod<DiscordVoiceRegion[]>(
rest,
'GET',
rest.constants.routes.GUILD_REGIONS(guildId)
)
return new Collection(
results.map((result) => {
const region = rest.transformers.voiceRegion(rest, result)
return [region.id, region]
})
)
}

View File

@@ -0,0 +1,3 @@
export * from './editVoiceState.js'
export * from './getAvailableVoiceRegions.js'
export * from './getVoiceRegions.js'

View File

@@ -0,0 +1,38 @@
import { BigString, DiscordGuildWidgetSettings } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
import { GuildWidgetSettings } from '../../../transformers/widgetSettings.js'
// TODO: Use `options` instead of `enabled` and `channelId`.
/**
* Edits the settings of a guild's widget.
*
* @param bot - The bot instance to use to make the request.
* @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}
*/
export async function editWidgetSettings (
rest: RestManager,
guildId: BigString,
enabled: boolean,
channelId?: string | null
): Promise<GuildWidgetSettings> {
const result = await rest.runMethod<DiscordGuildWidgetSettings>(
rest,
'PATCH',
rest.constants.routes.GUILD_WIDGET(guildId),
{
enabled,
channel_id: channelId
}
)
return rest.transformers.widgetSettings(rest, result)
}

View File

@@ -0,0 +1,25 @@
import { BigString, DiscordGuildWidget } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
import { GuildWidget } from '../../../transformers/widget.js'
/**
* Gets the guild widget by guild ID.
*
* @param bot - The bot instance to use to make the request.
* @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}
*/
export async function getWidget (
rest: RestManager,
guildId: BigString
): Promise<GuildWidget> {
const result = await rest.runMethod<DiscordGuildWidget>(
rest,
'GET',
rest.constants.routes.GUILD_WIDGET_JSON(guildId)
)
return rest.transformers.widget(rest, result)
}

View File

@@ -0,0 +1,32 @@
import { BigString } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
/**
* Builds a URL to the guild widget image stored in the Discord CDN.
*
* @param bot - The bot instance to use to build the URL.
* @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 (
rest: RestManager,
guildId: BigString,
options?: GetGuildWidgetImageQuery
): string {
return rest.constants.routes.GUILD_WIDGET_IMAGE(guildId, options?.style)
}
/** 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

@@ -0,0 +1,28 @@
import { BigString, DiscordGuildWidgetSettings } from '@discordeno/types'
import type { RestManager } from '../../../restManager.js'
import { GuildWidgetSettings } from '../../../transformers/widgetSettings.js'
/**
* Gets the settings of a guild's widget.
*
* @param bot - The bot instance to use to make the request.
* @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}
*/
export async function getWidgetSettings (
rest: RestManager,
guildId: BigString
): Promise<GuildWidgetSettings> {
const result = await rest.runMethod<DiscordGuildWidgetSettings>(
rest,
'GET',
rest.constants.routes.GUILD_WIDGET(guildId)
)
return rest.transformers.widgetSettings(rest, result)
}

View File

@@ -0,0 +1,4 @@
export * from './editWidgetSettings.js'
export * from './getWidget.js'
export * from './getWidgetImageUrl.js'
export * from './getWidgetSettings.js'

Some files were not shown because too many files have changed in this diff Show More