This commit is contained in:
MARCROCK22 2024-03-18 19:10:46 -04:00
commit 870e18a056
26 changed files with 985 additions and 929 deletions

View File

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

View File

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

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) => {
( callback: {
id: string, post(args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIInteractionCallbackJSONBody>): Promise<never>;
): {
(
token: string,
): {
callback: {
post(args: RestArguments<ProxyRequestMethod.Post, RESTPostAPIInteractionCallbackJSONBody>): Promise<never>;
};
};
}; };
}; };
} }

View File

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

View File

@ -7,37 +7,42 @@ 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';
import type { ChatInputCommandInteraction, MessageCommandInteraction, UserCommandInteraction } from '../structures'; import type { ChatInputCommandInteraction, Message, MessageCommandInteraction, UserCommandInteraction } from '../structures';
export class BaseClient { 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;
@ -240,7 +245,8 @@ export interface BaseClientOptions {
interaction: interaction:
| ChatInputCommandInteraction<boolean> | ChatInputCommandInteraction<boolean>
| UserCommandInteraction<boolean> | UserCommandInteraction<boolean>
| MessageCommandInteraction<boolean>, | MessageCommandInteraction<boolean>
| Message
) => {}; ) => {};
globalMiddlewares?: readonly (keyof RegisteredMiddlewares)[]; globalMiddlewares?: readonly (keyof RegisteredMiddlewares)[];
} }

View File

