mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
Merge branch 'channels-refactor'
This commit is contained in:
commit
c993699aab
@ -75,7 +75,7 @@ export abstract class BaseChannel implements Model {
|
||||
type: ChannelTypes;
|
||||
|
||||
/** If the channel is a TextChannel */
|
||||
isText(): this is TextChannel {
|
||||
isText(): this is TextChannel.T {
|
||||
return textBasedChannels.includes(this.type);
|
||||
}
|
||||
|
||||
@ -216,82 +216,73 @@ export type TextBasedChannels =
|
||||
|
||||
/**
|
||||
* Represents a text channel.
|
||||
* tbis trait can be implemented by using implements TextChannel.T
|
||||
*/
|
||||
export class TextChannel {
|
||||
constructor(session: Session, data: DiscordChannel) {
|
||||
this.session = session;
|
||||
this.id = data.id;
|
||||
this.name = data.name;
|
||||
this.type = data.type as number;
|
||||
this.rateLimitPerUser = data.rate_limit_per_user ?? 0;
|
||||
this.nsfw = !!data.nsfw ?? false;
|
||||
export namespace TextChannel {
|
||||
export interface T {
|
||||
/** The session that instantiated the channel */
|
||||
readonly session: Session;
|
||||
|
||||
if (data.last_message_id) {
|
||||
this.lastMessageId = data.last_message_id;
|
||||
}
|
||||
/** id's refers to the identification of the channel */
|
||||
readonly id: Snowflake;
|
||||
|
||||
if (data.last_pin_timestamp) {
|
||||
this.lastPinTimestamp = data.last_pin_timestamp;
|
||||
}
|
||||
}
|
||||
/** Current channel name */
|
||||
name?: string;
|
||||
|
||||
/** The session that instantiated the channel */
|
||||
readonly session: Session;
|
||||
/** The type of the channel */
|
||||
type: TextBasedChannels;
|
||||
|
||||
/** id's refers to the identification of the channel */
|
||||
readonly id: Snowflake;
|
||||
/** The id of the last message sent in this channel (or thread for GUILD_FORUM channels) (may not point to an existing or valid message or thread) */
|
||||
lastMessageId?: Snowflake;
|
||||
|
||||
/** Current channel name */
|
||||
name?: string;
|
||||
/** When the last pinned message was pinned. This may be undefined in events such as GUILD_CREATE when a message is not pinned. */
|
||||
lastPinTimestamp?: string;
|
||||
|
||||
/** The type of the channel */
|
||||
type: TextBasedChannels;
|
||||
/** Amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission manage_messages or manage_channel, are unaffected */
|
||||
// TODO: move this
|
||||
// rateLimitPerUser: number;
|
||||
|
||||
/** The id of the last message sent in this channel (or thread for GUILD_FORUM channels) (may not point to an existing or valid message or thread) */
|
||||
lastMessageId?: Snowflake;
|
||||
/** If the channel is NSFW (Not-Safe-For-Work content) */
|
||||
// TODO: move this
|
||||
// nsfw: boolean;
|
||||
|
||||
/** When the last pinned message was pinned. This may be undefined in events such as GUILD_CREATE when a message is not pinned. */
|
||||
lastPinTimestamp?: string;
|
||||
// methods to be implemented
|
||||
|
||||
/** Amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission manage_messages or manage_channel, are unaffected */
|
||||
rateLimitPerUser: number;
|
||||
|
||||
/** If the channel is NSFW (Not-Safe-For-Work content) */
|
||||
nsfw: boolean;
|
||||
|
||||
/**
|
||||
* Mixin
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
static applyTo(klass: Function, ignore: (keyof TextChannel)[] = []): void {
|
||||
const methods: (keyof TextChannel)[] = [
|
||||
'fetchPins',
|
||||
'createInvite',
|
||||
'fetchMessages',
|
||||
'sendTyping',
|
||||
'pinMessage',
|
||||
'unpinMessage',
|
||||
'addReaction',
|
||||
'removeReaction',
|
||||
'nukeReactions',
|
||||
'fetchPins',
|
||||
'sendMessage',
|
||||
'editMessage',
|
||||
'createWebhook',
|
||||
];
|
||||
|
||||
for (const method of methods) {
|
||||
if (ignore.includes(method)) { continue; }
|
||||
|
||||
klass.prototype[method] = TextChannel.prototype[method];
|
||||
}
|
||||
fetchPins(): Promise<Message[]>;
|
||||
createInvite(options?: DiscordInviteOptions): Promise<Invite>;
|
||||
fetchMessages(options?: GetMessagesOptions): Promise<Message[]>;
|
||||
sendTyping(): Promise<void>;
|
||||
pinMessage(messageId: Snowflake): Promise<void>;
|
||||
unpinMessage(messageId: Snowflake): Promise<void>;
|
||||
addReaction(
|
||||
messageId: Snowflake,
|
||||
reaction: EmojiResolvable,
|
||||
): Promise<void>;
|
||||
removeReaction(
|
||||
messageId: Snowflake,
|
||||
reaction: EmojiResolvable,
|
||||
options: { userId: Snowflake },
|
||||
): Promise<void>;
|
||||
removeReactionEmoji(
|
||||
messageId: Snowflake,
|
||||
reaction: EmojiResolvable,
|
||||
): Promise<void>;
|
||||
nukeReactions(messageId: Snowflake): Promise<void>;
|
||||
fetchReactions(
|
||||
messageId: Snowflake,
|
||||
reaction: EmojiResolvable,
|
||||
options: GetReactions,
|
||||
): Promise<User[]>;
|
||||
sendMessage(options: CreateMessage): Promise<Message>;
|
||||
editMessage(messageId: Snowflake, options: EditMessage): Promise<Message>;
|
||||
createWebhook(options: CreateWebhook): Promise<Webhook>;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetchPins makes an asynchronous request and gets the current channel pins.
|
||||
* @returns A promise that resolves with an array of Message objects.
|
||||
*/
|
||||
async fetchPins(): Promise<Message[] | []> {
|
||||
export async function fetchPins(this: T): Promise<Message[]> {
|
||||
const messages = await this.session.rest.get<DiscordMessage[]>(
|
||||
CHANNEL_PINS(this.id),
|
||||
);
|
||||
@ -304,7 +295,7 @@ export class TextChannel {
|
||||
* @param options - The options to create the invitation
|
||||
* @returns The created invite
|
||||
*/
|
||||
async createInvite(options?: DiscordInviteOptions): Promise<Invite> {
|
||||
export async function createInvite(this: T, options?: DiscordInviteOptions): Promise<Invite> {
|
||||
const invite = await this.session.rest.post<DiscordInvite>(
|
||||
CHANNEL_INVITES(this.id),
|
||||
options
|
||||
@ -328,7 +319,7 @@ export class TextChannel {
|
||||
* @param options - The options to get the messages
|
||||
* @returns The messages
|
||||
*/
|
||||
async fetchMessages(options?: GetMessagesOptions): Promise<Message[] | []> {
|
||||
export async function fetchMessages(this: T, options?: GetMessagesOptions): Promise<Message[]> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
|
||||
if (options?.limit! > 100) { throw Error('Values must be between 0-100'); }
|
||||
const messages = await this.session.rest.get<DiscordMessage[]>(
|
||||
@ -339,7 +330,7 @@ export class TextChannel {
|
||||
}
|
||||
|
||||
/** sendTyping sends a typing POST request */
|
||||
async sendTyping(): Promise<void> {
|
||||
export async function sendTyping(this: T): Promise<void> {
|
||||
await this.session.rest.post<undefined>(CHANNEL_TYPING(this.id), {});
|
||||
}
|
||||
|
||||
@ -349,7 +340,7 @@ export class TextChannel {
|
||||
* @param messageId - The id of the message to pin
|
||||
* @returns The promise that resolves when the request is complete
|
||||
*/
|
||||
async pinMessage(messageId: Snowflake): Promise<void> {
|
||||
export async function pinMessage(this: T, messageId: Snowflake): Promise<void> {
|
||||
await Message.prototype.pin.call({ id: messageId, channelId: this.id, session: this.session });
|
||||
}
|
||||
|
||||
@ -359,7 +350,7 @@ export class TextChannel {
|
||||
* @param messageId - The id of the message to unpin
|
||||
* @returns The promise of the request
|
||||
*/
|
||||
async unpinMessage(messageId: Snowflake): Promise<void> {
|
||||
export async function unpinMessage(this: T, messageId: Snowflake): Promise<void> {
|
||||
await Message.prototype.unpin.call({ id: messageId, channelId: this.id, session: this.session });
|
||||
}
|
||||
|
||||
@ -370,7 +361,11 @@ export class TextChannel {
|
||||
* @param reaction - The reaction to add
|
||||
* @returns The promise of the request
|
||||
*/
|
||||
async addReaction(messageId: Snowflake, reaction: EmojiResolvable): Promise<void> {
|
||||
export async function addReaction(
|
||||
this: T,
|
||||
messageId: Snowflake,
|
||||
reaction: EmojiResolvable,
|
||||
): Promise<void> {
|
||||
await Message.prototype.addReaction.call(
|
||||
{ channelId: this.id, id: messageId, session: this.session },
|
||||
reaction,
|
||||
@ -384,7 +379,8 @@ export class TextChannel {
|
||||
* @param reaction - The reaction to remove
|
||||
* @param options - The user to remove the reaction from
|
||||
*/
|
||||
async removeReaction(
|
||||
export async function removeReaction(
|
||||
this: T,
|
||||
messageId: Snowflake,
|
||||
reaction: EmojiResolvable,
|
||||
options?: { userId: Snowflake },
|
||||
@ -401,7 +397,11 @@ export class TextChannel {
|
||||
* Same as Message.removeReactionEmoji().
|
||||
* @param messageId - The message id to remove the reaction from.
|
||||
*/
|
||||
async removeReactionEmoji(messageId: Snowflake, reaction: EmojiResolvable): Promise<void> {
|
||||
export async function removeReactionEmoji(
|
||||
this: T,
|
||||
messageId: Snowflake,
|
||||
reaction: EmojiResolvable,
|
||||
): Promise<void> {
|
||||
await Message.prototype.removeReactionEmoji.call(
|
||||
{ channelId: this.id, id: messageId, session: this.session },
|
||||
reaction,
|
||||
@ -413,7 +413,7 @@ export class TextChannel {
|
||||
* @param messageId The message id to nuke reactions from.
|
||||
* @returns A promise that resolves when the reactions are nuked.
|
||||
*/
|
||||
async nukeReactions(messageId: Snowflake): Promise<void> {
|
||||
export async function nukeReactions(this: T, messageId: Snowflake): Promise<void> {
|
||||
await Message.prototype.nukeReactions.call({ channelId: this.id, id: messageId });
|
||||
}
|
||||
|
||||
@ -425,7 +425,8 @@ export class TextChannel {
|
||||
* @param options - The options to get the reactions with.
|
||||
* @returns The users who reacted with this emoji on the message.
|
||||
*/
|
||||
async fetchReactions(
|
||||
export async function fetchReactions(
|
||||
this: T,
|
||||
messageId: Snowflake,
|
||||
reaction: EmojiResolvable,
|
||||
options?: GetReactions,
|
||||
@ -445,8 +446,13 @@ export class TextChannel {
|
||||
* @param options - Options for a new message.
|
||||
* @returns The sent message.
|
||||
*/
|
||||
sendMessage(options: CreateMessage): Promise<Message> {
|
||||
return Message.prototype.reply.call({ channelId: this.id, session: this.session }, options);
|
||||
export async function sendMessage(this: T, options: CreateMessage): Promise<Message> {
|
||||
const message = await Message.prototype.reply.call({
|
||||
channelId: this.id,
|
||||
session: this.session,
|
||||
}, options);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -456,8 +462,18 @@ export class TextChannel {
|
||||
* @param options - Options for edit a message.
|
||||
* @returns The edited message.
|
||||
*/
|
||||
editMessage(messageId: Snowflake, options: EditMessage): Promise<Message> {
|
||||
return Message.prototype.edit.call({ channelId: this.id, id: messageId, session: this.session }, options);
|
||||
export async function editMessage(
|
||||
this: T,
|
||||
messageId: Snowflake,
|
||||
options: EditMessage,
|
||||
): Promise<Message> {
|
||||
const message = await Message.prototype.edit.call({
|
||||
channelId: this.id,
|
||||
id: messageId,
|
||||
session: this.session,
|
||||
}, options);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -465,7 +481,7 @@ export class TextChannel {
|
||||
* @param options - Options for a new webhook.
|
||||
* @returns The created webhook.
|
||||
*/
|
||||
async createWebhook(options: CreateWebhook): Promise<Webhook> {
|
||||
export async function createWebhook(this: T, options: CreateWebhook): Promise<Webhook> {
|
||||
const webhook = await this.session.rest.post<DiscordWebhook>(
|
||||
CHANNEL_WEBHOOKS(this.id),
|
||||
{
|
||||
@ -577,14 +593,19 @@ export class GuildChannel extends BaseChannel implements Model {
|
||||
|
||||
/** Channel type. */
|
||||
override type: Exclude<ChannelTypes, ChannelTypes.DM | ChannelTypes.GroupDm>;
|
||||
|
||||
/** Guild id. */
|
||||
guildId: Snowflake;
|
||||
|
||||
/** Channel topic */
|
||||
topic?: string;
|
||||
|
||||
/** Sorting position of the channel */
|
||||
position?: number;
|
||||
|
||||
/** Id of the parent category for a channel (each parent category can contain up to 50 channels). */
|
||||
parentId?: Snowflake;
|
||||
|
||||
/** Explicit permission overwrites for members and roles */
|
||||
permissionOverwrites: PermissionsOverwrites[];
|
||||
|
||||
@ -734,7 +755,7 @@ export interface UpdateVoiceState {
|
||||
selfDeaf: boolean;
|
||||
}
|
||||
|
||||
export abstract class BaseVoiceChannel extends GuildChannel {
|
||||
export abstract class BaseVoiceChannel extends GuildChannel implements Model {
|
||||
constructor(session: Session, data: DiscordChannel, guildId: Snowflake) {
|
||||
super(session, data, guildId);
|
||||
this.bitRate = data.bitrate;
|
||||
@ -760,10 +781,21 @@ export abstract class BaseVoiceChannel extends GuildChannel {
|
||||
}
|
||||
|
||||
/** DMChannel */
|
||||
export class DMChannel extends BaseChannel implements Model {
|
||||
export class DMChannel extends BaseChannel implements Model, TextChannel.T {
|
||||
constructor(session: Session, data: DiscordChannel) {
|
||||
super(session, data);
|
||||
|
||||
this.name = data.name;
|
||||
this.type = data.type as number;
|
||||
|
||||
if (data.last_message_id) {
|
||||
this.lastMessageId = data.last_message_id;
|
||||
}
|
||||
|
||||
if (data.last_pin_timestamp) {
|
||||
this.lastPinTimestamp = data.last_pin_timestamp;
|
||||
}
|
||||
|
||||
if (data.owner_id && data.recipients) {
|
||||
this.user = new User(session, data.recipients.find(user => user.id === data.owner_id)!);
|
||||
} else {
|
||||
@ -784,11 +816,16 @@ export class DMChannel extends BaseChannel implements Model {
|
||||
override type: ChannelTypes.DM | ChannelTypes.GroupDm;
|
||||
/** Onwer of the dm channel. */
|
||||
user: User;
|
||||
|
||||
/** If the channel is a DM Group it's has multiple users. */
|
||||
group?: User[];
|
||||
|
||||
/** Last message id. */
|
||||
lastMessageId?: Snowflake;
|
||||
|
||||
/** When the last pinned message was pinned. This may be undefined in events such as GUILD_CREATE when a message is not pinned. */
|
||||
lastPinTimestamp?: string;
|
||||
|
||||
async close(): Promise<DMChannel> {
|
||||
const channel = await this.session.rest.delete<DiscordChannel>(CHANNEL(this.id), {});
|
||||
|
||||
@ -802,12 +839,12 @@ export class DMChannel extends BaseChannel implements Model {
|
||||
}
|
||||
}
|
||||
|
||||
export interface DMChannel extends Omit<TextChannel, 'type'>, Omit<BaseChannel, 'type'> { }
|
||||
Object.assign(DMChannel.prototype, TextChannel);
|
||||
|
||||
TextChannel.applyTo(DMChannel);
|
||||
export interface DMChannel extends BaseChannel, TextChannel.T {}
|
||||
|
||||
/** VoiceChannel */
|
||||
export class VoiceChannel extends BaseVoiceChannel {
|
||||
export class VoiceChannel extends BaseVoiceChannel implements Model, TextChannel.T {
|
||||
constructor(session: Session, data: DiscordChannel, guildId: Snowflake) {
|
||||
super(session, data, guildId);
|
||||
this.type = data.type as number;
|
||||
@ -816,12 +853,12 @@ export class VoiceChannel extends BaseVoiceChannel {
|
||||
override type: ChannelTypes.GuildVoice;
|
||||
}
|
||||
|
||||
export interface VoiceChannel extends TextChannel, BaseVoiceChannel { }
|
||||
Object.assign(VoiceChannel.prototype, TextChannel);
|
||||
|
||||
TextChannel.applyTo(VoiceChannel);
|
||||
export interface VoiceChannel extends BaseVoiceChannel, TextChannel.T { }
|
||||
|
||||
/** NewsChannel */
|
||||
export class NewsChannel extends GuildChannel {
|
||||
export class NewsChannel extends GuildChannel implements Model, TextChannel.T {
|
||||
constructor(session: Session, data: DiscordChannel, guildId: Snowflake) {
|
||||
super(session, data, guildId);
|
||||
this.type = data.type as ChannelTypes.GuildNews;
|
||||
@ -840,9 +877,9 @@ export class NewsChannel extends GuildChannel {
|
||||
}
|
||||
}
|
||||
|
||||
TextChannel.applyTo(NewsChannel);
|
||||
Object.assign(NewsChannel.prototype, TextChannel);
|
||||
|
||||
export interface NewsChannel extends TextChannel, GuildChannel { }
|
||||
export interface NewsChannel extends GuildChannel, TextChannel.T { }
|
||||
|
||||
/** StageChannel */
|
||||
export class StageChannel extends BaseVoiceChannel {
|
||||
@ -857,7 +894,7 @@ export class StageChannel extends BaseVoiceChannel {
|
||||
}
|
||||
|
||||
/** ThreadChannel */
|
||||
export class ThreadChannel extends GuildChannel implements Model {
|
||||
export class ThreadChannel extends GuildChannel implements Model, TextChannel.T {
|
||||
constructor(session: Session, data: DiscordChannel, guildId: Snowflake) {
|
||||
super(session, data, guildId);
|
||||
this.type = data.type as number;
|
||||
@ -924,9 +961,9 @@ export class ThreadChannel extends GuildChannel implements Model {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ThreadChannel extends Omit<GuildChannel, 'type'>, Omit<TextChannel, 'type'> { }
|
||||
Object.assign(ThreadChannel.prototype, TextChannel);
|
||||
|
||||
TextChannel.applyTo(ThreadChannel);
|
||||
export interface ThreadChannel extends GuildChannel, TextChannel.T { }
|
||||
|
||||
/** ForumChannel */
|
||||
export class ForumChannel extends GuildChannel {
|
||||
@ -996,14 +1033,14 @@ export class GuildTextChannel extends GuildChannel {
|
||||
override type: ChannelTypes.GuildText;
|
||||
}
|
||||
|
||||
export interface GuildTextChannel extends GuildChannel, TextChannel { }
|
||||
Object.assign(GuildTextChannel.prototype, TextChannel);
|
||||
|
||||
TextChannel.applyTo(GuildTextChannel);
|
||||
export interface GuildTextChannel extends GuildChannel, TextChannel.T { }
|
||||
|
||||
/** ChannelFactory */
|
||||
export type Channel =
|
||||
| GuildTextChannel
|
||||
| TextChannel
|
||||
| TextChannel.T
|
||||
| VoiceChannel
|
||||
| DMChannel
|
||||
| NewsChannel
|
||||
@ -1077,7 +1114,8 @@ export class ChannelFactory {
|
||||
return new CategoryChannel(session, channel);
|
||||
default:
|
||||
if (textBasedChannels.includes(channel.type)) {
|
||||
return new TextChannel(session, channel);
|
||||
// BLACK MAGIC DO NOT EDIT
|
||||
return Object.assign(Object.create(TextChannel), { session, channel }) as TextChannel.T;
|
||||
}
|
||||
return null as any;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user