feat: thread methods and shorter (#184)

* feat: threads methods

* fix: typing

* fix: fixes
This commit is contained in:
Marcos Susaña 2024-04-16 15:07:11 -04:00 committed by GitHub
parent 838ebd5c27
commit 773c0a38c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 163 additions and 35 deletions

View File

@ -17,6 +17,7 @@ import {
ReactionShorter,
RoleShorter,
TemplateShorter,
ThreadShorter,
UsersShorter,
WebhookShorter,
filterSplit,
@ -50,6 +51,7 @@ export class BaseClient {
roles = new RoleShorter(this);
reactions = new ReactionShorter(this);
emojis = new EmojiShorter(this);
threads = new ThreadShorter(this);
debugger?: Logger;

View File

@ -12,6 +12,7 @@ export * from './shorters/reactions';
export * from './shorters/roles';
export * from './shorters/templates';
export * from './shorters/users';
export * from './shorters/threads';
export * from './shorters/webhook';
export * from './types/options';
export * from './types/resolvables';

View File

@ -5,9 +5,10 @@ import {
type RESTPostAPIGuildForumThreadsJSONBody,
} from 'discord-api-types/v10';
import { BaseChannel, Message, type GuildMember, type GuildRole } from '../../structures';
import channelFrom, { type AllChannels, type ThreadChannel } from '../../structures/channels';
import channelFrom, { type AllChannels } from '../../structures/channels';
import { PermissionsBitField } from '../../structures/extra/Permissions';
import { BaseShorter } from './base';
import { MergeOptions } from '../it/utils';
export class ChannelShorter extends BaseShorter {
/**
@ -35,8 +36,9 @@ export class ChannelShorter extends BaseShorter {
* @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!);
const options = MergeOptions<ChannelShorterOptionalParams>({ guildId: '@me' }, optional);
const res = await this.client.proxy.channels(id).delete({ reason: options.reason });
await this.client.cache.channels?.removeIfNI(BaseChannel.__intent__(options.guildId!), res.id, options.guildId!);
return channelFrom(res, this.client);
}
@ -52,18 +54,14 @@ export class ChannelShorter extends BaseShorter {
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,
);
const options = MergeOptions<ChannelShorterOptionalParams>({ guildId: '@me' }, optional);
const res = await this.client.proxy.channels(id).patch({ body, reason: options.reason });
await this.client.cache.channels?.setIfNI(BaseChannel.__intent__(options.guildId!), res.id, options.guildId!, res);
if (body.permission_overwrites && 'permission_overwrites' in res)
await this.client.cache.overwrites?.setIfNI(
BaseChannel.__intent__(optional.guildId!),
BaseChannel.__intent__(options.guildId!),
res.id,
optional.guildId!,
options.guildId!,
res.permission_overwrites,
);
return channelFrom(res, this.client);
@ -116,13 +114,7 @@ export class ChannelShorter extends BaseShorter {
body: RESTPostAPIChannelThreadsJSONBody | RESTPostAPIGuildForumThreadsJSONBody,
reason?: string,
) {
return (
this.client.proxy
.channels(channelId)
.threads.post({ body, reason })
// When testing this, discord returns the thread object, but in discord api types it does not.
.then(thread => channelFrom(thread, this.client) as ThreadChannel)
);
return this.client.threads.create(channelId, body, reason);
}
async memberPermissions(channelId: string, member: GuildMember, checkAdmin = true): Promise<PermissionsBitField> {

View File

@ -185,6 +185,15 @@ export class GuildShorter extends BaseShorter {
*/
editPositions: (guildId: string, body: RESTPatchAPIGuildChannelPositionsJSONBody) =>
this.client.proxy.guilds(guildId).channels.patch({ body }),
addFollower: async (channelId: string, webhook_channel_id: string, reason?: string) => {
return this.client.proxy.channels(channelId).followers.post({
body: {
webhook_channel_id,
},
reason,
});
},
};
}

View File

@ -4,8 +4,8 @@ import type {
RESTPostAPIChannelMessagesThreadsJSONBody,
} from 'discord-api-types/v10';
import { resolveFiles } from '../../builders';
import { Message, MessagesMethods, type ThreadChannel } from '../../structures';
import channelFrom from '../../structures/channels';
import { Message, MessagesMethods } from '../../structures';
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../types/write';
import { BaseShorter } from './base';
@ -70,12 +70,6 @@ export class MessageShorter extends BaseShorter {
messageId: string,
options: RESTPostAPIChannelMessagesThreadsJSONBody & { reason?: string },
) {
const { reason, ...body } = options;
return this.client.proxy
.channels(channelId)
.messages(messageId)
.threads.post({ body, reason })
.then(thread => channelFrom(thread, this.client) as ThreadChannel);
return this.client.threads.fromMessage(channelId, messageId, options);
}
}

View File

@ -0,0 +1,125 @@
import type {
APIThreadMember,
RESTGetAPIChannelThreadMembersQuery,
RESTGetAPIChannelThreadsArchivedQuery,
RESTPatchAPIChannelJSONBody,
RESTPostAPIChannelMessagesThreadsJSONBody,
RESTPostAPIChannelThreadsJSONBody,
RESTPostAPIGuildForumThreadsJSONBody,
} from 'discord-api-types/v10';
import type { ThreadChannel } from '../../structures';
import channelFrom from '../../structures/channels';
import { BaseShorter } from './base';
import type { MakeRequired, When } from '../types/util';
export class ThreadShorter extends BaseShorter {
/**
* Creates a new thread in the channel (only guild based channels).
* @param channelId The ID of the parent channel.
* @param reason The reason for unpinning the message.
* @returns A promise that resolves when the thread is succesfully created.
*/
async create(
channelId: string,
body: RESTPostAPIChannelThreadsJSONBody | RESTPostAPIGuildForumThreadsJSONBody,
reason?: string,
) {
return (
this.client.proxy
.channels(channelId)
.threads.post({ body, reason })
// When testing this, discord returns the thread object, but in discord api types it does not.
.then(thread => channelFrom(thread, this.client) as ThreadChannel)
);
}
async fromMessage(
channelId: string,
messageId: string,
options: RESTPostAPIChannelMessagesThreadsJSONBody & { reason?: string },
) {
const { reason, ...body } = options;
return this.client.proxy
.channels(channelId)
.messages(messageId)
.threads.post({ body, reason })
.then(thread => channelFrom(thread, this.client) as ThreadChannel);
}
async join(threadId: string) {
return this.client.proxy.channels(threadId)['thread-members']('@me').put();
}
async leave(threadId: string) {
return this.client.proxy.channels(threadId)['thread-members']('@me').delete();
}
async lock(threadId: string, locked = true, reason?: string) {
return this.edit(threadId, { locked }, reason).then(x => channelFrom(x, this.client) as ThreadChannel);
}
async edit(threadId: string, body: RESTPatchAPIChannelJSONBody, reason?: string) {
return this.client.channels.edit(threadId, body, { reason });
}
async removeMember(threadId: string, memberId: string) {
return this.client.proxy.channels(threadId)['thread-members'](memberId).delete();
}
async fetchMember<WithMember extends boolean = false>(
threadId: string,
memberId: string,
with_member: WithMember,
): Promise<When<WithMember, Required<APIThreadMember>, GetAPIChannelThreadMemberResult>> {
return this.client.proxy.channels(threadId)['thread-members'](memberId).get({
query: {
with_member,
},
}) as never;
}
async addMember(threadId: string, memberId: string) {
return this.client.proxy.channels(threadId)['thread-members'](memberId).put();
}
async listMembers<T extends RESTGetAPIChannelThreadMembersQuery = RESTGetAPIChannelThreadMembersQuery>(
threadId: string,
query?: T,
): Promise<InferWithMemberOnList<T>> {
return this.client.proxy.channels(threadId)['thread-members'].get({ query }) as never;
}
async listArchivedThreads(
channelId: string,
type: 'public' | 'private',
query?: RESTGetAPIChannelThreadsArchivedQuery,
) {
const data = await this.client.proxy.channels(channelId).threads.archived[type].get({ query });
return {
threads: data.threads.map(thread => channelFrom(thread, this.client) as ThreadChannel),
members: data.members as GetAPIChannelThreadMemberResult[],
hasMore: data.has_more,
};
}
async listJoinedArchivedPrivate(channelId: string, query?: RESTGetAPIChannelThreadsArchivedQuery) {
const data = await this.client.proxy.channels(channelId).users('@me').threads.archived.private.get({ query });
return {
threads: data.threads.map(thread => channelFrom(thread, this.client) as ThreadChannel),
members: data.members as GetAPIChannelThreadMemberResult[],
hasMore: data.has_more,
};
}
}
export type GetAPIChannelThreadMemberResult = MakeRequired<APIThreadMember, 'id' | 'user_id'>;
type InferWithMemberOnList<T extends RESTGetAPIChannelThreadMembersQuery> = T extends {
with_member: infer B;
}
? B extends true
? Required<APIThreadMember>[]
: GetAPIChannelThreadMemberResult[]
: GetAPIChannelThreadMemberResult[];

View File

@ -455,6 +455,16 @@ export class ThreadChannel extends BaseChannel<
channelId: this.parentId!,
});
async join() {
await this.client.threads.join(this.id);
return this;
}
async leave() {
await this.client.threads.leave(this.id);
return this;
}
setRatelimitPerUser(rate_limit_per_user: number | null | undefined) {
return this.edit({ rate_limit_per_user });
}
@ -506,13 +516,8 @@ export interface NewsChannel extends ObjectToLower<APINewsChannel>, WebhookChann
export class NewsChannel extends BaseChannel<ChannelType.GuildAnnouncement> {
declare type: ChannelType.GuildAnnouncement;
addFollower(webhook_channel_id: string, reason?: string) {
return this.api.channels(this.id).followers.post({
body: {
webhook_channel_id,
},
reason,
});
addFollower(webhookChannelId: string, reason?: string) {
return this.client.guilds.channels.addFollower(this.id, webhookChannelId, reason);
}
}