@ -44,15 +44,15 @@ function getCommandFromContent(
const command = const command =
groupName || subcommandName groupName || subcommandName
? (parent.options?.find(opt => { ? (parent.options?.find(opt => {
if (opt instanceof SubCommand) { if (opt instanceof SubCommand) {
if (groupName) { if (groupName) {
if (opt.group !== groupName) return false; if (opt.group !== groupName) return false;
}
if (opt.group && !groupName) return false;
return subcommandName === opt.name;
} }
return false; if (opt.group && !groupName) return false;
}) as SubCommand) return subcommandName === opt.name;
}
return false;
}) as SubCommand)
: parent; : parent;
return { return {
@ -97,6 +97,8 @@ export async function onMessageCreate(
const { options, errors } = await parseOptions(self, command, rawMessage, args, resolved); const { options, errors } = await parseOptions(self, command, rawMessage, args, resolved);
const optionsResolver = new OptionResolver(self, options, parent as Command, message.guildId, resolved); const optionsResolver = new OptionResolver(self, options, parent as Command, message.guildId, resolved);
const context = new CommandContext(self, message, optionsResolver, shardId, command); const context = new CommandContext(self, message, optionsResolver, shardId, command);
const extendContext = self.options?.context?.(message) ?? {};
Object.assign(context, extendContext);
try { try {
if (command.botPermissions && message.guildId) { if (command.botPermissions && message.guildId) {
const meMember = await self.cache.members?.get(self.botId, message.guildId); const meMember = await self.cache.members?.get(self.botId, message.guildId);

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,180 +5,158 @@ 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() { /**
* 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 { return {
/** everyone: everyoneOverwrites,
* Fetches a channel by its ID. roles: roleOverwrites,
* @param id The ID of the channel to fetch. member: memberOverwrites,
* @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,
}; };
} }
get pins() { async rolePermissions(channelId: string, role: GuildRole, checkAdmin = true): Promise<PermissionsBitField> {
return { if (checkAdmin && role.permissions.has(PermissionFlagsBits.Administrator)) {
/** return new PermissionsBitField(PermissionsBitField.All);
* Fetches pinned messages in the channel. }
* @param channelId The ID of the channel. const channelOverwrites = (await this.client.cache.overwrites?.get(channelId)) ?? [];
* @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))),
/** const everyoneOverwrites = channelOverwrites.find(x => x.id === role.guildId);
* Pins a message in the channel. const roleOverwrites = channelOverwrites.find(x => x.id === role.id);
* @param messageId The ID of the message to pin. const permissions = new PermissionsBitField(role.permissions.bits);
* @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 }),
/** permissions.remove(everyoneOverwrites?.deny.bits ?? 0n);
* Unpins a message in the channel. permissions.add(everyoneOverwrites?.allow.bits ?? 0n);
* @param messageId The ID of the message to unpin. permissions.remove(roleOverwrites?.deny.bits ?? 0n);
* @param channelId The ID of the channel. permissions.add(roleOverwrites?.allow.bits ?? 0n);
* @param reason The reason for unpinning the message. return permissions;
* @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;
},
};
} }
} }

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,
@ -27,163 +25,67 @@ import { BaseShorter } from './base';
export class GuildShorter extends BaseShorter { 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() { async create(body: RESTPostAPIGuildsJSONBody): Promise<Guild<'api'>> {
return { const guild = await this.client.proxy.guilds.post({ body });
/** await this.client.cache.guilds?.setIfNI('Guilds', guild.id, guild);
* Creates a new guild. return new Guild<'api'>(this.client, 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,
};
} }
/** /**
* 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() { async fetch(id: string, force = false) {
return { if (!force) {
/** const guild = await this.client.cache.guilds?.get(id);
* Retrieves a list of emojis in the guild. if (guild) return 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));
},
/** const data = await this.client.proxy.guilds(id).get();
* Creates a new emoji in the guild. await this.client.cache.guilds?.patch(id, data);
* @param guildId The ID of the guild. return (await this.client.cache.guilds?.get(id)) ?? new Guild<'api'>(this.client, data);
* @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. * Generates the widget URL for the guild.
* @param guildId The ID of the guild. * @param id The ID of the guild.
* @param emojiId The ID of the emoji to fetch. * @param style The style of the widget.
* @param force Whether to force fetching the emoji from the API even if it exists in the cache. * @returns The generated widget URL.
* @returns A Promise that resolves to the fetched emoji. */
*/ widgetURL(id: string, style?: GuildWidgetStyle) {
fetch: async (guildId: string, emojiId: string, force = false) => { const query = new URLSearchParams();
let emoji; if (style) {
if (!force) { query.append('style', style);
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);
},
/** return this.client.proxy.guilds(id).widget.get({ query });
* 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);
},
/** list(query?: RESTGetAPICurrentUserGuildsQuery) {
* Edits an emoji in the guild. return this.client.proxy
* @param guildId The ID of the guild. .users('@me')
* @param emojiId The ID of the emoji to edit. .guilds.get({ query })
* @param body The data to update the emoji with. .then(guilds => guilds.map(guild => new AnonymousGuild(this.client, { ...guild, splash: null })));
* @param reason The reason for editing the emoji. }
* @returns A Promise that resolves to the edited emoji.
*/ async fetchSelf(id: string) {
edit: async (guildId: string, emojiId: string, body: RESTPatchAPIGuildEmojiJSONBody, reason?: string) => { const self = await this.client.proxy.guilds(id).members(this.client.botId).get();
const emoji = await this.client.proxy.guilds(guildId).emojis(emojiId).patch({ body, reason }); await this.client.cache.members?.patch(self.user!.id, id, self);
await this.client.cache.channels?.setIfNI('GuildEmojisAndStickers', emoji.id!, guildId, emoji); return new GuildMember(this.client, self, self.user!, id);
return new GuildEmoji(this.client, emoji, guildId); }
},
}; 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(); 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

@ -13,188 +13,172 @@ import { BaseShorter } from './base';
export class MemberShorter extends BaseShorter { 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() { async resolve(guildId: string, resolve: GuildMemberResolvable) {
return { if (typeof resolve === 'string') {
/** const match: { id?: string } | undefined = resolve.match(FormattingPatterns.User)?.groups;
* Resolves a member in the guild based on the provided GuildMemberResolvable. if (match?.id) {
* @param guildId The ID of the guild. return this.fetch(guildId, match.id);
* @param resolve The GuildMemberResolvable to resolve. }
* @returns A Promise that resolves to the resolved member. if (resolve.match(/\d{17,20}/)) {
*/ return this.fetch(guildId, resolve);
resolve: async (guildId: string, resolve: GuildMemberResolvable) => { }
if (typeof resolve === 'string') { return this.search(guildId, { query: resolve, limit: 1 }).then(x => x[0]);
const match: { id?: string } | undefined = resolve.match(FormattingPatterns.User)?.groups; }
if (match?.id) { if (resolve.id) {
return this.members.fetch(guildId, match.id); return this.client.members.fetch(guildId, resolve.id);
} }
if (resolve.match(/\d{17,20}/)) { return resolve.displayName
return this.members.fetch(guildId, resolve); ? this.search(guildId, { query: resolve.displayName, limit: 1 }).then(x => x[0])
} : undefined;
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,
};
} }
get roles() { /**
return { * Searches for members in the guild based on the provided query.
/** * @param guildId The ID of the guild.
* Adds a role to a guild member. * @param query The query parameters for searching members.
* @param guildId The ID of the guild. * @returns A Promise that resolves to an array of matched members.
* @param memberId The ID of the member to add the role to. */
* @param id The ID of the role to add. async search(guildId: string, query?: RESTGetAPIGuildMembersSearchQuery) {
*/ const members = await this.client.proxy.guilds(guildId).members.search.get({
add: async (guildId: string, memberId: string, id: string) => { query,
await this.client.proxy.guilds(guildId).members(memberId).roles(id).put({}); });
}, 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. * Unbans a member from the guild.
* @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 unban.
* @param id The ID of the role to remove. * @param body The request body for unbanning the member.
*/ * @param reason The reason for unbanning the member.
remove: async (guildId: string, memberId: string, id: string) => { */
await this.client.proxy.guilds(guildId).members(memberId).roles(id).delete(); 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 { 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 { const parsedFiles = files ? await resolveFiles(files) : [];
write: async (channelId: string, { files, ...body }: MessageCreateBodyRequest) => {
const parsedFiles = files ? await resolveFiles(files) : [];
const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIChannelMessageJSONBody>(body); const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIChannelMessageJSONBody>(body);
return this.client.proxy return this.client.proxy
.channels(channelId) .channels(channelId)
.messages.post({ .messages.post({
body: transformedBody, body: transformedBody,
files: parsedFiles, files: parsedFiles,
}) })
.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)
.messages(messageId) .messages(messageId)
.patch({ .patch({
body: MessagesMethods.transformMessageBody<RESTPatchAPIChannelMessageJSONBody>(body), body: MessagesMethods.transformMessageBody<RESTPatchAPIChannelMessageJSONBody>(body),
files: parsedFiles, files: parsedFiles,
}) })
.then(message => { .then(message => {
return new Message(this.client, 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,
};
} }
get reactions() { crosspost(messageId: string, channelId: string, reason?: string) {
return { return this.client.proxy
add: async (messageId: string, channelId: string, emoji: EmojiResolvable) => { .channels(channelId)
const rawEmoji = await resolveEmoji(emoji, this.client.cache); .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) { thread(
throw new Error('Emoji no resolvable'); channelId: string,
} messageId: string,
options: RESTPostAPIChannelMessagesThreadsJSONBody & { reason?: string },
) {
const { reason, ...body } = options;
return this.client.proxy return this.client.proxy
.channels(channelId) .channels(channelId)
.messages(messageId) .messages(messageId)
.reactions(encodeEmoji(rawEmoji))('@me') .threads.post({ body, reason })
.put({}); .then(x => new ThreadChannel(this.client, x));
},
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();
},
};
} }
} }

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'; 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.
.guilds(guildId) * @param reason The reason for creating the role.
.roles.post({ body, reason }) * @returns A Promise that resolves when the role is created.
.then(res => this.client.cache.roles?.setIfNI('Guilds', res.id, guildId, res)), */
list: async (guildId: string, force = false) => { create(guildId: string, body: RESTPostAPIGuildRoleJSONBody, reason?: string) {
let roles: APIRole[] = []; return this.client.proxy
if (!force) { .guilds(guildId)
const cachedRoles = (await this.client.cache.roles?.values(guildId)) ?? []; .roles.post({ body, reason })
if (cachedRoles.length) { .then(res => this.client.cache.roles?.setIfNI('Guilds', res.id, guildId, res));
return cachedRoles; }
}
} /**
roles = await this.client.proxy.guilds(guildId).roles.get(); * Retrieves a list of roles in the guild.
await this.client.cache.roles?.set( * @param guildId The ID of the guild.
roles.map(r => [r.id, r]), * @param force Whether to force fetching roles from the API even if they exist in the cache.
guildId, * @returns A Promise that resolves to an array of roles.
); */
return roles.map(r => new GuildRole(this.client, r, guildId)); async list(guildId: string, force = false) {
}, let roles: APIRole[] = [];
edit: (guildId: string, roleId: string, body: RESTPatchAPIGuildRoleJSONBody, reason?: string) => { if (!force) {
return this.client.proxy const cachedRoles = (await this.client.cache.roles?.values(guildId)) ?? [];
.guilds(guildId) if (cachedRoles.length) {
.roles(roleId) return cachedRoles;
.patch({ body, reason }) }
.then(res => this.client.cache.roles?.setIfNI('Guilds', roleId, guildId, res)); }
}, roles = await this.client.proxy.guilds(guildId).roles.get();
delete: (guildId: string, roleId: string, reason?: string) => { await this.client.cache.roles?.set(
return this.client.proxy roles.map<[string, APIRole]>(r => [r.id, r]),
.guilds(guildId) guildId,
.roles(roleId) );
.delete({ reason }) return roles.map(r => new GuildRole(this.client, r, guildId));
.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({ * Edits a role in the guild.
body, * @param guildId The ID of the guild.
}); * @param roleId The ID of the role to edit.
if (!this.client.cache.hasRolesIntent) { * @param body The data to update the role with.
await this.client.cache.roles?.set( * @param reason The reason for editing the role.
roles.map(x => [x.id, x]), * @returns A Promise that resolves when the role is edited.
guildId, */
); edit(guildId: string, roleId: string, body: RESTPatchAPIGuildRoleJSONBody, reason?: string) {
} return this.client.proxy
return roles.map(x => new GuildRole(this.client, x, guildId)); .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'; import { BaseShorter } from './base';
export class TemplateShorter extends BaseShorter { export class TemplateShorter extends BaseShorter {
get templates() { fetch(code: string) {
return { return this.client.proxy.guilds.templates(code).get();
fetch: (code: string) => { }
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) => {
return this.client.proxy.guilds(guildId).templates(code).put({}); 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 });
}, edit(guildId: string, code: string, body: RESTPatchAPIGuildTemplateJSONBody) {
delete: (guildId: string, code: string) => { return this.client.proxy.guilds(guildId).templates(code).patch({ body });
return this.client.proxy.guilds(guildId).templates(code).delete(); }
},
}; 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'; 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,82 +5,128 @@ 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.
} */
return this.client.proxy.webhooks(webhookId).delete({ reason }); delete(webhookId: string, options: WebhookShorterOptionalParams) {
}, if (options.token) {
edit: ( return this.client.proxy.webhooks(webhookId)(options.token).delete({ reason: options.reason, auth: false });
webhookId: string, }
body: RESTPatchAPIWebhookWithTokenJSONBody | RESTPatchAPIWebhookJSONBody, return this.client.proxy.webhooks(webhookId).delete({ reason: options.reason });
{ 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,
};
} }
get messages() { /**
return { * Edits a webhook.
write: async (webhookId: string, token: string, { body: data, ...payload }: MessageWebhookMethodWriteParams) => { * @param webhookId The ID of the webhook.
const { files, ...body } = data; * @param body The data to update the webhook with.
const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIWebhookWithTokenJSONBody>(body); * @param options The optional parameters including token and reason.
const parsedFiles = files ? await resolveFiles(files) : []; * @returns A Promise that resolves when the webhook is edited.
return this.client.proxy */
.webhooks(webhookId)(token) edit(
.post({ ...payload, files: parsedFiles, body: transformedBody }) webhookId: string,
.then(m => (m?.id ? new WebhookMessage(this.client, m, webhookId, token) : null)); body: RESTPatchAPIWebhookWithTokenJSONBody | RESTPatchAPIWebhookJSONBody,
}, options: WebhookShorterOptionalParams,
edit: async ( ) {
webhookId: string, if (options.token) {
token: string, return this.client.proxy.webhooks(webhookId)(options.token).patch({ body, reason: options.reason, auth: false });
{ messageId, body: data, ...json }: MessageWebhookMethodEditParams, }
) => { return this.client.proxy.webhooks(webhookId).patch({ body, reason: options.reason });
const { files, ...body } = data; }
const transformedBody = MessagesMethods.transformMessageBody<RESTPostAPIWebhookWithTokenJSONBody>(body);
const parsedFiles = files ? await resolveFiles(files) : []; /**
return this.client.proxy * Fetches a webhook.
.webhooks(webhookId)(token) * @param webhookId The ID of the webhook.
.messages(messageId) * @param token The token of the webhook (optional).
.patch({ ...json, auth: false, files: parsedFiles, body: transformedBody }) * @returns A Promise that resolves to the fetched webhook.
.then(m => new WebhookMessage(this.client, m, webhookId, token)); */
}, async fetch(webhookId: string, token?: string) {
delete: async (webhookId: string, token: string, messageId: string, reason?: string) => { let webhook;
return this.client.proxy.webhooks(webhookId)(token).messages(messageId).delete({ reason }); if (token) {
}, webhook = await this.client.proxy.webhooks(webhookId)(token).get({ auth: false });
fetch: async (webhookId: string, token: string, messageId: string, threadId?: string) => { } else {
const message = await this.client.proxy webhook = await this.client.proxy.webhooks(webhookId).get();
.webhooks(webhookId)(token) }
.messages(messageId) return new Webhook(this.client, webhook);
.get({ auth: false, query: { threadId } }); }
return message ? new WebhookMessage(this.client, message, webhookId, token) : undefined;
}, /**
}; * 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

@ -1,7 +1,7 @@
import type { InternalRuntimeConfig, InternalRuntimeConfigHTTP, RuntimeConfig, RuntimeConfigHTTP } from './client/base'; import type { InternalRuntimeConfig, InternalRuntimeConfigHTTP, RuntimeConfig, RuntimeConfigHTTP } from './client/base';
import { GatewayIntentBits } from './common'; import { GatewayIntentBits } from './common';
import type { ClientNameEvents, EventContext } from './events'; import type { ClientNameEvents, EventContext } from './events';
import type { ChatInputCommandInteraction, MessageCommandInteraction, UserCommandInteraction } from './structures'; import type { ChatInputCommandInteraction, Message, MessageCommandInteraction, UserCommandInteraction } from './structures';
export { Logger, PermissionFlagsBits, PermissionStrings, Watcher } from './common'; export { Logger, PermissionFlagsBits, PermissionStrings, Watcher } from './common';
// //
@ -95,7 +95,7 @@ export const config = {
* }); * });
*/ */
export function extendContext<T extends {}>( export function extendContext<T extends {}>(
cb: (interaction: ChatInputCommandInteraction | UserCommandInteraction | MessageCommandInteraction) => T, cb: (interaction: ChatInputCommandInteraction | UserCommandInteraction | MessageCommandInteraction | Message) => T,
) { ) {
return cb; return cb;
} }

View File

@ -2,7 +2,7 @@ import type { BaseImageURLOptions } from '../api';
import type { BaseClient } from '../client/base'; import type { BaseClient } from '../client/base';
import type { import type {
APIEmoji, APIEmoji,
GuildShorter, EmojiShorter,
MethodContext, MethodContext,
ObjectToLower, ObjectToLower,
RESTPatchAPIChannelJSONBody, RESTPatchAPIChannelJSONBody,
@ -27,15 +27,15 @@ export class GuildEmoji extends DiscordBase {
} }
edit(body: RESTPatchAPIChannelJSONBody, reason?: string) { edit(body: RESTPatchAPIChannelJSONBody, reason?: string) {
return this.client.guilds.emojis.edit(this.guildId, this.id, body, reason); return this.client.emojis.edit(this.guildId, this.id, body, reason);
} }
delete(reason?: string) { delete(reason?: string) {
return this.client.guilds.emojis.delete(this.guildId, this.id, reason); return this.client.emojis.delete(this.guildId, this.id, reason);
} }
fetch(force = false) { fetch(force = false) {
return this.client.guilds.emojis.fetch(this.guildId, this.id, force); return this.client.emojis.fetch(this.guildId, this.id, force);
} }
url(options?: BaseImageURLOptions) { url(options?: BaseImageURLOptions) {
@ -57,10 +57,10 @@ export class GuildEmoji extends DiscordBase {
static methods({ client, guildId }: MethodContext<{ guildId: string }>) { static methods({ client, guildId }: MethodContext<{ guildId: string }>) {
return { return {
edit: (emojiId: string, body: RESTPatchAPIGuildEmojiJSONBody, reason?: string) => edit: (emojiId: string, body: RESTPatchAPIGuildEmojiJSONBody, reason?: string) =>
client.guilds.emojis.edit(guildId, emojiId, body, reason), client.emojis.edit(guildId, emojiId, body, reason),
create: (body: Parameters<GuildShorter['emojis']['create']>[1]) => client.guilds.emojis.create(guildId, body), create: (body: Parameters<EmojiShorter['create']>[1]) => client.emojis.create(guildId, body),
fetch: (emojiId: string, force = false) => client.guilds.emojis.fetch(guildId, emojiId, force), fetch: (emojiId: string, force = false) => client.emojis.fetch(guildId, emojiId, force),
list: (force = false) => client.guilds.emojis.list(guildId, force), list: (force = false) => client.emojis.list(guildId, force),
}; };
} }
} }

View File

@ -96,8 +96,8 @@ export class BaseGuildMember extends DiscordBase {
get roles() { get roles() {
return { return {
values: Object.freeze(this._roles), values: Object.freeze(this._roles),
add: (id: string) => this.client.members.roles.add(this.guildId, this.id, id), add: (id: string) => this.client.members.addRole(this.guildId, this.id, id),
remove: (id: string) => this.client.members.roles.remove(this.guildId, this.id, id), remove: (id: string) => this.client.members.removeRole(this.guildId, this.id, id),
permissions: async () => permissions: async () =>
new PermissionsBitField( new PermissionsBitField(
((await this.cache.roles?.bulk(this.roles.values as string[])) ?? []) ((await this.cache.roles?.bulk(this.roles.values as string[])) ?? [])

View File

@ -326,7 +326,7 @@ export class Interaction<
Type extends APIInteraction = APIInteraction, Type extends APIInteraction = APIInteraction,
> extends BaseInteraction<FromGuild, Type> { > extends BaseInteraction<FromGuild, Type> {
fetchMessage(messageId: string) { fetchMessage(messageId: string) {
return this.client.webhooks.messages.fetch(this.applicationId, this.token, messageId); return this.client.webhooks.fetchMessage(this.applicationId, this.token, messageId);
} }
fetchResponse() { fetchResponse() {

View File

@ -64,7 +64,7 @@ export class BaseMessage extends DiscordBase {
} }
react(emoji: EmojiResolvable) { react(emoji: EmojiResolvable) {
return this.client.messages.reactions.add(this.id, this.channelId, emoji); return this.client.reactions.add(this.id, this.channelId, emoji);
} }
private patch(data: MessageData) { private patch(data: MessageData) {
@ -170,14 +170,14 @@ export class WebhookMessage extends BaseMessage {
} }
edit(body: EditMessageWebhook) { edit(body: EditMessageWebhook) {
return this.client.webhooks.messages.edit(this.webhookId, this.webhookToken, { ...body, messageId: this.id }); return this.client.webhooks.editMessage(this.webhookId, this.webhookToken, { ...body, messageId: this.id });
} }
write(body: WriteMessageWebhook) { write(body: WriteMessageWebhook) {
return this.client.webhooks.messages.write(this.webhookId, this.webhookToken, body); return this.client.webhooks.writeMessage(this.webhookId, this.webhookToken, body);
} }
delete(reason?: string) { delete(reason?: string) {
return this.client.webhooks.messages.delete(this.webhookId, this.webhookToken, this.id, reason); return this.client.webhooks.deleteMessage(this.webhookId, this.webhookToken, this.id, reason);
} }
} }

View File

@ -71,11 +71,10 @@ export class Webhook extends DiscordBase {
static messages({ client, webhookId, webhookToken }: MethodContext<{ webhookId: string; webhookToken: string }>) { static messages({ client, webhookId, webhookToken }: MethodContext<{ webhookId: string; webhookToken: string }>) {
return { return {
write: (payload: MessageWebhookMethodWriteParams) => write: (payload: MessageWebhookMethodWriteParams) =>
client.webhooks.messages.write(webhookId, webhookToken, payload), client.webhooks.writeMessage(webhookId, webhookToken, payload),
edit: (payload: MessageWebhookMethodEditParams) => edit: (payload: MessageWebhookMethodEditParams) => client.webhooks.editMessage(webhookId, webhookToken, payload),
client.webhooks.messages.edit(webhookId, webhookToken, payload),
delete: (messageId: string, reason?: string) => delete: (messageId: string, reason?: string) =>
client.webhooks.messages.delete(webhookId, webhookToken, messageId, reason), client.webhooks.deleteMessage(webhookId, webhookToken, messageId, reason),
}; };
} }

View File

@ -176,15 +176,15 @@ export class BaseGuildChannel extends BaseChannel<ChannelType> {
}; };
memberPermissions(member: GuildMember, checkAdmin = true) { memberPermissions(member: GuildMember, checkAdmin = true) {
return this.client.channels.overwrites.memberPermissions(this.id, member, checkAdmin); return this.client.channels.memberPermissions(this.id, member, checkAdmin);
} }
rolePermissions(role: GuildRole, checkAdmin = true) { rolePermissions(role: GuildRole, checkAdmin = true) {
return this.client.channels.overwrites.rolePermissions(this.id, role, checkAdmin); return this.client.channels.rolePermissions(this.id, role, checkAdmin);
} }
overwritesFor(member: GuildMember) { overwritesFor(member: GuildMember) {
return this.client.channels.overwrites.overwritesFor(this.id, member); return this.client.channels.overwritesFor(this.id, member);
} }
guild(force = false) { guild(force = false) {
@ -233,21 +233,20 @@ export class MessagesMethods extends DiscordBase {
static reactions(ctx: MethodContext<{ channelId: string }>) { static reactions(ctx: MethodContext<{ channelId: string }>) {
return { return {
add: (messageId: string, emoji: EmojiResolvable) => add: (messageId: string, emoji: EmojiResolvable) => ctx.client.reactions.add(messageId, ctx.channelId, emoji),
ctx.client.messages.reactions.add(messageId, ctx.channelId, emoji),
delete: (messageId: string, emoji: EmojiResolvable, userId = '@me') => delete: (messageId: string, emoji: EmojiResolvable, userId = '@me') =>
ctx.client.messages.reactions.delete(messageId, ctx.channelId, emoji, userId), ctx.client.reactions.delete(messageId, ctx.channelId, emoji, userId),
fetch: (messageId: string, emoji: EmojiResolvable, query?: RESTGetAPIChannelMessageReactionUsersQuery) => fetch: (messageId: string, emoji: EmojiResolvable, query?: RESTGetAPIChannelMessageReactionUsersQuery) =>
ctx.client.messages.reactions.fetch(messageId, ctx.channelId, emoji, query), ctx.client.reactions.fetch(messageId, ctx.channelId, emoji, query),
purge: (messageId: string, emoji?: EmojiResolvable) => purge: (messageId: string, emoji?: EmojiResolvable) =>
ctx.client.messages.reactions.purge(messageId, ctx.channelId, emoji), ctx.client.reactions.purge(messageId, ctx.channelId, emoji),
}; };
} }
static pins(ctx: MethodContext<{ channelId: string }>) { static pins(ctx: MethodContext<{ channelId: string }>) {
return { return {
fetch: () => ctx.client.channels.pins.fetch(ctx.channelId), fetch: () => ctx.client.channels.pins(ctx.channelId),
set: (messageId: string, reason?: string) => ctx.client.channels.pins.set(messageId, ctx.channelId, reason), set: (messageId: string, reason?: string) => ctx.client.channels.setPin(messageId, ctx.channelId, reason),
delete: (messageId: string, reason?: string) => ctx.client.channels.pins.delete(messageId, ctx.channelId, reason), delete: (messageId: string, reason?: string) => ctx.client.channels.deletePin(messageId, ctx.channelId, reason),
}; };
} }

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() {