breaking?: shorters methods

This commit is contained in:
Marcos Susaña 2024-03-17 22:15:18 -04:00
parent 6d4e0589b1
commit f58be61f98
18 changed files with 942 additions and 887 deletions

View File

@ -28,14 +28,8 @@ import type { RestArguments } from '../api';
import type { ProxyRequestMethod } from '../Router'; import type { ProxyRequestMethod } from '../Router';
export interface ApplicationRoutes { export interface ApplicationRoutes {
applications: { applications: (id: string) => {
( guilds: (id: string) => {
id: string,
): {
guilds: {
(
id: string,
): {
commands: { commands: {
get( get(
args?: RestArguments<ProxyRequestMethod.Get, RESTGetAPIApplicationGuildCommandsQuery>, args?: RestArguments<ProxyRequestMethod.Get, RESTGetAPIApplicationGuildCommandsQuery>,
@ -71,7 +65,6 @@ export interface ApplicationRoutes {
}; };
}; };
}; };
};
commands: { commands: {
get( get(
args?: RestArguments<ProxyRequestMethod.Get, RESTGetAPIApplicationCommandsQuery>, args?: RestArguments<ProxyRequestMethod.Get, RESTGetAPIApplicationCommandsQuery>,
@ -101,5 +94,4 @@ export interface ApplicationRoutes {
}; };
}; };
}; };
};
} }

View File

@ -66,10 +66,7 @@ export interface ChannelRoutes {
): Promise<RESTPatchAPIChannelResult>; ): Promise<RESTPatchAPIChannelResult>;
//. //.
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelResult>; delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelResult>;
users: { users: (id: '@me') => {
(
id: '@me',
): {
threads: { threads: {
archived: { archived: {
private: { private: {
@ -81,7 +78,6 @@ export interface ChannelRoutes {
}; };
}; };
}; };
};
'thread-members': { 'thread-members': {
//. //.
get( get(
@ -131,10 +127,7 @@ export interface ChannelRoutes {
}; };
}; };
}; };
recipients: { recipients: (id: string) => {
(
id: string,
): {
//. //.
put( put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIChannelRecipientJSONBody>, args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIChannelRecipientJSONBody>,
@ -142,7 +135,6 @@ export interface ChannelRoutes {
//. //.
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelRecipientResult>; delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelRecipientResult>;
}; };
};
pins: { pins: {
//. //.
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIChannelPinsResult>; get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIChannelPinsResult>;
@ -161,10 +153,7 @@ export interface ChannelRoutes {
args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIChannelFollowersJSONBody>, args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIChannelFollowersJSONBody>,
): Promise<RESTPostAPIChannelFollowersResult>; ): Promise<RESTPostAPIChannelFollowersResult>;
}; };
permissions: { permissions: (id: string) => {
(
id: string,
): {
//. //.
put( put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIChannelPermissionJSONBody>, args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIChannelPermissionJSONBody>,
@ -172,7 +161,6 @@ export interface ChannelRoutes {
//. //.
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelPermissionResult>; delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelPermissionResult>;
}; };
};
invites: { invites: {
//. //.
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIChannelInvitesResult>; get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIChannelInvitesResult>;

View File

@ -3,17 +3,9 @@ import type { RestArguments } from '../api';
import type { ProxyRequestMethod } from '../Router'; import type { ProxyRequestMethod } from '../Router';
export interface InteractionRoutes { export interface InteractionRoutes {
interactions: { interactions: (id: string) => (token: string) => {
(
id: string,
): {
(
token: string,
): {
callback: { callback: {
post(args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIInteractionCallbackJSONBody>): Promise<never>; post(args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIInteractionCallbackJSONBody>): Promise<never>;
}; };
}; };
};
};
} }

View File

@ -65,10 +65,7 @@ export interface WebhookRoutes {
>, >,
): Promise<RESTPostAPIWebhookWithTokenGitHubResult | RESTPostAPIWebhookWithTokenGitHubWaitResult>; ): Promise<RESTPostAPIWebhookWithTokenGitHubResult | RESTPostAPIWebhookWithTokenGitHubWaitResult>;
}; };
messages: { messages: (id: string | '@original') => {
(
id: string | '@original',
): {
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIWebhookWithTokenMessageResult>; get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIWebhookWithTokenMessageResult>;
patch( patch(
args: RestArguments<ProxyRequestMethod.Patch, RESTPatchAPIWebhookWithTokenMessageJSONBody>, args: RestArguments<ProxyRequestMethod.Patch, RESTPatchAPIWebhookWithTokenMessageJSONBody>,
@ -77,5 +74,4 @@ export interface WebhookRoutes {
}; };
}; };
}; };
};
} }

View File

@ -7,20 +7,23 @@ import type { MiddlewareContext } from '../commands/applications/shared';
import { CommandHandler } from '../commands/handler'; import { CommandHandler } from '../commands/handler';
import { import {
ChannelShorter, ChannelShorter,
EmojiShorter,
GuildShorter, GuildShorter,
LogLevels, LogLevels,
Logger, Logger,
MemberShorter,
MessageShorter,
ReactionShorter,
RoleShorter,
TemplateShorter,
UsersShorter, UsersShorter,
WebhookShorter,
filterSplit, filterSplit,
magicImport, magicImport,
type LocaleString, type LocaleString,
type MakeRequired, type MakeRequired,
} from '../common'; } from '../common';
import { MemberShorter } from '../common/shorters/members';
import { MessageShorter } from '../common/shorters/messages';
import { RoleShorter } from '../common/shorters/roles';
import { TemplateShorter } from '../common/shorters/templates';
import { WebhookShorter } from '../common/shorters/webhook';
import type { DeepPartial, IntentStrings, OmitInsert } from '../common/types/util'; import type { DeepPartial, IntentStrings, OmitInsert } from '../common/types/util';
import { ComponentHandler } from '../components/handler'; import { ComponentHandler } from '../components/handler';
import { LangsHandler } from '../langs/handler'; import { LangsHandler } from '../langs/handler';
@ -30,14 +33,16 @@ export class BaseClient {
rest!: ApiHandler; rest!: ApiHandler;
cache!: Cache; cache!: Cache;
users = new UsersShorter(this).users; users = new UsersShorter(this);
channels = new ChannelShorter(this).channels; channels = new ChannelShorter(this);
guilds = new GuildShorter(this).guilds; guilds = new GuildShorter(this);
messages = new MessageShorter(this).messages; messages = new MessageShorter(this);
members = new MemberShorter(this).members; members = new MemberShorter(this);
webhooks = new WebhookShorter(this).webhooks; webhooks = new WebhookShorter(this);
templates = new TemplateShorter(this).templates; templates = new TemplateShorter(this);
roles = new RoleShorter(this).roles; roles = new RoleShorter(this);
reactions = new ReactionShorter(this);
emojis = new EmojiShorter(this);
debugger?: Logger; debugger?: Logger;

View File

@ -5,8 +5,15 @@ export * from 'discord-api-types/v10';
export * from './it/colors'; export * from './it/colors';
export * from './it/logger'; export * from './it/logger';
export * from './shorters/channels'; export * from './shorters/channels';
export * from './shorters/emojis';
export * from './shorters/guilds'; export * from './shorters/guilds';
export * from './shorters/members';
export * from './shorters/messages';
export * from './shorters/reactions';
export * from './shorters/roles';
export * from './shorters/templates';
export * from './shorters/users'; export * from './shorters/users';
export * from './shorters/webhook';
export * from './types/options'; export * from './types/options';
export * from './types/resolvables'; export * from './types/resolvables';
export * from './types/util'; export * from './types/util';

View File

@ -250,6 +250,7 @@ export async function magicImport(path: string) {
try { try {
return require(path); return require(path);
} catch { } catch {
// biome-ignore lint/security/noGlobalEval: modules import broke
return eval('((path) => import(`file:///${path}`))')(path.split('\\').join('\\\\')); return eval('((path) => import(`file:///${path}`))')(path.split('\\').join('\\\\'));
} }
} }
@ -263,6 +264,7 @@ export function fakePromise<T = unknown | Promise<unknown>>(
} { } {
if (value instanceof Promise) return value as any; if (value instanceof Promise) return value as any;
return { return {
// biome-ignore lint/suspicious/noThenProperty: magic
then: callback => callback(value as Awaited<T>), then: callback => callback(value as Awaited<T>),
}; };
} }

View File

@ -5,15 +5,13 @@ import { PermissionsBitField } from '../../structures/extra/Permissions';
import { BaseShorter } from './base'; import { BaseShorter } from './base';
export class ChannelShorter extends BaseShorter { export class ChannelShorter extends BaseShorter {
get channels() {
return {
/** /**
* Fetches a channel by its ID. * Fetches a channel by its ID.
* @param id The ID of the channel to fetch. * @param id The ID of the channel to fetch.
* @param force Whether to force fetching the channel from the API even if it exists in the cache. * @param force Whether to force fetching the channel from the API even if it exists in the cache.
* @returns A Promise that resolves to the fetched channel. * @returns A Promise that resolves to the fetched channel.
*/ */
fetch: async (id: string, force?: boolean): Promise<AllChannels> => { async fetch(id: string, force?: boolean): Promise<AllChannels> {
let channel; let channel;
if (!force) { if (!force) {
channel = await this.client.cache.channels?.get(id); channel = await this.client.cache.channels?.get(id);
@ -23,7 +21,7 @@ export class ChannelShorter extends BaseShorter {
channel = await this.client.proxy.channels(id).get(); channel = await this.client.proxy.channels(id).get();
await this.client.cache.channels?.patch(id, undefined, channel); await this.client.cache.channels?.patch(id, undefined, channel);
return channelFrom(channel, this.client); return channelFrom(channel, this.client);
}, }
/** /**
* Deletes a channel by its ID. * Deletes a channel by its ID.
@ -31,15 +29,11 @@ export class ChannelShorter extends BaseShorter {
* @param optional Optional parameters for the deletion. * @param optional Optional parameters for the deletion.
* @returns A Promise that resolves to the deleted channel. * @returns A Promise that resolves to the deleted channel.
*/ */
delete: async (id: string, optional: ChannelShorterOptionalParams = { guildId: '@me' }) => { async delete(id: string, optional: ChannelShorterOptionalParams = { guildId: '@me' }): Promise<AllChannels> {
const res = await this.client.proxy.channels(id).delete({ reason: optional.reason }); const res = await this.client.proxy.channels(id).delete({ reason: optional.reason });
await this.client.cache.channels?.removeIfNI( await this.client.cache.channels?.removeIfNI(BaseChannel.__intent__(optional.guildId!), res.id, optional.guildId!);
BaseChannel.__intent__(optional.guildId!),
res.id,
optional.guildId!,
);
return channelFrom(res, this.client); return channelFrom(res, this.client);
}, }
/** /**
* Edits a channel by its ID. * Edits a channel by its ID.
@ -48,11 +42,11 @@ export class ChannelShorter extends BaseShorter {
* @param optional Optional parameters for the editing. * @param optional Optional parameters for the editing.
* @returns A Promise that resolves to the edited channel. * @returns A Promise that resolves to the edited channel.
*/ */
edit: async ( async edit(
id: string, id: string,
body: RESTPatchAPIChannelJSONBody, body: RESTPatchAPIChannelJSONBody,
optional: ChannelShorterOptionalParams = { guildId: '@me' }, optional: ChannelShorterOptionalParams = { guildId: '@me' },
) => { ): Promise<AllChannels> {
const res = await this.client.proxy.channels(id).patch({ body, reason: optional.reason }); const res = await this.client.proxy.channels(id).patch({ body, reason: optional.reason });
await this.client.cache.channels?.setIfNI( await this.client.cache.channels?.setIfNI(
BaseChannel.__intent__(optional.guildId!), BaseChannel.__intent__(optional.guildId!),
@ -68,35 +62,21 @@ export class ChannelShorter extends BaseShorter {
res.permission_overwrites, res.permission_overwrites,
); );
return channelFrom(res, this.client); return channelFrom(res, this.client);
}, }
/** /**
* Sends a typing indicator to the channel. * Sends a typing indicator to the channel.
* @param id The ID of the channel. * @param id The ID of the channel.
* @returns A Promise that resolves when the typing indicator is successfully sent. * @returns A Promise that resolves when the typing indicator is successfully sent.
*/ */
typing: (id: string) => this.client.proxy.channels(id).typing.post(), async typing(id: string): Promise<void> {
await this.client.proxy.channels(id).typing.post();
/**
* Provides access to pinned messages in the channel.
*/
pins: this.pins,
overwrites: this.overwrites,
};
} }
get pins() { async pins(channelId: string): Promise<Message[]> {
return { const messages = await this.client.proxy.channels(channelId).pins.get();
/** return messages.map(message => new Message(this.client, message));
* Fetches pinned messages in the channel. }
* @param channelId The ID of the channel.
* @returns A Promise that resolves to an array of pinned messages.
*/
fetch: (channelId: string) =>
this.client.proxy
.channels(channelId)
.pins.get()
.then(messages => messages.map(message => new Message(this.client, message))),
/** /**
* Pins a message in the channel. * Pins a message in the channel.
@ -105,8 +85,9 @@ export class ChannelShorter extends BaseShorter {
* @param reason The reason for pinning the message. * @param reason The reason for pinning the message.
* @returns A Promise that resolves when the message is successfully pinned. * @returns A Promise that resolves when the message is successfully pinned.
*/ */
set: (messageId: string, channelId: string, reason?: string) => setPin(messageId: string, channelId: string, reason?: string) {
this.client.proxy.channels(channelId).pins(messageId).put({ reason }), return this.client.proxy.channels(channelId).pins(messageId).put({ reason });
}
/** /**
* Unpins a message in the channel. * Unpins a message in the channel.
@ -115,21 +96,18 @@ export class ChannelShorter extends BaseShorter {
* @param reason The reason for unpinning the message. * @param reason The reason for unpinning the message.
* @returns A Promise that resolves when the message is successfully unpinned. * @returns A Promise that resolves when the message is successfully unpinned.
*/ */
delete: (messageId: string, channelId: string, reason?: string) => deletePin(messageId: string, channelId: string, reason?: string) {
this.client.proxy.channels(channelId).pins(messageId).delete({ reason }), return this.client.proxy.channels(channelId).pins(messageId).delete({ reason });
};
} }
get overwrites() { async memberPermissions(channelId: string, member: GuildMember, checkAdmin = true): Promise<PermissionsBitField> {
return {
memberPermissions: async (channelId: string, member: GuildMember, checkAdmin = true) => {
const permissions = await member.fetchPermissions(); const permissions = await member.fetchPermissions();
if (checkAdmin && permissions.has(PermissionFlagsBits.Administrator)) { if (checkAdmin && permissions.has(PermissionFlagsBits.Administrator)) {
return new PermissionsBitField(PermissionsBitField.All); return new PermissionsBitField(PermissionsBitField.All);
} }
const overwrites = await this.overwrites.overwritesFor(channelId, member); const overwrites = await this.overwritesFor(channelId, member);
permissions.remove(overwrites.everyone?.deny.bits ?? 0n); permissions.remove(overwrites.everyone?.deny.bits ?? 0n);
permissions.add(overwrites.everyone?.allow.bits ?? 0n); permissions.add(overwrites.everyone?.allow.bits ?? 0n);
@ -138,8 +116,9 @@ export class ChannelShorter extends BaseShorter {
permissions.remove(overwrites.member?.deny.bits ?? 0n); permissions.remove(overwrites.member?.deny.bits ?? 0n);
permissions.add(overwrites.member?.allow.bits ?? 0n); permissions.add(overwrites.member?.allow.bits ?? 0n);
return permissions; return permissions;
}, }
overwritesFor: async (channelId: string, member: GuildMember) => {
async overwritesFor(channelId: string, member: GuildMember) {
const roleOverwrites = []; const roleOverwrites = [];
let memberOverwrites; let memberOverwrites;
let everyoneOverwrites; let everyoneOverwrites;
@ -161,8 +140,9 @@ export class ChannelShorter extends BaseShorter {
roles: roleOverwrites, roles: roleOverwrites,
member: memberOverwrites, member: memberOverwrites,
}; };
}, }
rolePermissions: async (channelId: string, role: GuildRole, checkAdmin = true) => {
async rolePermissions(channelId: string, role: GuildRole, checkAdmin = true): Promise<PermissionsBitField> {
if (checkAdmin && role.permissions.has(PermissionFlagsBits.Administrator)) { if (checkAdmin && role.permissions.has(PermissionFlagsBits.Administrator)) {
return new PermissionsBitField(PermissionsBitField.All); return new PermissionsBitField(PermissionsBitField.All);
} }
@ -177,8 +157,6 @@ export class ChannelShorter extends BaseShorter {
permissions.remove(roleOverwrites?.deny.bits ?? 0n); permissions.remove(roleOverwrites?.deny.bits ?? 0n);
permissions.add(roleOverwrites?.allow.bits ?? 0n); permissions.add(roleOverwrites?.allow.bits ?? 0n);
return permissions; return permissions;
},
};
} }
} }

View File

@ -0,0 +1,86 @@
import type { APIEmoji, RESTPatchAPIGuildEmojiJSONBody, RESTPostAPIGuildEmojiJSONBody } from 'discord-api-types/v10';
import { GuildEmoji } from '../..';
import { resolveImage } from '../../builders';
import type { ImageResolvable } from '../types/resolvables';
import type { OmitInsert } from '../types/util';
import { BaseShorter } from './base';
export class EmojiShorter extends BaseShorter {
/**
* Retrieves a list of emojis in the guild.
* @param guildId The ID of the guild.
* @param force Whether to force fetching emojis from the API even if they exist in the cache.
* @returns A Promise that resolves to an array of emojis.
*/
async list(guildId: string, force = false) {
let emojis;
if (!force) {
emojis = (await this.client.cache.emojis?.values(guildId)) ?? [];
if (emojis.length) {
return emojis;
}
}
emojis = await this.client.proxy.guilds(guildId).emojis.get();
await this.client.cache.emojis?.set(
emojis.map<[string, APIEmoji]>(x => [x.id!, x]),
guildId,
);
return emojis.map(m => new GuildEmoji(this.client, m, guildId));
}
/**
* Creates a new emoji in the guild.
* @param guildId The ID of the guild.
* @param body The data for creating the emoji.
* @returns A Promise that resolves to the created emoji.
*/
async create(guildId: string, body: OmitInsert<RESTPostAPIGuildEmojiJSONBody, 'image', { image: ImageResolvable }>) {
const bodyResolved = { ...body, image: await resolveImage(body.image) };
const emoji = await this.client.proxy.guilds(guildId).emojis.post({
body: bodyResolved,
});
await this.client.cache.channels?.setIfNI('GuildEmojisAndStickers', emoji.id!, guildId, emoji);
}
/**
* Fetches an emoji by its ID.
* @param guildId The ID of the guild.
* @param emojiId The ID of the emoji to fetch.
* @param force Whether to force fetching the emoji from the API even if it exists in the cache.
* @returns A Promise that resolves to the fetched emoji.
*/
async fetch(guildId: string, emojiId: string, force = false) {
let emoji;
if (!force) {
emoji = await this.client.cache.emojis?.get(emojiId);
if (emoji) return emoji;
}
emoji = await this.client.proxy.guilds(guildId).emojis(emojiId).get();
return new GuildEmoji(this.client, emoji, guildId);
}
/**
* Deletes an emoji from the guild.
* @param guildId The ID of the guild.
* @param emojiId The ID of the emoji to delete.
* @param reason The reason for deleting the emoji.
*/
async delete(guildId: string, emojiId: string, reason?: string) {
await this.client.proxy.guilds(guildId).emojis(emojiId).delete({ reason });
await this.client.cache.channels?.removeIfNI('GuildEmojisAndStickers', emojiId, guildId);
}
/**
* Edits an emoji in the guild.
* @param guildId The ID of the guild.
* @param emojiId The ID of the emoji to edit.
* @param body The data to update the emoji with.
* @param reason The reason for editing the emoji.
* @returns A Promise that resolves to the edited emoji.
*/
async edit(guildId: string, emojiId: string, body: RESTPatchAPIGuildEmojiJSONBody, reason?: string) {
const emoji = await this.client.proxy.guilds(guildId).emojis(emojiId).patch({ body, reason });
await this.client.cache.channels?.setIfNI('GuildEmojisAndStickers', emoji.id!, guildId, emoji);
return new GuildEmoji(this.client, emoji, guildId);
}
}

View File

@ -1,23 +1,21 @@
import type { import type {
APIChannel,
GuildWidgetStyle, GuildWidgetStyle,
RESTGetAPICurrentUserGuildsQuery, RESTGetAPICurrentUserGuildsQuery,
RESTPatchAPIAutoModerationRuleJSONBody, RESTPatchAPIAutoModerationRuleJSONBody,
RESTPatchAPIChannelJSONBody, RESTPatchAPIChannelJSONBody,
RESTPatchAPIGuildChannelPositionsJSONBody, RESTPatchAPIGuildChannelPositionsJSONBody,
RESTPatchAPIGuildEmojiJSONBody,
RESTPatchAPIGuildStickerJSONBody, RESTPatchAPIGuildStickerJSONBody,
RESTPostAPIAutoModerationRuleJSONBody, RESTPostAPIAutoModerationRuleJSONBody,
RESTPostAPIGuildChannelJSONBody, RESTPostAPIGuildChannelJSONBody,
RESTPostAPIGuildEmojiJSONBody,
RESTPostAPIGuildsJSONBody, RESTPostAPIGuildsJSONBody,
} from 'discord-api-types/v10'; } from 'discord-api-types/v10';
import type { ImageResolvable, ObjectToLower, OmitInsert } from '..'; import type { ObjectToLower } from '..';
import { resolveFiles, resolveImage } from '../../builders'; import { resolveFiles } from '../../builders';
import { import {
AnonymousGuild, AnonymousGuild,
BaseChannel, BaseChannel,
Guild, Guild,
GuildEmoji,
GuildMember, GuildMember,
Sticker, Sticker,
type CreateStickerBodyRequest, type CreateStickerBodyRequest,
@ -26,21 +24,16 @@ import channelFrom from '../../structures/channels';
import { BaseShorter } from './base'; import { BaseShorter } from './base';
export class GuildShorter extends BaseShorter { export class GuildShorter extends BaseShorter {
/**
* Provides access to guild-related functionality.
*/
get guilds() {
return {
/** /**
* Creates a new guild. * Creates a new guild.
* @param body The data for creating the guild. * @param body The data for creating the guild.
* @returns A Promise that resolves to the created guild. * @returns A Promise that resolves to the created guild.
*/ */
create: async (body: RESTPostAPIGuildsJSONBody) => { async create(body: RESTPostAPIGuildsJSONBody): Promise<Guild<'api'>> {
const guild = await this.client.proxy.guilds.post({ body }); const guild = await this.client.proxy.guilds.post({ body });
await this.client.cache.guilds?.setIfNI('Guilds', guild.id, guild); await this.client.cache.guilds?.setIfNI('Guilds', guild.id, guild);
return new Guild<'api'>(this.client, guild); return new Guild<'api'>(this.client, guild);
}, }
/** /**
* Fetches a guild by its ID. * Fetches a guild by its ID.
@ -48,7 +41,7 @@ export class GuildShorter extends BaseShorter {
* @param force Whether to force fetching the guild from the API even if it exists in the cache. * @param force Whether to force fetching the guild from the API even if it exists in the cache.
* @returns A Promise that resolves to the fetched guild. * @returns A Promise that resolves to the fetched guild.
*/ */
fetch: async (id: string, force = false) => { async fetch(id: string, force = false) {
if (!force) { if (!force) {
const guild = await this.client.cache.guilds?.get(id); const guild = await this.client.cache.guilds?.get(id);
if (guild) return guild; if (guild) return guild;
@ -57,7 +50,7 @@ export class GuildShorter extends BaseShorter {
const data = await this.client.proxy.guilds(id).get(); const data = await this.client.proxy.guilds(id).get();
await this.client.cache.guilds?.patch(id, data); await this.client.cache.guilds?.patch(id, data);
return (await this.client.cache.guilds?.get(id)) ?? new Guild<'api'>(this.client, data); return (await this.client.cache.guilds?.get(id)) ?? new Guild<'api'>(this.client, data);
}, }
/** /**
* Generates the widget URL for the guild. * Generates the widget URL for the guild.
@ -65,125 +58,34 @@ export class GuildShorter extends BaseShorter {
* @param style The style of the widget. * @param style The style of the widget.
* @returns The generated widget URL. * @returns The generated widget URL.
*/ */
widgetURL: (id: string, style?: GuildWidgetStyle) => { widgetURL(id: string, style?: GuildWidgetStyle) {
const query = new URLSearchParams(); const query = new URLSearchParams();
if (style) { if (style) {
query.append('style', style); query.append('style', style);
} }
return this.client.proxy.guilds(id).widget.get({ query }); return this.client.proxy.guilds(id).widget.get({ query });
}, }
list: (query?: RESTGetAPICurrentUserGuildsQuery) => {
list(query?: RESTGetAPICurrentUserGuildsQuery) {
return this.client.proxy return this.client.proxy
.users('@me') .users('@me')
.guilds.get({ query }) .guilds.get({ query })
.then(guilds => guilds.map(guild => new AnonymousGuild(this.client, { ...guild, splash: null }))); .then(guilds => guilds.map(guild => new AnonymousGuild(this.client, { ...guild, splash: null })));
}, }
fetchSelf: async (id: string) => {
async fetchSelf(id: string) {
const self = await this.client.proxy.guilds(id).members(this.client.botId).get(); const self = await this.client.proxy.guilds(id).members(this.client.botId).get();
await this.client.cache.members?.patch(self.user!.id, id, self); await this.client.cache.members?.patch(self.user!.id, id, self);
return new GuildMember(this.client, self, self.user!, id); return new GuildMember(this.client, self, self.user!, id);
}, }
leave: (id: string) => {
leave(id: string) {
return this.client.proxy return this.client.proxy
.users('@me') .users('@me')
.guilds(id) .guilds(id)
.delete() .delete()
.then(() => this.client.cache.guilds?.removeIfNI('Guilds', id)); .then(() => this.client.cache.guilds?.removeIfNI('Guilds', id));
},
channels: this.channels,
moderation: this.moderation,
stickers: this.stickers,
emojis: this.emojis,
};
}
/**
* Provides access to emoji-related functionality in a guild.
*/
get emojis() {
return {
/**
* Retrieves a list of emojis in the guild.
* @param guildId The ID of the guild.
* @param force Whether to force fetching emojis from the API even if they exist in the cache.
* @returns A Promise that resolves to an array of emojis.
*/
list: async (guildId: string, force = false) => {
let emojis;
if (!force) {
emojis = (await this.client.cache.emojis?.values(guildId)) ?? [];
if (emojis.length) {
return emojis;
}
}
emojis = await this.client.proxy.guilds(guildId).emojis.get();
await this.client.cache.emojis?.set(
emojis.map(x => [x.id!, x]),
guildId,
);
return emojis.map(m => new GuildEmoji(this.client, m, guildId));
},
/**
* Creates a new emoji in the guild.
* @param guildId The ID of the guild.
* @param body The data for creating the emoji.
* @returns A Promise that resolves to the created emoji.
*/
create: async (
guildId: string,
body: OmitInsert<RESTPostAPIGuildEmojiJSONBody, 'image', { image: ImageResolvable }>,
) => {
const bodyResolved = { ...body, image: await resolveImage(body.image) };
const emoji = await this.client.proxy.guilds(guildId).emojis.post({
body: bodyResolved,
});
await this.client.cache.channels?.setIfNI('GuildEmojisAndStickers', emoji.id!, guildId, emoji);
},
/**
* Fetches an emoji by its ID.
* @param guildId The ID of the guild.
* @param emojiId The ID of the emoji to fetch.
* @param force Whether to force fetching the emoji from the API even if it exists in the cache.
* @returns A Promise that resolves to the fetched emoji.
*/
fetch: async (guildId: string, emojiId: string, force = false) => {
let emoji;
if (!force) {
emoji = await this.client.cache.emojis?.get(emojiId);
if (emoji) return emoji;
}
emoji = await this.client.proxy.guilds(guildId).emojis(emojiId).get();
return new GuildEmoji(this.client, emoji, guildId);
},
/**
* Deletes an emoji from the guild.
* @param guildId The ID of the guild.
* @param emojiId The ID of the emoji to delete.
* @param reason The reason for deleting the emoji.
*/
delete: async (guildId: string, emojiId: string, reason?: string) => {
await this.client.proxy.guilds(guildId).emojis(emojiId).delete({ reason });
await this.client.cache.channels?.removeIfNI('GuildEmojisAndStickers', emojiId, guildId);
},
/**
* Edits an emoji in the guild.
* @param guildId The ID of the guild.
* @param emojiId The ID of the emoji to edit.
* @param body The data to update the emoji with.
* @param reason The reason for editing the emoji.
* @returns A Promise that resolves to the edited emoji.
*/
edit: async (guildId: string, emojiId: string, body: RESTPatchAPIGuildEmojiJSONBody, reason?: string) => {
const emoji = await this.client.proxy.guilds(guildId).emojis(emojiId).patch({ body, reason });
await this.client.cache.channels?.setIfNI('GuildEmojisAndStickers', emoji.id!, guildId, emoji);
return new GuildEmoji(this.client, emoji, guildId);
},
};
} }
/** /**
@ -207,7 +109,7 @@ export class GuildShorter extends BaseShorter {
} }
channels = await this.client.proxy.guilds(guildId).channels.get(); channels = await this.client.proxy.guilds(guildId).channels.get();
await this.client.cache.channels?.set( await this.client.cache.channels?.set(
channels.map(x => [x.id, x]), channels.map<[string, APIChannel]>(x => [x.id, x]),
guildId, guildId,
); );
return channels.map(m => channelFrom(m, this.client)); return channels.map(m => channelFrom(m, this.client));

View File

@ -12,35 +12,30 @@ import { GuildMember } from '../../structures';
import { BaseShorter } from './base'; import { BaseShorter } from './base';
export class MemberShorter extends BaseShorter { export class MemberShorter extends BaseShorter {
/**
* Provides access to member-related functionality in a guild.
*/
get members() {
return {
/** /**
* Resolves a member in the guild based on the provided GuildMemberResolvable. * Resolves a member in the guild based on the provided GuildMemberResolvable.
* @param guildId The ID of the guild. * @param guildId The ID of the guild.
* @param resolve The GuildMemberResolvable to resolve. * @param resolve The GuildMemberResolvable to resolve.
* @returns A Promise that resolves to the resolved member. * @returns A Promise that resolves to the resolved member.
*/ */
resolve: async (guildId: string, resolve: GuildMemberResolvable) => { async resolve(guildId: string, resolve: GuildMemberResolvable) {
if (typeof resolve === 'string') { if (typeof resolve === 'string') {
const match: { id?: string } | undefined = resolve.match(FormattingPatterns.User)?.groups; const match: { id?: string } | undefined = resolve.match(FormattingPatterns.User)?.groups;
if (match?.id) { if (match?.id) {
return this.members.fetch(guildId, match.id); return this.fetch(guildId, match.id);
} }
if (resolve.match(/\d{17,20}/)) { if (resolve.match(/\d{17,20}/)) {
return this.members.fetch(guildId, resolve); return this.fetch(guildId, resolve);
} }
return this.members.search(guildId, { query: resolve, limit: 1 }).then(x => x[0]); return this.search(guildId, { query: resolve, limit: 1 }).then(x => x[0]);
} }
if (resolve.id) { if (resolve.id) {
return this.client.members.fetch(guildId, resolve.id); return this.client.members.fetch(guildId, resolve.id);
} }
return resolve.displayName return resolve.displayName
? this.members.search(guildId, { query: resolve.displayName, limit: 1 }).then(x => x[0]) ? this.search(guildId, { query: resolve.displayName, limit: 1 }).then(x => x[0])
: undefined; : undefined;
}, }
/** /**
* Searches for members in the guild based on the provided query. * Searches for members in the guild based on the provided query.
@ -48,7 +43,7 @@ export class MemberShorter extends BaseShorter {
* @param query The query parameters for searching members. * @param query The query parameters for searching members.
* @returns A Promise that resolves to an array of matched members. * @returns A Promise that resolves to an array of matched members.
*/ */
search: async (guildId: string, query?: RESTGetAPIGuildMembersSearchQuery) => { async search(guildId: string, query?: RESTGetAPIGuildMembersSearchQuery) {
const members = await this.client.proxy.guilds(guildId).members.search.get({ const members = await this.client.proxy.guilds(guildId).members.search.get({
query, query,
}); });
@ -57,7 +52,7 @@ export class MemberShorter extends BaseShorter {
guildId, guildId,
); );
return members.map(m => new GuildMember(this.client, m, m.user!, guildId)); return members.map(m => new GuildMember(this.client, m, m.user!, guildId));
}, }
/** /**
* Unbans a member from the guild. * Unbans a member from the guild.
@ -66,9 +61,9 @@ export class MemberShorter extends BaseShorter {
* @param body The request body for unbanning the member. * @param body The request body for unbanning the member.
* @param reason The reason for unbanning the member. * @param reason The reason for unbanning the member.
*/ */
unban: async (guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) => { async unban(guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) {
await this.client.proxy.guilds(guildId).bans(memberId).delete({ reason, body }); await this.client.proxy.guilds(guildId).bans(memberId).delete({ reason, body });
}, }
/** /**
* Bans a member from the guild. * Bans a member from the guild.
@ -77,10 +72,10 @@ export class MemberShorter extends BaseShorter {
* @param body The request body for banning the member. * @param body The request body for banning the member.
* @param reason The reason for banning the member. * @param reason The reason for banning the member.
*/ */
ban: async (guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) => { async ban(guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) {
await this.client.proxy.guilds(guildId).bans(memberId).put({ reason, body }); await this.client.proxy.guilds(guildId).bans(memberId).put({ reason, body });
await this.client.cache.members?.removeIfNI('GuildBans', memberId, guildId); await this.client.cache.members?.removeIfNI('GuildBans', memberId, guildId);
}, }
/** /**
* Kicks a member from the guild. * Kicks a member from the guild.
@ -88,10 +83,10 @@ export class MemberShorter extends BaseShorter {
* @param memberId The ID of the member to kick. * @param memberId The ID of the member to kick.
* @param reason The reason for kicking the member. * @param reason The reason for kicking the member.
*/ */
kick: async (guildId: string, memberId: string, reason?: string) => { async kick(guildId: string, memberId: string, reason?: string) {
await this.client.proxy.guilds(guildId).members(memberId).delete({ reason }); await this.client.proxy.guilds(guildId).members(memberId).delete({ reason });
await this.client.cache.members?.removeIfNI('GuildMembers', memberId, guildId); await this.client.cache.members?.removeIfNI('GuildMembers', memberId, guildId);
}, }
/** /**
* Edits a member in the guild. * Edits a member in the guild.
@ -101,11 +96,11 @@ export class MemberShorter extends BaseShorter {
* @param reason The reason for editing the member. * @param reason The reason for editing the member.
* @returns A Promise that resolves to the edited member. * @returns A Promise that resolves to the edited member.
*/ */
edit: async (guildId: string, memberId: string, body: RESTPatchAPIGuildMemberJSONBody, reason?: string) => { async edit(guildId: string, memberId: string, body: RESTPatchAPIGuildMemberJSONBody, reason?: string) {
const member = await this.client.proxy.guilds(guildId).members(memberId).patch({ body, reason }); const member = await this.client.proxy.guilds(guildId).members(memberId).patch({ body, reason });
await this.client.cache.members?.setIfNI('GuildMembers', memberId, guildId, member); await this.client.cache.members?.setIfNI('GuildMembers', memberId, guildId, member);
return new GuildMember(this.client, member, member.user!, guildId); return new GuildMember(this.client, member, member.user!, guildId);
}, }
/** /**
* Adds a member to the guild. * Adds a member to the guild.
@ -114,7 +109,7 @@ export class MemberShorter extends BaseShorter {
* @param body The request body for adding the member. * @param body The request body for adding the member.
* @returns A Promise that resolves to the added member. * @returns A Promise that resolves to the added member.
*/ */
add: async (guildId: string, memberId: string, body: RESTPutAPIGuildMemberJSONBody) => { async add(guildId: string, memberId: string, body: RESTPutAPIGuildMemberJSONBody) {
const member = await this.client.proxy.guilds(guildId).members(memberId).put({ const member = await this.client.proxy.guilds(guildId).members(memberId).put({
body, body,
}); });
@ -127,7 +122,7 @@ export class MemberShorter extends BaseShorter {
await this.client.cache.members?.setIfNI('GuildMembers', member.user!.id, guildId, member); await this.client.cache.members?.setIfNI('GuildMembers', member.user!.id, guildId, member);
return new GuildMember(this.client, member, member.user!, guildId); return new GuildMember(this.client, member, member.user!, guildId);
}, }
/** /**
* Fetches a member from the guild. * Fetches a member from the guild.
@ -136,7 +131,7 @@ export class MemberShorter extends BaseShorter {
* @param force Whether to force fetching the member from the API even if it exists in the cache. * @param force Whether to force fetching the member from the API even if it exists in the cache.
* @returns A Promise that resolves to the fetched member. * @returns A Promise that resolves to the fetched member.
*/ */
fetch: async (guildId: string, memberId: string, force = false) => { async fetch(guildId: string, memberId: string, force = false) {
let member; let member;
if (!force) { if (!force) {
member = await this.client.cache.members?.get(memberId, guildId); member = await this.client.cache.members?.get(memberId, guildId);
@ -146,7 +141,7 @@ export class MemberShorter extends BaseShorter {
member = await this.client.proxy.guilds(guildId).members(memberId).get(); member = await this.client.proxy.guilds(guildId).members(memberId).get();
await this.client.cache.members?.set(member.user!.id, guildId, member); await this.client.cache.members?.set(member.user!.id, guildId, member);
return new GuildMember(this.client, member, member.user!, guildId); return new GuildMember(this.client, member, member.user!, guildId);
}, }
/** /**
* Lists members in the guild based on the provided query. * Lists members in the guild based on the provided query.
@ -155,7 +150,7 @@ export class MemberShorter extends BaseShorter {
* @param force Whether to force listing members from the API even if they exist in the cache. * @param force Whether to force listing members from the API even if they exist in the cache.
* @returns A Promise that resolves to an array of listed members. * @returns A Promise that resolves to an array of listed members.
*/ */
list: async (guildId: string, query?: RESTGetAPIGuildMembersQuery, force = false) => { async list(guildId: string, query?: RESTGetAPIGuildMembersQuery, force = false) {
let members; let members;
if (!force) { if (!force) {
members = (await this.client.cache.members?.values(guildId)) ?? []; members = (await this.client.cache.members?.values(guildId)) ?? [];
@ -166,35 +161,24 @@ export class MemberShorter extends BaseShorter {
}); });
await this.client.cache.members?.set(members.map(x => [x.user!.id, x]) as [string, APIGuildMember][], guildId); await this.client.cache.members?.set(members.map(x => [x.user!.id, x]) as [string, APIGuildMember][], guildId);
return members.map(m => new GuildMember(this.client, m, m.user!, guildId)); return members.map(m => new GuildMember(this.client, m, m.user!, guildId));
},
/**
* Provides methods to add and remove roles from a guild member.
*/
roles: this.roles,
};
} }
get roles() {
return {
/** /**
* Adds a role to a guild member. * Adds a role to a guild member.
* @param guildId The ID of the guild. * @param guildId The ID of the guild.
* @param memberId The ID of the member to add the role to. * @param memberId The ID of the member to add the role to.
* @param id The ID of the role to add. * @param id The ID of the role to add.
*/ */
add: async (guildId: string, memberId: string, id: string) => { addRole(guildId: string, memberId: string, id: string) {
await this.client.proxy.guilds(guildId).members(memberId).roles(id).put({}); this.client.proxy.guilds(guildId).members(memberId).roles(id).put({});
}, }
/** /**
* Removes a role from a guild member. * Removes a role from a guild member.
* @param guildId The ID of the guild. * @param guildId The ID of the guild.
* @param memberId The ID of the member to remove the role from. * @param memberId The ID of the member to remove the role from.
* @param id The ID of the role to remove. * @param id The ID of the role to remove.
*/ */
remove: async (guildId: string, memberId: string, id: string) => { removeRole(guildId: string, memberId: string, id: string) {
await this.client.proxy.guilds(guildId).members(memberId).roles(id).delete(); return this.client.proxy.guilds(guildId).members(memberId).roles(id).delete();
},
};
} }
} }

View File

@ -1,19 +1,15 @@
import type { import type {
RESTGetAPIChannelMessageReactionUsersQuery,
RESTPatchAPIChannelMessageJSONBody, RESTPatchAPIChannelMessageJSONBody,
RESTPostAPIChannelMessageJSONBody, RESTPostAPIChannelMessageJSONBody,
RESTPostAPIChannelMessagesThreadsJSONBody,
} from 'discord-api-types/v10'; } from 'discord-api-types/v10';
import { resolveFiles } from '../../builders'; import { resolveFiles } from '../../builders';
import { Message, MessagesMethods, User } from '../../structures'; import { Message, MessagesMethods, ThreadChannel } from '../../structures';
import { encodeEmoji, resolveEmoji } from '../../structures/extra/functions';
import type { EmojiResolvable } from '../types/resolvables';
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../types/write'; import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../types/write';
import { BaseShorter } from './base'; import { BaseShorter } from './base';
export class MessageShorter extends BaseShorter { export class MessageShorter extends BaseShorter {
get messages() { async write(channelId: string, { files, ...body }: MessageCreateBodyRequest) {
return {
write: async (channelId: string, { files, ...body }: MessageCreateBodyRequest) => {
const parsedFiles = files ? await resolveFiles(files) : []; const parsedFiles = files ? await resolveFiles(files) : [];
const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIChannelMessageJSONBody>(body); const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIChannelMessageJSONBody>(body);
@ -26,8 +22,8 @@ export class MessageShorter extends BaseShorter {
.then(message => { .then(message => {
return new Message(this.client, message); return new Message(this.client, message);
}); });
}, }
edit: async (messageId: string, channelId: string, { files, ...body }: MessageUpdateBodyRequest) => { async edit(messageId: string, channelId: string, { files, ...body }: MessageUpdateBodyRequest) {
const parsedFiles = files ? await resolveFiles(files) : []; const parsedFiles = files ? await resolveFiles(files) : [];
return this.client.proxy return this.client.proxy
.channels(channelId) .channels(channelId)
@ -39,15 +35,16 @@ export class MessageShorter extends BaseShorter {
.then(message => { .then(message => {
return new Message(this.client, message); return new Message(this.client, message);
}); });
}, }
crosspost: (messageId: string, channelId: string, reason?: string) => {
crosspost(messageId: string, channelId: string, reason?: string) {
return this.client.proxy return this.client.proxy
.channels(channelId) .channels(channelId)
.messages(messageId) .messages(messageId)
.crosspost.post({ reason }) .crosspost.post({ reason })
.then(m => new Message(this.client, m)); .then(m => new Message(this.client, m));
}, }
delete: (messageId: string, channelId: string, reason?: string) => { delete(messageId: string, channelId: string, reason?: string) {
return this.client.proxy return this.client.proxy
.channels(channelId) .channels(channelId)
.messages(messageId) .messages(messageId)
@ -55,80 +52,29 @@ export class MessageShorter extends BaseShorter {
.then(() => { .then(() => {
return this.client.components.onMessageDelete(messageId); return this.client.components.onMessageDelete(messageId);
}); });
}, }
fetch: async (messageId: string, channelId: string) => { fetch(messageId: string, channelId: string) {
return this.client.proxy return this.client.proxy
.channels(channelId) .channels(channelId)
.messages(messageId) .messages(messageId)
.get() .get()
.then(x => new Message(this.client, x)); .then(x => new Message(this.client, x));
}, }
purge: (messages: string[], channelId: string, reason?: string) => { purge(messages: string[], channelId: string, reason?: string) {
return this.client.proxy.channels(channelId).messages['bulk-delete'].post({ body: { messages }, reason }); return this.client.proxy.channels(channelId).messages['bulk-delete'].post({ body: { messages }, reason });
},
reactions: this.reactions,
};
} }
get reactions() { thread(
return {
add: async (messageId: string, channelId: string, emoji: EmojiResolvable) => {
const rawEmoji = await resolveEmoji(emoji, this.client.cache);
if (!rawEmoji) {
throw new Error('Emoji no resolvable');
}
return this.client.proxy
.channels(channelId)
.messages(messageId)
.reactions(encodeEmoji(rawEmoji))('@me')
.put({});
},
delete: async (messageId: string, channelId: string, emoji: EmojiResolvable, userId = '@me') => {
const rawEmoji = await resolveEmoji(emoji, this.client.cache);
if (!rawEmoji) {
throw new Error('Emoji no resolvable');
}
return this.client.proxy
.channels(channelId)
.messages(messageId)
.reactions(encodeEmoji(rawEmoji))(userId)
.delete();
},
fetch: async (
messageId: string,
channelId: string, channelId: string,
emoji: EmojiResolvable, messageId: string,
query?: RESTGetAPIChannelMessageReactionUsersQuery, options: RESTPostAPIChannelMessagesThreadsJSONBody & { reason?: string },
) => { ) {
const rawEmoji = await resolveEmoji(emoji, this.client.cache); const { reason, ...body } = options;
if (!rawEmoji) {
throw new Error('Emoji no resolvable');
}
return this.client.proxy return this.client.proxy
.channels(channelId) .channels(channelId)
.messages(messageId) .messages(messageId)
.reactions(encodeEmoji(rawEmoji)) .threads.post({ body, reason })
.get({ query }) .then(x => new ThreadChannel(this.client, x));
.then(u => u.map(user => new User(this.client, user)));
},
purge: async (messageId: string, channelId: string, emoji?: EmojiResolvable) => {
if (!emoji) {
return this.client.proxy.channels(channelId).messages(messageId).reactions.delete();
}
const rawEmoji = await resolveEmoji(emoji, this.client.cache);
if (!rawEmoji) {
throw new Error('Emoji no resolvable');
}
return this.client.proxy.channels(channelId).messages(messageId).reactions(encodeEmoji(rawEmoji)).delete();
},
};
} }
} }

View File

@ -0,0 +1,60 @@
import type { RESTGetAPIChannelMessageReactionUsersQuery } from 'discord-api-types/v10';
import { User } from '../../structures';
import { encodeEmoji, resolveEmoji } from '../../structures/extra/functions';
import type { EmojiResolvable } from '../types/resolvables';
import { BaseShorter } from './base';
export class ReactionShorter extends BaseShorter {
async add(messageId: string, channelId: string, emoji: EmojiResolvable): Promise<void> {
const rawEmoji = await resolveEmoji(emoji, this.client.cache);
if (!rawEmoji) {
throw new Error('Emoji no resolvable');
}
return this.client.proxy.channels(channelId).messages(messageId).reactions(encodeEmoji(rawEmoji))('@me').put({});
}
async delete(messageId: string, channelId: string, emoji: EmojiResolvable, userId = '@me'): Promise<void> {
const rawEmoji = await resolveEmoji(emoji, this.client.cache);
if (!rawEmoji) {
throw new Error('Emoji no resolvable');
}
return this.client.proxy.channels(channelId).messages(messageId).reactions(encodeEmoji(rawEmoji))(userId).delete();
}
async fetch(
messageId: string,
channelId: string,
emoji: EmojiResolvable,
query?: RESTGetAPIChannelMessageReactionUsersQuery,
): Promise<User[]> {
const rawEmoji = await resolveEmoji(emoji, this.client.cache);
if (!rawEmoji) {
throw new Error('Emoji no resolvable');
}
return this.client.proxy
.channels(channelId)
.messages(messageId)
.reactions(encodeEmoji(rawEmoji))
.get({ query })
.then(u => u.map(user => new User(this.client, user)));
}
async purge(messageId: string, channelId: string, emoji?: EmojiResolvable): Promise<void> {
if (!emoji) {
return this.client.proxy.channels(channelId).messages(messageId).reactions.delete();
}
const rawEmoji = await resolveEmoji(emoji, this.client.cache);
if (!rawEmoji) {
throw new Error('Emoji no resolvable');
}
return this.client.proxy.channels(channelId).messages(messageId).reactions(encodeEmoji(rawEmoji)).delete();
}
}

View File

@ -8,14 +8,27 @@ import { GuildRole } from '../../structures';
import { BaseShorter } from './base'; import { BaseShorter } from './base';
export class RoleShorter extends BaseShorter { export class RoleShorter extends BaseShorter {
get roles() { /**
return { * Creates a new role in the guild.
create: (guildId: string, body: RESTPostAPIGuildRoleJSONBody, reason?: string) => * @param guildId The ID of the guild.
this.client.proxy * @param body The data for creating the role.
* @param reason The reason for creating the role.
* @returns A Promise that resolves when the role is created.
*/
create(guildId: string, body: RESTPostAPIGuildRoleJSONBody, reason?: string) {
return this.client.proxy
.guilds(guildId) .guilds(guildId)
.roles.post({ body, reason }) .roles.post({ body, reason })
.then(res => this.client.cache.roles?.setIfNI('Guilds', res.id, guildId, res)), .then(res => this.client.cache.roles?.setIfNI('Guilds', res.id, guildId, res));
list: async (guildId: string, force = false) => { }
/**
* Retrieves a list of roles in the guild.
* @param guildId The ID of the guild.
* @param force Whether to force fetching roles from the API even if they exist in the cache.
* @returns A Promise that resolves to an array of roles.
*/
async list(guildId: string, force = false) {
let roles: APIRole[] = []; let roles: APIRole[] = [];
if (!force) { if (!force) {
const cachedRoles = (await this.client.cache.roles?.values(guildId)) ?? []; const cachedRoles = (await this.client.cache.roles?.values(guildId)) ?? [];
@ -25,26 +38,50 @@ export class RoleShorter extends BaseShorter {
} }
roles = await this.client.proxy.guilds(guildId).roles.get(); roles = await this.client.proxy.guilds(guildId).roles.get();
await this.client.cache.roles?.set( await this.client.cache.roles?.set(
roles.map(r => [r.id, r]), roles.map<[string, APIRole]>(r => [r.id, r]),
guildId, guildId,
); );
return roles.map(r => new GuildRole(this.client, r, guildId)); return roles.map(r => new GuildRole(this.client, r, guildId));
}, }
edit: (guildId: string, roleId: string, body: RESTPatchAPIGuildRoleJSONBody, reason?: string) => {
/**
* Edits a role in the guild.
* @param guildId The ID of the guild.
* @param roleId The ID of the role to edit.
* @param body The data to update the role with.
* @param reason The reason for editing the role.
* @returns A Promise that resolves when the role is edited.
*/
edit(guildId: string, roleId: string, body: RESTPatchAPIGuildRoleJSONBody, reason?: string) {
return this.client.proxy return this.client.proxy
.guilds(guildId) .guilds(guildId)
.roles(roleId) .roles(roleId)
.patch({ body, reason }) .patch({ body, reason })
.then(res => this.client.cache.roles?.setIfNI('Guilds', roleId, guildId, res)); .then(res => this.client.cache.roles?.setIfNI('Guilds', roleId, guildId, res));
}, }
delete: (guildId: string, roleId: string, reason?: string) => {
/**
* Deletes a role from the guild.
* @param guildId The ID of the guild.
* @param roleId The ID of the role to delete.
* @param reason The reason for deleting the role.
* @returns A Promise that resolves when the role is deleted.
*/
delete(guildId: string, roleId: string, reason?: string) {
return this.client.proxy return this.client.proxy
.guilds(guildId) .guilds(guildId)
.roles(roleId) .roles(roleId)
.delete({ reason }) .delete({ reason })
.then(() => this.client.cache.roles?.removeIfNI('Guilds', roleId, guildId)); .then(() => this.client.cache.roles?.removeIfNI('Guilds', roleId, guildId));
}, }
editPositions: async (guildId: string, body: RESTPatchAPIGuildRolePositionsJSONBody) => {
/**
* Edits the positions of roles in the guild.
* @param guildId The ID of the guild.
* @param body The data to update the positions of roles with.
* @returns A Promise that resolves to an array of edited roles.
*/
async editPositions(guildId: string, body: RESTPatchAPIGuildRolePositionsJSONBody) {
const roles = await this.client.proxy.guilds(guildId).roles.patch({ const roles = await this.client.proxy.guilds(guildId).roles.patch({
body, body,
}); });
@ -55,7 +92,5 @@ export class RoleShorter extends BaseShorter {
); );
} }
return roles.map(x => new GuildRole(this.client, x, guildId)); return roles.map(x => new GuildRole(this.client, x, guildId));
},
};
} }
} }

View File

@ -2,26 +2,27 @@ import type { RESTPatchAPIGuildTemplateJSONBody, RESTPostAPIGuildTemplatesJSONBo
import { BaseShorter } from './base'; import { BaseShorter } from './base';
export class TemplateShorter extends BaseShorter { export class TemplateShorter extends BaseShorter {
get templates() { fetch(code: string) {
return {
fetch: (code: string) => {
return this.client.proxy.guilds.templates(code).get(); return this.client.proxy.guilds.templates(code).get();
}, }
list: (guildId: string) => {
list(guildId: string) {
return this.client.proxy.guilds(guildId).templates.get(); return this.client.proxy.guilds(guildId).templates.get();
}, }
create: (guildId: string, body: RESTPostAPIGuildTemplatesJSONBody) => {
create(guildId: string, body: RESTPostAPIGuildTemplatesJSONBody) {
return this.client.proxy.guilds(guildId).templates.post({ body }); return this.client.proxy.guilds(guildId).templates.post({ body });
}, }
sync: (guildId: string, code: string) => {
sync(guildId: string, code: string) {
return this.client.proxy.guilds(guildId).templates(code).put({}); return this.client.proxy.guilds(guildId).templates(code).put({});
}, }
edit: (guildId: string, code: string, body: RESTPatchAPIGuildTemplateJSONBody) => {
edit(guildId: string, code: string, body: RESTPatchAPIGuildTemplateJSONBody) {
return this.client.proxy.guilds(guildId).templates(code).patch({ body }); return this.client.proxy.guilds(guildId).templates(code).patch({ body });
}, }
delete: (guildId: string, code: string) => {
delete(guildId: string, code: string) {
return this.client.proxy.guilds(guildId).templates(code).delete(); return this.client.proxy.guilds(guildId).templates(code).delete();
},
};
} }
} }

View File

@ -3,6 +3,39 @@ import type { MessageCreateBodyRequest } from '../types/write';
import { BaseShorter } from './base'; import { BaseShorter } from './base';
export class UsersShorter extends BaseShorter { export class UsersShorter extends BaseShorter {
async createDM(userId: string, force = false) {
if (!force) {
const dm = await this.client.cache.channels?.get(userId);
if (dm) return dm as DMChannel;
}
const data = await this.client.proxy.users('@me').channels.post({
body: { recipient_id: userId },
});
await this.client.cache.channels?.set(userId, '@me', data);
return new DMChannel(this.client, data);
}
async deleteDM(userId: string, reason?: string) {
const res = await this.client.proxy.channels(userId).delete({ reason });
await this.client.cache.channels?.removeIfNI(BaseChannel.__intent__('@me'), res.id, '@me');
return new DMChannel(this.client, res);
}
async fetch(userId: string, force = false) {
if (!force) {
const user = await this.client.cache.users?.get(userId);
if (user) return user;
}
const data = await this.client.proxy.users(userId).get();
await this.client.cache.users?.patch(userId, data);
return new User(this.client, data);
}
async write(userId: string, body: MessageCreateBodyRequest) {
return (await this.client.users.createDM(userId)).messages.write(body);
}
get users() { get users() {
return { return {
createDM: async (userId: string, force = false) => { createDM: async (userId: string, force = false) => {

View File

@ -5,34 +5,53 @@ import type {
} from '..'; } from '..';
import { resolveFiles } from '../../builders'; import { resolveFiles } from '../../builders';
import { import {
type MessageWebhookMethodEditParams,
type MessageWebhookMethodWriteParams,
MessagesMethods, MessagesMethods,
Webhook, Webhook,
WebhookMessage, WebhookMessage,
type MessageWebhookMethodEditParams,
type MessageWebhookMethodWriteParams,
} from '../../structures'; } from '../../structures';
import { BaseShorter } from './base'; import { BaseShorter } from './base';
export class WebhookShorter extends BaseShorter { export class WebhookShorter extends BaseShorter {
get webhooks() { /**
return { * Deletes a webhook.
delete: (webhookId: string, { token, reason }: WebhookShorterOptionalParams) => { * @param webhookId The ID of the webhook.
if (token) { * @param options The optional parameters including token and reason.
return this.client.proxy.webhooks(webhookId)(token).delete({ reason, auth: false }); * @returns A Promise that resolves when the webhook is deleted.
*/
delete(webhookId: string, options: WebhookShorterOptionalParams) {
if (options.token) {
return this.client.proxy.webhooks(webhookId)(options.token).delete({ reason: options.reason, auth: false });
} }
return this.client.proxy.webhooks(webhookId).delete({ reason }); return this.client.proxy.webhooks(webhookId).delete({ reason: options.reason });
}, }
edit: (
/**
* Edits a webhook.
* @param webhookId The ID of the webhook.
* @param body The data to update the webhook with.
* @param options The optional parameters including token and reason.
* @returns A Promise that resolves when the webhook is edited.
*/
edit(
webhookId: string, webhookId: string,
body: RESTPatchAPIWebhookWithTokenJSONBody | RESTPatchAPIWebhookJSONBody, body: RESTPatchAPIWebhookWithTokenJSONBody | RESTPatchAPIWebhookJSONBody,
{ token, reason }: WebhookShorterOptionalParams, options: WebhookShorterOptionalParams,
) => { ) {
if (token) { if (options.token) {
return this.client.proxy.webhooks(webhookId)(token).patch({ body, reason, auth: false }); return this.client.proxy.webhooks(webhookId)(options.token).patch({ body, reason: options.reason, auth: false });
} }
return this.client.proxy.webhooks(webhookId).patch({ body, reason }); return this.client.proxy.webhooks(webhookId).patch({ body, reason: options.reason });
}, }
fetch: async (webhookId: string, token?: string) => {
/**
* Fetches a webhook.
* @param webhookId The ID of the webhook.
* @param token The token of the webhook (optional).
* @returns A Promise that resolves to the fetched webhook.
*/
async fetch(webhookId: string, token?: string) {
let webhook; let webhook;
if (token) { if (token) {
webhook = await this.client.proxy.webhooks(webhookId)(token).get({ auth: false }); webhook = await this.client.proxy.webhooks(webhookId)(token).get({ auth: false });
@ -40,14 +59,16 @@ export class WebhookShorter extends BaseShorter {
webhook = await this.client.proxy.webhooks(webhookId).get(); webhook = await this.client.proxy.webhooks(webhookId).get();
} }
return new Webhook(this.client, webhook); return new Webhook(this.client, webhook);
},
messages: this.messages,
};
} }
get messages() { /**
return { * Writes a message using the webhook.
write: async (webhookId: string, token: string, { body: data, ...payload }: MessageWebhookMethodWriteParams) => { * @param webhookId The ID of the webhook.
* @param token The token of the webhook.
* @param data The data for writing the message.
* @returns A Promise that resolves to the written message.
*/
async writeMessage(webhookId: string, token: string, { body: data, ...payload }: MessageWebhookMethodWriteParams) {
const { files, ...body } = data; const { files, ...body } = data;
const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIWebhookWithTokenJSONBody>(body); const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIWebhookWithTokenJSONBody>(body);
const parsedFiles = files ? await resolveFiles(files) : []; const parsedFiles = files ? await resolveFiles(files) : [];
@ -55,12 +76,21 @@ export class WebhookShorter extends BaseShorter {
.webhooks(webhookId)(token) .webhooks(webhookId)(token)
.post({ ...payload, files: parsedFiles, body: transformedBody }) .post({ ...payload, files: parsedFiles, body: transformedBody })
.then(m => (m?.id ? new WebhookMessage(this.client, m, webhookId, token) : null)); .then(m => (m?.id ? new WebhookMessage(this.client, m, webhookId, token) : null));
}, }
edit: async (
/**
* Edits a message sent by the webhook.
* @param webhookId The ID of the webhook.
* @param token The token of the webhook.
* @param messageId The ID of the message to edit.
* @param data The data for editing the message.
* @returns A Promise that resolves to the edited message.
*/
async editMessage(
webhookId: string, webhookId: string,
token: string, token: string,
{ messageId, body: data, ...json }: MessageWebhookMethodEditParams, { messageId, body: data, ...json }: MessageWebhookMethodEditParams,
) => { ) {
const { files, ...body } = data; const { files, ...body } = data;
const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIWebhookWithTokenJSONBody>(body); const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIWebhookWithTokenJSONBody>(body);
const parsedFiles = files ? await resolveFiles(files) : []; const parsedFiles = files ? await resolveFiles(files) : [];
@ -69,18 +99,34 @@ export class WebhookShorter extends BaseShorter {
.messages(messageId) .messages(messageId)
.patch({ ...json, auth: false, files: parsedFiles, body: transformedBody }) .patch({ ...json, auth: false, files: parsedFiles, body: transformedBody })
.then(m => new WebhookMessage(this.client, m, webhookId, token)); .then(m => new WebhookMessage(this.client, m, webhookId, token));
}, }
delete: async (webhookId: string, token: string, messageId: string, reason?: string) => {
/**
* Deletes a message sent by the webhook.
* @param webhookId The ID of the webhook.
* @param token The token of the webhook.
* @param messageId The ID of the message to delete.
* @param reason The reason for deleting the message.
* @returns A Promise that resolves when the message is deleted.
*/
deleteMessage(webhookId: string, token: string, messageId: string, reason?: string) {
return this.client.proxy.webhooks(webhookId)(token).messages(messageId).delete({ reason }); return this.client.proxy.webhooks(webhookId)(token).messages(messageId).delete({ reason });
}, }
fetch: async (webhookId: string, token: string, messageId: string, threadId?: string) => {
/**
* Fetches a message sent by the webhook.
* @param webhookId The ID of the webhook.
* @param token The token of the webhook.
* @param messageId The ID of the message to fetch.
* @param threadId The ID of the thread the message belongs to.
* @returns A Promise that resolves to the fetched message, or undefined if not found.
*/
async fetchMessage(webhookId: string, token: string, messageId: string, threadId?: string) {
const message = await this.client.proxy const message = await this.client.proxy
.webhooks(webhookId)(token) .webhooks(webhookId)(token)
.messages(messageId) .messages(messageId)
.get({ auth: false, query: { threadId } }); .get({ auth: false, query: { threadId } });
return message ? new WebhookMessage(this.client, message, webhookId, token) : undefined; return message ? new WebhookMessage(this.client, message, webhookId, token) : undefined;
},
};
} }
} }

View File

@ -55,7 +55,9 @@ export class Shard {
} }
get latency() { get latency() {
return this.heart.lastAck && this.heart.lastBeat ? this.heart.lastAck - this.heart.lastBeat : Infinity; return this.heart.lastAck && this.heart.lastBeat
? this.heart.lastAck - this.heart.lastBeat
: Number.POSITIVE_INFINITY;
} }
get isOpen() { get isOpen() {