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,77 +28,69 @@ import type { RestArguments } from '../api';
import type { ProxyRequestMethod } from '../Router';
export interface ApplicationRoutes {
applications: {
(
id: string,
): {
guilds: {
applications: (id: string) => {
guilds: (id: string) => {
commands: {
get(
args?: RestArguments<ProxyRequestMethod.Get, RESTGetAPIApplicationGuildCommandsQuery>,
): Promise<RESTGetAPIApplicationGuildCommandsResult>;
post(
args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIApplicationGuildCommandsJSONBody>,
): Promise<RESTPostAPIApplicationGuildCommandsResult>;
put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIApplicationGuildCommandsJSONBody>,
): Promise<RESTPutAPIApplicationGuildCommandsResult>;
permissions: {
get(
args?: RestArguments<ProxyRequestMethod.Get>,
): Promise<RESTGetAPIGuildApplicationCommandsPermissionsResult>;
// put(args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIGuildApplicationCommandsPermissionsJSONBody>): Promise<RESTPutAPIGuildApplicationCommandsPermissionsResult>
};
(
id: string,
): {
commands: {
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIApplicationGuildCommandResult>;
patch(
args: RestArguments<ProxyRequestMethod.Patch, RESTPatchAPIApplicationGuildCommandJSONBody>,
): Promise<RESTPatchAPIApplicationGuildCommandResult>;
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<never>;
permissions: {
get(
args?: RestArguments<ProxyRequestMethod.Get, RESTGetAPIApplicationGuildCommandsQuery>,
): Promise<RESTGetAPIApplicationGuildCommandsResult>;
post(
args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIApplicationGuildCommandsJSONBody>,
): Promise<RESTPostAPIApplicationGuildCommandsResult>;
args?: RestArguments<ProxyRequestMethod.Get>,
): Promise<RESTGetAPIGuildApplicationCommandsPermissionsResult>;
put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIApplicationGuildCommandsJSONBody>,
): Promise<RESTPutAPIApplicationGuildCommandsResult>;
permissions: {
get(
args?: RestArguments<ProxyRequestMethod.Get>,
): Promise<RESTGetAPIGuildApplicationCommandsPermissionsResult>;
// put(args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIGuildApplicationCommandsPermissionsJSONBody>): Promise<RESTPutAPIGuildApplicationCommandsPermissionsResult>
};
(
id: string,
): {
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIApplicationGuildCommandResult>;
patch(
args: RestArguments<ProxyRequestMethod.Patch, RESTPatchAPIApplicationGuildCommandJSONBody>,
): Promise<RESTPatchAPIApplicationGuildCommandResult>;
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<never>;
permissions: {
get(
args?: RestArguments<ProxyRequestMethod.Get>,
): Promise<RESTGetAPIGuildApplicationCommandsPermissionsResult>;
put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIApplicationCommandPermissionsJSONBody>,
): Promise<RESTPutAPIGuildApplicationCommandsPermissionsResult>;
};
};
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIApplicationCommandPermissionsJSONBody>,
): Promise<RESTPutAPIGuildApplicationCommandsPermissionsResult>;
};
};
};
commands: {
get(
args?: RestArguments<ProxyRequestMethod.Get, RESTGetAPIApplicationCommandsQuery>,
): Promise<RESTGetAPIApplicationCommandsResult>;
post(
args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIApplicationCommandsJSONBody>,
): Promise<RESTPostAPIApplicationCommandsResult>;
put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIApplicationCommandsJSONBody>,
): Promise<RESTPutAPIApplicationCommandsResult>;
(
id: string,
): {
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIApplicationCommandResult>;
patch(
args: RestArguments<ProxyRequestMethod.Patch, RESTPatchAPIApplicationCommandJSONBody>,
): Promise<RESTPatchAPIApplicationCommandResult>;
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<never>;
};
};
commands: {
get(
args?: RestArguments<ProxyRequestMethod.Get, RESTGetAPIApplicationCommandsQuery>,
): Promise<RESTGetAPIApplicationCommandsResult>;
post(
args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIApplicationCommandsJSONBody>,
): Promise<RESTPostAPIApplicationCommandsResult>;
put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIApplicationCommandsJSONBody>,
): Promise<RESTPutAPIApplicationCommandsResult>;
(
id: string,
): {
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIApplicationCommandResult>;
patch(
args: RestArguments<ProxyRequestMethod.Patch, RESTPatchAPIApplicationCommandJSONBody>,
): Promise<RESTPatchAPIApplicationCommandResult>;
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<never>;
};
'role-connections': {
metadata: {
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIApplicationRoleConnectionMetadataResult>;
put(
args: RestArguments<ProxyRequestMethod.Put, RESTPutAPIApplicationRoleConnectionMetadataJSONBody>,
): Promise<RESTPutAPIApplicationRoleConnectionMetadataResult>;
};
};
'role-connections': {
metadata: {
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIApplicationRoleConnectionMetadataResult>;
put(
args: RestArguments<ProxyRequestMethod.Put, RESTPutAPIApplicationRoleConnectionMetadataJSONBody>,
): Promise<RESTPutAPIApplicationRoleConnectionMetadataResult>;
};
};
};

View File

@ -66,18 +66,14 @@ export interface ChannelRoutes {
): Promise<RESTPatchAPIChannelResult>;
//.
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelResult>;
users: {
(
id: '@me',
): {
threads: {
archived: {
private: {
//.
get(
args?: RestArguments<ProxyRequestMethod.Get, RESTGetAPIChannelThreadsArchivedQuery>,
): Promise<RESTGetAPIChannelUsersThreadsArchivedResult>;
};
users: (id: '@me') => {
threads: {
archived: {
private: {
//.
get(
args?: RestArguments<ProxyRequestMethod.Get, RESTGetAPIChannelThreadsArchivedQuery>,
): Promise<RESTGetAPIChannelUsersThreadsArchivedResult>;
};
};
};
@ -131,17 +127,13 @@ export interface ChannelRoutes {
};
};
};
recipients: {
(
id: string,
): {
//.
put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIChannelRecipientJSONBody>,
): Promise<RESTPutAPIChannelRecipientResult>;
//.
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelRecipientResult>;
};
recipients: (id: string) => {
//.
put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIChannelRecipientJSONBody>,
): Promise<RESTPutAPIChannelRecipientResult>;
//.
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelRecipientResult>;
};
pins: {
//.
@ -161,17 +153,13 @@ export interface ChannelRoutes {
args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIChannelFollowersJSONBody>,
): Promise<RESTPostAPIChannelFollowersResult>;
};
permissions: {
(
id: string,
): {
//.
put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIChannelPermissionJSONBody>,
): Promise<RESTPutAPIChannelPermissionResult>;
//.
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelPermissionResult>;
};
permissions: (id: string) => {
//.
put(
args?: RestArguments<ProxyRequestMethod.Put, RESTPutAPIChannelPermissionJSONBody>,
): Promise<RESTPutAPIChannelPermissionResult>;
//.
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIChannelPermissionResult>;
};
invites: {
//.

View File

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

View File

@ -65,16 +65,12 @@ export interface WebhookRoutes {
>,
): Promise<RESTPostAPIWebhookWithTokenGitHubResult | RESTPostAPIWebhookWithTokenGitHubWaitResult>;
};
messages: {
(
id: string | '@original',
): {
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIWebhookWithTokenMessageResult>;
patch(
args: RestArguments<ProxyRequestMethod.Patch, RESTPatchAPIWebhookWithTokenMessageJSONBody>,
): Promise<RESTPatchAPIWebhookWithTokenMessageResult>;
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIWebhookWithTokenMessageResult>;
};
messages: (id: string | '@original') => {
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIWebhookWithTokenMessageResult>;
patch(
args: RestArguments<ProxyRequestMethod.Patch, RESTPatchAPIWebhookWithTokenMessageJSONBody>,
): Promise<RESTPatchAPIWebhookWithTokenMessageResult>;
delete(args?: RestArguments<ProxyRequestMethod.Delete>): Promise<RESTDeleteAPIWebhookWithTokenMessageResult>;
};
};
};

View File

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

View File

@ -5,8 +5,15 @@ export * from 'discord-api-types/v10';
export * from './it/colors';
export * from './it/logger';
export * from './shorters/channels';
export * from './shorters/emojis';
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/webhook';
export * from './types/options';
export * from './types/resolvables';
export * from './types/util';

View File

@ -250,6 +250,7 @@ export async function magicImport(path: string) {
try {
return require(path);
} catch {
// biome-ignore lint/security/noGlobalEval: modules import broke
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;
return {
// biome-ignore lint/suspicious/noThenProperty: magic
then: callback => callback(value as Awaited<T>),
};
}

View File

@ -5,180 +5,158 @@ import { PermissionsBitField } from '../../structures/extra/Permissions';
import { BaseShorter } from './base';
export class ChannelShorter extends BaseShorter {
get channels() {
/**
* Fetches a channel by its ID.
* @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.
* @returns A Promise that resolves to the fetched channel.
*/
async fetch(id: string, force?: boolean): Promise<AllChannels> {
let channel;
if (!force) {
channel = await this.client.cache.channels?.get(id);
if (channel) return channel;
}
channel = await this.client.proxy.channels(id).get();
await this.client.cache.channels?.patch(id, undefined, channel);
return channelFrom(channel, this.client);
}
/**
* Deletes a channel by its ID.
* @param id The ID of the channel to delete.
* @param optional Optional parameters for the deletion.
* @returns A Promise that resolves to the deleted channel.
*/
async delete(id: string, optional: ChannelShorterOptionalParams = { guildId: '@me' }): Promise<AllChannels> {
const res = await this.client.proxy.channels(id).delete({ reason: optional.reason });
await this.client.cache.channels?.removeIfNI(BaseChannel.__intent__(optional.guildId!), res.id, optional.guildId!);
return channelFrom(res, this.client);
}
/**
* Edits a channel by its ID.
* @param id The ID of the channel to edit.
* @param body The updated channel data.
* @param optional Optional parameters for the editing.
* @returns A Promise that resolves to the edited channel.
*/
async edit(
id: string,
body: RESTPatchAPIChannelJSONBody,
optional: ChannelShorterOptionalParams = { guildId: '@me' },
): Promise<AllChannels> {
const res = await this.client.proxy.channels(id).patch({ body, reason: optional.reason });
await this.client.cache.channels?.setIfNI(
BaseChannel.__intent__(optional.guildId!),
res.id,
optional.guildId!,
res,
);
if (body.permission_overwrites && 'permission_overwrites' in res)
await this.client.cache.overwrites?.setIfNI(
BaseChannel.__intent__(optional.guildId!),
res.id,
optional.guildId!,
res.permission_overwrites,
);
return channelFrom(res, this.client);
}
/**
* Sends a typing indicator to the channel.
* @param id The ID of the channel.
* @returns A Promise that resolves when the typing indicator is successfully sent.
*/
async typing(id: string): Promise<void> {
await this.client.proxy.channels(id).typing.post();
}
async pins(channelId: string): Promise<Message[]> {
const messages = await this.client.proxy.channels(channelId).pins.get();
return messages.map(message => new Message(this.client, message));
}
/**
* Pins a message in the channel.
* @param messageId The ID of the message to pin.
* @param channelId The ID of the channel.
* @param reason The reason for pinning the message.
* @returns A Promise that resolves when the message is successfully pinned.
*/
setPin(messageId: string, channelId: string, reason?: string) {
return this.client.proxy.channels(channelId).pins(messageId).put({ reason });
}
/**
* Unpins a message in the channel.
* @param messageId The ID of the message to unpin.
* @param channelId The ID of the channel.
* @param reason The reason for unpinning the message.
* @returns A Promise that resolves when the message is successfully unpinned.
*/
deletePin(messageId: string, channelId: string, reason?: string) {
return this.client.proxy.channels(channelId).pins(messageId).delete({ reason });
}
async memberPermissions(channelId: string, member: GuildMember, checkAdmin = true): Promise<PermissionsBitField> {
const permissions = await member.fetchPermissions();
if (checkAdmin && permissions.has(PermissionFlagsBits.Administrator)) {
return new PermissionsBitField(PermissionsBitField.All);
}
const overwrites = await this.overwritesFor(channelId, member);
permissions.remove(overwrites.everyone?.deny.bits ?? 0n);
permissions.add(overwrites.everyone?.allow.bits ?? 0n);
permissions.remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.deny.bits) : 0n);
permissions.add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allow.bits) : 0n);
permissions.remove(overwrites.member?.deny.bits ?? 0n);
permissions.add(overwrites.member?.allow.bits ?? 0n);
return permissions;
}
async overwritesFor(channelId: string, member: GuildMember) {
const roleOverwrites = [];
let memberOverwrites;
let everyoneOverwrites;
const channelOverwrites = (await this.client.cache.overwrites?.get(channelId)) ?? [];
for (const overwrite of channelOverwrites) {
if (overwrite.id === member.guildId) {
everyoneOverwrites = overwrite;
} else if (member.roles.values.includes(overwrite.id)) {
roleOverwrites.push(overwrite);
} else if (overwrite.id === member.id) {
memberOverwrites = overwrite;
}
}
return {
/**
* Fetches a channel by its ID.
* @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.
* @returns A Promise that resolves to the fetched channel.
*/
fetch: async (id: string, force?: boolean): Promise<AllChannels> => {
let channel;
if (!force) {
channel = await this.client.cache.channels?.get(id);
if (channel) return channel;
}
channel = await this.client.proxy.channels(id).get();
await this.client.cache.channels?.patch(id, undefined, channel);
return channelFrom(channel, this.client);
},
/**
* Deletes a channel by its ID.
* @param id The ID of the channel to delete.
* @param optional Optional parameters for the deletion.
* @returns A Promise that resolves to the deleted channel.
*/
delete: async (id: string, optional: ChannelShorterOptionalParams = { guildId: '@me' }) => {
const res = await this.client.proxy.channels(id).delete({ reason: optional.reason });
await this.client.cache.channels?.removeIfNI(
BaseChannel.__intent__(optional.guildId!),
res.id,
optional.guildId!,
);
return channelFrom(res, this.client);
},
/**
* Edits a channel by its ID.
* @param id The ID of the channel to edit.
* @param body The updated channel data.
* @param optional Optional parameters for the editing.
* @returns A Promise that resolves to the edited channel.
*/
edit: async (
id: string,
body: RESTPatchAPIChannelJSONBody,
optional: ChannelShorterOptionalParams = { guildId: '@me' },
) => {
const res = await this.client.proxy.channels(id).patch({ body, reason: optional.reason });
await this.client.cache.channels?.setIfNI(
BaseChannel.__intent__(optional.guildId!),
res.id,
optional.guildId!,
res,
);
if (body.permission_overwrites && 'permission_overwrites' in res)
await this.client.cache.overwrites?.setIfNI(
BaseChannel.__intent__(optional.guildId!),
res.id,
optional.guildId!,
res.permission_overwrites,
);
return channelFrom(res, this.client);
},
/**
* Sends a typing indicator to the channel.
* @param id The ID of the channel.
* @returns A Promise that resolves when the typing indicator is successfully sent.
*/
typing: (id: string) => this.client.proxy.channels(id).typing.post(),
/**
* Provides access to pinned messages in the channel.
*/
pins: this.pins,
overwrites: this.overwrites,
everyone: everyoneOverwrites,
roles: roleOverwrites,
member: memberOverwrites,
};
}
get pins() {
return {
/**
* 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))),
async rolePermissions(channelId: string, role: GuildRole, checkAdmin = true): Promise<PermissionsBitField> {
if (checkAdmin && role.permissions.has(PermissionFlagsBits.Administrator)) {
return new PermissionsBitField(PermissionsBitField.All);
}
const channelOverwrites = (await this.client.cache.overwrites?.get(channelId)) ?? [];
/**
* Pins a message in the channel.
* @param messageId The ID of the message to pin.
* @param channelId The ID of the channel.
* @param reason The reason for pinning the message.
* @returns A Promise that resolves when the message is successfully pinned.
*/
set: (messageId: string, channelId: string, reason?: string) =>
this.client.proxy.channels(channelId).pins(messageId).put({ reason }),
const everyoneOverwrites = channelOverwrites.find(x => x.id === role.guildId);
const roleOverwrites = channelOverwrites.find(x => x.id === role.id);
const permissions = new PermissionsBitField(role.permissions.bits);
/**
* Unpins a message in the channel.
* @param messageId The ID of the message to unpin.
* @param channelId The ID of the channel.
* @param reason The reason for unpinning the message.
* @returns A Promise that resolves when the message is successfully unpinned.
*/
delete: (messageId: string, channelId: string, reason?: string) =>
this.client.proxy.channels(channelId).pins(messageId).delete({ reason }),
};
}
get overwrites() {
return {
memberPermissions: async (channelId: string, member: GuildMember, checkAdmin = true) => {
const permissions = await member.fetchPermissions();
if (checkAdmin && permissions.has(PermissionFlagsBits.Administrator)) {
return new PermissionsBitField(PermissionsBitField.All);
}
const overwrites = await this.overwrites.overwritesFor(channelId, member);
permissions.remove(overwrites.everyone?.deny.bits ?? 0n);
permissions.add(overwrites.everyone?.allow.bits ?? 0n);
permissions.remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.deny.bits) : 0n);
permissions.add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allow.bits) : 0n);
permissions.remove(overwrites.member?.deny.bits ?? 0n);
permissions.add(overwrites.member?.allow.bits ?? 0n);
return permissions;
},
overwritesFor: async (channelId: string, member: GuildMember) => {
const roleOverwrites = [];
let memberOverwrites;
let everyoneOverwrites;
const channelOverwrites = (await this.client.cache.overwrites?.get(channelId)) ?? [];
for (const overwrite of channelOverwrites) {
if (overwrite.id === member.guildId) {
everyoneOverwrites = overwrite;
} else if (member.roles.values.includes(overwrite.id)) {
roleOverwrites.push(overwrite);
} else if (overwrite.id === member.id) {
memberOverwrites = overwrite;
}
}
return {
everyone: everyoneOverwrites,
roles: roleOverwrites,
member: memberOverwrites,
};
},
rolePermissions: async (channelId: string, role: GuildRole, checkAdmin = true) => {
if (checkAdmin && role.permissions.has(PermissionFlagsBits.Administrator)) {
return new PermissionsBitField(PermissionsBitField.All);
}
const channelOverwrites = (await this.client.cache.overwrites?.get(channelId)) ?? [];
const everyoneOverwrites = channelOverwrites.find(x => x.id === role.guildId);
const roleOverwrites = channelOverwrites.find(x => x.id === role.id);
const permissions = new PermissionsBitField(role.permissions.bits);
permissions.remove(everyoneOverwrites?.deny.bits ?? 0n);
permissions.add(everyoneOverwrites?.allow.bits ?? 0n);
permissions.remove(roleOverwrites?.deny.bits ?? 0n);
permissions.add(roleOverwrites?.allow.bits ?? 0n);
return permissions;
},
};
permissions.remove(everyoneOverwrites?.deny.bits ?? 0n);
permissions.add(everyoneOverwrites?.allow.bits ?? 0n);
permissions.remove(roleOverwrites?.deny.bits ?? 0n);
permissions.add(roleOverwrites?.allow.bits ?? 0n);
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 {
APIChannel,
GuildWidgetStyle,
RESTGetAPICurrentUserGuildsQuery,
RESTPatchAPIAutoModerationRuleJSONBody,
RESTPatchAPIChannelJSONBody,
RESTPatchAPIGuildChannelPositionsJSONBody,
RESTPatchAPIGuildEmojiJSONBody,
RESTPatchAPIGuildStickerJSONBody,
RESTPostAPIAutoModerationRuleJSONBody,
RESTPostAPIGuildChannelJSONBody,
RESTPostAPIGuildEmojiJSONBody,
RESTPostAPIGuildsJSONBody,
} from 'discord-api-types/v10';
import type { ImageResolvable, ObjectToLower, OmitInsert } from '..';
import { resolveFiles, resolveImage } from '../../builders';
import type { ObjectToLower } from '..';
import { resolveFiles } from '../../builders';
import {
AnonymousGuild,
BaseChannel,
Guild,
GuildEmoji,
GuildMember,
Sticker,
type CreateStickerBodyRequest,
@ -27,163 +25,67 @@ import { BaseShorter } from './base';
export class GuildShorter extends BaseShorter {
/**
* Provides access to guild-related functionality.
* Creates a new guild.
* @param body The data for creating the guild.
* @returns A Promise that resolves to the created guild.
*/
get guilds() {
return {
/**
* Creates a new guild.
* @param body The data for creating the guild.
* @returns A Promise that resolves to the created guild.
*/
create: async (body: RESTPostAPIGuildsJSONBody) => {
const guild = await this.client.proxy.guilds.post({ body });
await this.client.cache.guilds?.setIfNI('Guilds', guild.id, guild);
return new Guild<'api'>(this.client, guild);
},
/**
* Fetches a guild by its ID.
* @param id The ID of the guild to fetch.
* @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.
*/
fetch: async (id: string, force = false) => {
if (!force) {
const guild = await this.client.cache.guilds?.get(id);
if (guild) return guild;
}
const data = await this.client.proxy.guilds(id).get();
await this.client.cache.guilds?.patch(id, data);
return (await this.client.cache.guilds?.get(id)) ?? new Guild<'api'>(this.client, data);
},
/**
* Generates the widget URL for the guild.
* @param id The ID of the guild.
* @param style The style of the widget.
* @returns The generated widget URL.
*/
widgetURL: (id: string, style?: GuildWidgetStyle) => {
const query = new URLSearchParams();
if (style) {
query.append('style', style);
}
return this.client.proxy.guilds(id).widget.get({ query });
},
list: (query?: RESTGetAPICurrentUserGuildsQuery) => {
return this.client.proxy
.users('@me')
.guilds.get({ query })
.then(guilds => guilds.map(guild => new AnonymousGuild(this.client, { ...guild, splash: null })));
},
fetchSelf: async (id: string) => {
const self = await this.client.proxy.guilds(id).members(this.client.botId).get();
await this.client.cache.members?.patch(self.user!.id, id, self);
return new GuildMember(this.client, self, self.user!, id);
},
leave: (id: string) => {
return this.client.proxy
.users('@me')
.guilds(id)
.delete()
.then(() => this.client.cache.guilds?.removeIfNI('Guilds', id));
},
channels: this.channels,
moderation: this.moderation,
stickers: this.stickers,
emojis: this.emojis,
};
async create(body: RESTPostAPIGuildsJSONBody): Promise<Guild<'api'>> {
const guild = await this.client.proxy.guilds.post({ body });
await this.client.cache.guilds?.setIfNI('Guilds', guild.id, guild);
return new Guild<'api'>(this.client, guild);
}
/**
* Provides access to emoji-related functionality in a guild.
* Fetches a guild by its ID.
* @param id The ID of the guild to fetch.
* @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.
*/
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));
},
async fetch(id: string, force = false) {
if (!force) {
const guild = await this.client.cache.guilds?.get(id);
if (guild) return guild;
}
/**
* 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);
},
const data = await this.client.proxy.guilds(id).get();
await this.client.cache.guilds?.patch(id, data);
return (await this.client.cache.guilds?.get(id)) ?? new Guild<'api'>(this.client, data);
}
/**
* 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);
},
/**
* Generates the widget URL for the guild.
* @param id The ID of the guild.
* @param style The style of the widget.
* @returns The generated widget URL.
*/
widgetURL(id: string, style?: GuildWidgetStyle) {
const query = new URLSearchParams();
if (style) {
query.append('style', style);
}
/**
* 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);
},
return this.client.proxy.guilds(id).widget.get({ query });
}
/**
* 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);
},
};
list(query?: RESTGetAPICurrentUserGuildsQuery) {
return this.client.proxy
.users('@me')
.guilds.get({ query })
.then(guilds => guilds.map(guild => new AnonymousGuild(this.client, { ...guild, splash: null })));
}
async fetchSelf(id: string) {
const self = await this.client.proxy.guilds(id).members(this.client.botId).get();
await this.client.cache.members?.patch(self.user!.id, id, self);
return new GuildMember(this.client, self, self.user!, id);
}
leave(id: string) {
return this.client.proxy
.users('@me')
.guilds(id)
.delete()
.then(() => this.client.cache.guilds?.removeIfNI('Guilds', id));
}
/**
@ -207,7 +109,7 @@ export class GuildShorter extends BaseShorter {
}
channels = await this.client.proxy.guilds(guildId).channels.get();
await this.client.cache.channels?.set(
channels.map(x => [x.id, x]),
channels.map<[string, APIChannel]>(x => [x.id, x]),
guildId,
);
return channels.map(m => channelFrom(m, this.client));

View File

@ -13,188 +13,172 @@ import { BaseShorter } from './base';
export class MemberShorter extends BaseShorter {
/**
* Provides access to member-related functionality in a guild.
* Resolves a member in the guild based on the provided GuildMemberResolvable.
* @param guildId The ID of the guild.
* @param resolve The GuildMemberResolvable to resolve.
* @returns A Promise that resolves to the resolved member.
*/
get members() {
return {
/**
* Resolves a member in the guild based on the provided GuildMemberResolvable.
* @param guildId The ID of the guild.
* @param resolve The GuildMemberResolvable to resolve.
* @returns A Promise that resolves to the resolved member.
*/
resolve: async (guildId: string, resolve: GuildMemberResolvable) => {
if (typeof resolve === 'string') {
const match: { id?: string } | undefined = resolve.match(FormattingPatterns.User)?.groups;
if (match?.id) {
return this.members.fetch(guildId, match.id);
}
if (resolve.match(/\d{17,20}/)) {
return this.members.fetch(guildId, resolve);
}
return this.members.search(guildId, { query: resolve, limit: 1 }).then(x => x[0]);
}
if (resolve.id) {
return this.client.members.fetch(guildId, resolve.id);
}
return resolve.displayName
? this.members.search(guildId, { query: resolve.displayName, limit: 1 }).then(x => x[0])
: undefined;
},
/**
* Searches for members in the guild based on the provided query.
* @param guildId The ID of the guild.
* @param query The query parameters for searching members.
* @returns A Promise that resolves to an array of matched members.
*/
search: async (guildId: string, query?: RESTGetAPIGuildMembersSearchQuery) => {
const members = await this.client.proxy.guilds(guildId).members.search.get({
query,
});
await this.client.cache.members?.set(
members.map(x => [x.user!.id, x]),
guildId,
);
return members.map(m => new GuildMember(this.client, m, m.user!, guildId));
},
/**
* Unbans a member from the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to unban.
* @param body The request body for unbanning the member.
* @param reason The reason for unbanning the member.
*/
unban: async (guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) => {
await this.client.proxy.guilds(guildId).bans(memberId).delete({ reason, body });
},
/**
* Bans a member from the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to ban.
* @param body The request body for banning the member.
* @param reason The reason for banning the member.
*/
ban: async (guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) => {
await this.client.proxy.guilds(guildId).bans(memberId).put({ reason, body });
await this.client.cache.members?.removeIfNI('GuildBans', memberId, guildId);
},
/**
* Kicks a member from the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to kick.
* @param reason The reason for kicking the member.
*/
kick: async (guildId: string, memberId: string, reason?: string) => {
await this.client.proxy.guilds(guildId).members(memberId).delete({ reason });
await this.client.cache.members?.removeIfNI('GuildMembers', memberId, guildId);
},
/**
* Edits a member in the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to edit.
* @param body The data to update the member with.
* @param reason The reason for editing the member.
* @returns A Promise that resolves to the edited member.
*/
edit: async (guildId: string, memberId: string, body: RESTPatchAPIGuildMemberJSONBody, reason?: string) => {
const member = await this.client.proxy.guilds(guildId).members(memberId).patch({ body, reason });
await this.client.cache.members?.setIfNI('GuildMembers', memberId, guildId, member);
return new GuildMember(this.client, member, member.user!, guildId);
},
/**
* Adds a member to the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to add.
* @param body The request body for adding the member.
* @returns A Promise that resolves to the added member.
*/
add: async (guildId: string, memberId: string, body: RESTPutAPIGuildMemberJSONBody) => {
const member = await this.client.proxy.guilds(guildId).members(memberId).put({
body,
});
// Thanks dapi-types, fixed
if (!member) {
return;
}
await this.client.cache.members?.setIfNI('GuildMembers', member.user!.id, guildId, member);
return new GuildMember(this.client, member, member.user!, guildId);
},
/**
* Fetches a member from the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to fetch.
* @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.
*/
fetch: async (guildId: string, memberId: string, force = false) => {
let member;
if (!force) {
member = await this.client.cache.members?.get(memberId, guildId);
if (member) return member;
}
member = await this.client.proxy.guilds(guildId).members(memberId).get();
await this.client.cache.members?.set(member.user!.id, guildId, member);
return new GuildMember(this.client, member, member.user!, guildId);
},
/**
* Lists members in the guild based on the provided query.
* @param guildId The ID of the guild.
* @param query The query parameters for listing members.
* @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.
*/
list: async (guildId: string, query?: RESTGetAPIGuildMembersQuery, force = false) => {
let members;
if (!force) {
members = (await this.client.cache.members?.values(guildId)) ?? [];
if (members.length) return members;
}
members = await this.client.proxy.guilds(guildId).members.get({
query,
});
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));
},
/**
* Provides methods to add and remove roles from a guild member.
*/
roles: this.roles,
};
async resolve(guildId: string, resolve: GuildMemberResolvable) {
if (typeof resolve === 'string') {
const match: { id?: string } | undefined = resolve.match(FormattingPatterns.User)?.groups;
if (match?.id) {
return this.fetch(guildId, match.id);
}
if (resolve.match(/\d{17,20}/)) {
return this.fetch(guildId, resolve);
}
return this.search(guildId, { query: resolve, limit: 1 }).then(x => x[0]);
}
if (resolve.id) {
return this.client.members.fetch(guildId, resolve.id);
}
return resolve.displayName
? this.search(guildId, { query: resolve.displayName, limit: 1 }).then(x => x[0])
: undefined;
}
get roles() {
return {
/**
* Adds a role to a guild member.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to add the role to.
* @param id The ID of the role to add.
*/
add: async (guildId: string, memberId: string, id: string) => {
await this.client.proxy.guilds(guildId).members(memberId).roles(id).put({});
},
/**
* Searches for members in the guild based on the provided query.
* @param guildId The ID of the guild.
* @param query The query parameters for searching members.
* @returns A Promise that resolves to an array of matched members.
*/
async search(guildId: string, query?: RESTGetAPIGuildMembersSearchQuery) {
const members = await this.client.proxy.guilds(guildId).members.search.get({
query,
});
await this.client.cache.members?.set(
members.map(x => [x.user!.id, x]),
guildId,
);
return members.map(m => new GuildMember(this.client, m, m.user!, guildId));
}
/**
* Removes a role from a guild member.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to remove the role from.
* @param id The ID of the role to remove.
*/
remove: async (guildId: string, memberId: string, id: string) => {
await this.client.proxy.guilds(guildId).members(memberId).roles(id).delete();
},
};
/**
* Unbans a member from the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to unban.
* @param body The request body for unbanning the member.
* @param reason The reason for unbanning the member.
*/
async unban(guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) {
await this.client.proxy.guilds(guildId).bans(memberId).delete({ reason, body });
}
/**
* Bans a member from the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to ban.
* @param body The request body for banning the member.
* @param reason The reason for banning the member.
*/
async ban(guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) {
await this.client.proxy.guilds(guildId).bans(memberId).put({ reason, body });
await this.client.cache.members?.removeIfNI('GuildBans', memberId, guildId);
}
/**
* Kicks a member from the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to kick.
* @param reason The reason for kicking the member.
*/
async kick(guildId: string, memberId: string, reason?: string) {
await this.client.proxy.guilds(guildId).members(memberId).delete({ reason });
await this.client.cache.members?.removeIfNI('GuildMembers', memberId, guildId);
}
/**
* Edits a member in the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to edit.
* @param body The data to update the member with.
* @param reason The reason for editing the member.
* @returns A Promise that resolves to the edited member.
*/
async edit(guildId: string, memberId: string, body: RESTPatchAPIGuildMemberJSONBody, reason?: string) {
const member = await this.client.proxy.guilds(guildId).members(memberId).patch({ body, reason });
await this.client.cache.members?.setIfNI('GuildMembers', memberId, guildId, member);
return new GuildMember(this.client, member, member.user!, guildId);
}
/**
* Adds a member to the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to add.
* @param body The request body for adding the member.
* @returns A Promise that resolves to the added member.
*/
async add(guildId: string, memberId: string, body: RESTPutAPIGuildMemberJSONBody) {
const member = await this.client.proxy.guilds(guildId).members(memberId).put({
body,
});
// Thanks dapi-types, fixed
if (!member) {
return;
}
await this.client.cache.members?.setIfNI('GuildMembers', member.user!.id, guildId, member);
return new GuildMember(this.client, member, member.user!, guildId);
}
/**
* Fetches a member from the guild.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to fetch.
* @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.
*/
async fetch(guildId: string, memberId: string, force = false) {
let member;
if (!force) {
member = await this.client.cache.members?.get(memberId, guildId);
if (member) return member;
}
member = await this.client.proxy.guilds(guildId).members(memberId).get();
await this.client.cache.members?.set(member.user!.id, guildId, member);
return new GuildMember(this.client, member, member.user!, guildId);
}
/**
* Lists members in the guild based on the provided query.
* @param guildId The ID of the guild.
* @param query The query parameters for listing members.
* @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.
*/
async list(guildId: string, query?: RESTGetAPIGuildMembersQuery, force = false) {
let members;
if (!force) {
members = (await this.client.cache.members?.values(guildId)) ?? [];
if (members.length) return members;
}
members = await this.client.proxy.guilds(guildId).members.get({
query,
});
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));
}
/**
* Adds a role to a guild member.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to add the role to.
* @param id The ID of the role to add.
*/
addRole(guildId: string, memberId: string, id: string) {
this.client.proxy.guilds(guildId).members(memberId).roles(id).put({});
}
/**
* Removes a role from a guild member.
* @param guildId The ID of the guild.
* @param memberId The ID of the member to remove the role from.
* @param id The ID of the role to remove.
*/
removeRole(guildId: string, memberId: string, id: string) {
return this.client.proxy.guilds(guildId).members(memberId).roles(id).delete();
}
}

View File

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

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,54 +8,89 @@ import { GuildRole } from '../../structures';
import { BaseShorter } from './base';
export class RoleShorter extends BaseShorter {
get roles() {
return {
create: (guildId: string, body: RESTPostAPIGuildRoleJSONBody, reason?: string) =>
this.client.proxy
.guilds(guildId)
.roles.post({ body, reason })
.then(res => this.client.cache.roles?.setIfNI('Guilds', res.id, guildId, res)),
list: async (guildId: string, force = false) => {
let roles: APIRole[] = [];
if (!force) {
const cachedRoles = (await this.client.cache.roles?.values(guildId)) ?? [];
if (cachedRoles.length) {
return cachedRoles;
}
}
roles = await this.client.proxy.guilds(guildId).roles.get();
await this.client.cache.roles?.set(
roles.map(r => [r.id, r]),
guildId,
);
return roles.map(r => new GuildRole(this.client, r, guildId));
},
edit: (guildId: string, roleId: string, body: RESTPatchAPIGuildRoleJSONBody, reason?: string) => {
return this.client.proxy
.guilds(guildId)
.roles(roleId)
.patch({ body, reason })
.then(res => this.client.cache.roles?.setIfNI('Guilds', roleId, guildId, res));
},
delete: (guildId: string, roleId: string, reason?: string) => {
return this.client.proxy
.guilds(guildId)
.roles(roleId)
.delete({ reason })
.then(() => this.client.cache.roles?.removeIfNI('Guilds', roleId, guildId));
},
editPositions: async (guildId: string, body: RESTPatchAPIGuildRolePositionsJSONBody) => {
const roles = await this.client.proxy.guilds(guildId).roles.patch({
body,
});
if (!this.client.cache.hasRolesIntent) {
await this.client.cache.roles?.set(
roles.map(x => [x.id, x]),
guildId,
);
}
return roles.map(x => new GuildRole(this.client, x, guildId));
},
};
/**
* Creates a new role in the guild.
* @param guildId The ID of the guild.
* @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)
.roles.post({ body, reason })
.then(res => this.client.cache.roles?.setIfNI('Guilds', res.id, guildId, res));
}
/**
* 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[] = [];
if (!force) {
const cachedRoles = (await this.client.cache.roles?.values(guildId)) ?? [];
if (cachedRoles.length) {
return cachedRoles;
}
}
roles = await this.client.proxy.guilds(guildId).roles.get();
await this.client.cache.roles?.set(
roles.map<[string, APIRole]>(r => [r.id, r]),
guildId,
);
return roles.map(r => new GuildRole(this.client, r, guildId));
}
/**
* 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
.guilds(guildId)
.roles(roleId)
.patch({ body, reason })
.then(res => this.client.cache.roles?.setIfNI('Guilds', roleId, guildId, res));
}
/**
* 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
.guilds(guildId)
.roles(roleId)
.delete({ reason })
.then(() => this.client.cache.roles?.removeIfNI('Guilds', roleId, guildId));
}
/**
* 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({
body,
});
if (!this.client.cache.hasRolesIntent) {
await this.client.cache.roles?.set(
roles.map(x => [x.id, 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';
export class TemplateShorter extends BaseShorter {
get templates() {
return {
fetch: (code: string) => {
return this.client.proxy.guilds.templates(code).get();
},
list: (guildId: string) => {
return this.client.proxy.guilds(guildId).templates.get();
},
create: (guildId: string, body: RESTPostAPIGuildTemplatesJSONBody) => {
return this.client.proxy.guilds(guildId).templates.post({ body });
},
sync: (guildId: string, code: string) => {
return this.client.proxy.guilds(guildId).templates(code).put({});
},
edit: (guildId: string, code: string, body: RESTPatchAPIGuildTemplateJSONBody) => {
return this.client.proxy.guilds(guildId).templates(code).patch({ body });
},
delete: (guildId: string, code: string) => {
return this.client.proxy.guilds(guildId).templates(code).delete();
},
};
fetch(code: string) {
return this.client.proxy.guilds.templates(code).get();
}
list(guildId: string) {
return this.client.proxy.guilds(guildId).templates.get();
}
create(guildId: string, body: RESTPostAPIGuildTemplatesJSONBody) {
return this.client.proxy.guilds(guildId).templates.post({ body });
}
sync(guildId: string, code: string) {
return this.client.proxy.guilds(guildId).templates(code).put({});
}
edit(guildId: string, code: string, body: RESTPatchAPIGuildTemplateJSONBody) {
return this.client.proxy.guilds(guildId).templates(code).patch({ body });
}
delete(guildId: string, code: string) {
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';
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() {
return {
createDM: async (userId: string, force = false) => {

View File

@ -5,82 +5,128 @@ import type {
} from '..';
import { resolveFiles } from '../../builders';
import {
type MessageWebhookMethodEditParams,
type MessageWebhookMethodWriteParams,
MessagesMethods,
Webhook,
WebhookMessage,
type MessageWebhookMethodEditParams,
type MessageWebhookMethodWriteParams,
} from '../../structures';
import { BaseShorter } from './base';
export class WebhookShorter extends BaseShorter {
get webhooks() {
return {
delete: (webhookId: string, { token, reason }: WebhookShorterOptionalParams) => {
if (token) {
return this.client.proxy.webhooks(webhookId)(token).delete({ reason, auth: false });
}
return this.client.proxy.webhooks(webhookId).delete({ reason });
},
edit: (
webhookId: string,
body: RESTPatchAPIWebhookWithTokenJSONBody | RESTPatchAPIWebhookJSONBody,
{ token, reason }: WebhookShorterOptionalParams,
) => {
if (token) {
return this.client.proxy.webhooks(webhookId)(token).patch({ body, reason, auth: false });
}
return this.client.proxy.webhooks(webhookId).patch({ body, reason });
},
fetch: async (webhookId: string, token?: string) => {
let webhook;
if (token) {
webhook = await this.client.proxy.webhooks(webhookId)(token).get({ auth: false });
} else {
webhook = await this.client.proxy.webhooks(webhookId).get();
}
return new Webhook(this.client, webhook);
},
messages: this.messages,
};
/**
* Deletes a webhook.
* @param webhookId The ID of the webhook.
* @param options The optional parameters including token and reason.
* @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: options.reason });
}
get messages() {
return {
write: async (webhookId: string, token: string, { body: data, ...payload }: MessageWebhookMethodWriteParams) => {
const { files, ...body } = data;
const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIWebhookWithTokenJSONBody>(body);
const parsedFiles = files ? await resolveFiles(files) : [];
return this.client.proxy
.webhooks(webhookId)(token)
.post({ ...payload, files: parsedFiles, body: transformedBody })
.then(m => (m?.id ? new WebhookMessage(this.client, m, webhookId, token) : null));
},
edit: async (
webhookId: string,
token: string,
{ messageId, body: data, ...json }: MessageWebhookMethodEditParams,
) => {
const { files, ...body } = data;
const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIWebhookWithTokenJSONBody>(body);
const parsedFiles = files ? await resolveFiles(files) : [];
return this.client.proxy
.webhooks(webhookId)(token)
.messages(messageId)
.patch({ ...json, auth: false, files: parsedFiles, body: transformedBody })
.then(m => new WebhookMessage(this.client, m, webhookId, token));
},
delete: async (webhookId: string, token: string, messageId: string, reason?: string) => {
return this.client.proxy.webhooks(webhookId)(token).messages(messageId).delete({ reason });
},
fetch: async (webhookId: string, token: string, messageId: string, threadId?: string) => {
const message = await this.client.proxy
.webhooks(webhookId)(token)
.messages(messageId)
.get({ auth: false, query: { threadId } });
return message ? new WebhookMessage(this.client, message, webhookId, token) : undefined;
},
};
/**
* 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,
body: RESTPatchAPIWebhookWithTokenJSONBody | RESTPatchAPIWebhookJSONBody,
options: WebhookShorterOptionalParams,
) {
if (options.token) {
return this.client.proxy.webhooks(webhookId)(options.token).patch({ body, reason: options.reason, auth: false });
}
return this.client.proxy.webhooks(webhookId).patch({ body, reason: options.reason });
}
/**
* 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;
if (token) {
webhook = await this.client.proxy.webhooks(webhookId)(token).get({ auth: false });
} else {
webhook = await this.client.proxy.webhooks(webhookId).get();
}
return new Webhook(this.client, webhook);
}
/**
* Writes a message using the webhook.
* @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 transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIWebhookWithTokenJSONBody>(body);
const parsedFiles = files ? await resolveFiles(files) : [];
return this.client.proxy
.webhooks(webhookId)(token)
.post({ ...payload, files: parsedFiles, body: transformedBody })
.then(m => (m?.id ? new WebhookMessage(this.client, m, webhookId, token) : null));
}
/**
* 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,
token: string,
{ messageId, body: data, ...json }: MessageWebhookMethodEditParams,
) {
const { files, ...body } = data;
const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIWebhookWithTokenJSONBody>(body);
const parsedFiles = files ? await resolveFiles(files) : [];
return this.client.proxy
.webhooks(webhookId)(token)
.messages(messageId)
.patch({ ...json, auth: false, files: parsedFiles, body: transformedBody })
.then(m => new WebhookMessage(this.client, m, webhookId, token));
}
/**
* 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 });
}
/**
* 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
.webhooks(webhookId)(token)
.messages(messageId)
.get({ auth: false, query: { threadId } });
return message ? new WebhookMessage(this.client, message, webhookId, token) : undefined;
}
}

View File

@ -55,7 +55,9 @@ export class Shard {
}
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() {