diff --git a/src/gateway/handlers/guildMemberAdd.ts b/src/gateway/handlers/guildMemberAdd.ts index 333dc6d..4524b3f 100644 --- a/src/gateway/handlers/guildMemberAdd.ts +++ b/src/gateway/handlers/guildMemberAdd.ts @@ -1,15 +1,16 @@ import { Gateway, GatewayEventHandler } from '../index.ts' import { Guild } from '../../structures/guild.ts' +import { GuildMemberAddPayload } from "../../../mod.ts" export const guildMemberAdd: GatewayEventHandler = async ( gateway: Gateway, - d: + d: GuildMemberAddPayload ) => { const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) // Weird case, shouldn't happen if (guild === undefined) return - await guild.members.set(d.id, d) - const member = await guild.members.get(d.id) + await guild.members.set(d.user.id, d) + const member = await guild.members.get(d.user.id) gateway.client.emit('guildMemberAdd', member) } \ No newline at end of file diff --git a/src/models/client.ts b/src/models/client.ts index 4fe06e3..56e7949 100644 --- a/src/models/client.ts +++ b/src/models/client.ts @@ -1,124 +1,123 @@ -import { User } from '../structures/user.ts' -import { GatewayIntents } from '../types/gateway.ts' -import { Gateway } from '../gateway/index.ts' -import { RESTManager } from './rest.ts' -import EventEmitter from 'https://deno.land/std@0.74.0/node/events.ts' -import { DefaultCacheAdapter, ICacheAdapter } from './cacheAdapter.ts' -import { UserManager } from '../managers/users.ts' -import { GuildManager } from '../managers/guilds.ts' -import { ChannelsManager } from '../managers/channels.ts' -import { - ActivityGame, - ClientActivity, - ClientPresence -} from '../structures/presence.ts' -import { EmojisManager } from '../managers/emojis.ts' - -/** Some Client Options to modify behaviour */ -export interface ClientOptions { - /** Token of the Bot/User */ - token?: string - /** Gateway Intents */ - intents?: GatewayIntents[] - /** Cache Adapter to use, defaults to Collections one */ - cache?: ICacheAdapter, - /** Force New Session and don't use cached Session (by persistent caching) */ - forceNewSession?: boolean, - /** Startup presence of client */ - presence?: ClientPresence | ClientActivity | ActivityGame - /** Whether it's a bot user or not? Use this if selfbot! */ - bot?: boolean - /** Force all requests to Canary API */ - canary?: boolean - /** Time till which Messages are to be cached, in MS. Default is 3600000 */ - messageCacheLifetime?: number -} - -/** - * Discord Client. - */ -export class Client extends EventEmitter { - /** Gateway object */ - gateway?: Gateway - /** REST Manager - used to make all requests */ - rest: RESTManager = new RESTManager(this) - /** User which Client logs in to, undefined until logs in */ - user?: User - /** WebSocket ping of Client */ - ping = 0 - /** Token of the Bot/User */ - token?: string - /** Cache Adapter */ - cache: ICacheAdapter = new DefaultCacheAdapter() - /** Gateway Intents */ - intents?: GatewayIntents[] - /** Whether to force new session or not */ - forceNewSession?: boolean - /** Time till messages to stay cached, in MS. */ - messageCacheLifetime: number = 3600000 - - users: UserManager = new UserManager(this) - guilds: GuildManager = new GuildManager(this) - channels: ChannelsManager = new ChannelsManager(this) - emojis: EmojisManager = new EmojisManager(this) - - /** Whether this client will login as bot user or not */ - bot: boolean = true - /** Whether the REST Manager will use Canary API or not */ - canary: boolean = false - /** Client's presence. Startup one if set before connecting */ - presence: ClientPresence = new ClientPresence() - - constructor (options: ClientOptions = {}) { - super() - this.token = options.token - this.intents = options.intents - this.forceNewSession = options.forceNewSession - if (options.cache !== undefined) this.cache = options.cache - if (options.presence !== undefined) - this.presence = - options.presence instanceof ClientPresence - ? options.presence - : new ClientPresence(options.presence) - if (options.bot === false) this.bot = false - if (options.canary === true) this.canary = true - if (options.messageCacheLifetime !== undefined) this.messageCacheLifetime = options.messageCacheLifetime - } - - /** Set Cache Adapter */ - setAdapter (adapter: ICacheAdapter): Client { - this.cache = adapter - return this - } - - /** Change Presence of Client */ - setPresence (presence: ClientPresence | ClientActivity | ActivityGame): void { - if (presence instanceof ClientPresence) { - this.presence = presence - } else this.presence = new ClientPresence(presence) - this.gateway?.sendPresence(this.presence.create()) - } - - /** Emit debug event */ - debug (tag: string, msg: string): void { - this.emit('debug', `[${tag}] ${msg}`) - } - - /** - * This function is used for connect to discord. - * @param token Your token. This is required. - * @param intents Gateway intents in array. This is required. - */ - connect (token?: string, intents?: GatewayIntents[]): void { - if (token === undefined && this.token !== undefined) token = this.token - else if (this.token === undefined && token !== undefined) { - this.token = token - } else throw new Error('No Token Provided') - if (intents === undefined && this.intents !== undefined) - intents = this.intents - else if (intents !== undefined && this.intents === undefined) { - this.intents = intents - } else throw new Error('No Gateway Intents were provided') - this.gateway = new Gateway(this, token, intents) - } -} +import { User } from '../structures/user.ts' +import { GatewayIntents } from '../types/gateway.ts' +import { Gateway } from '../gateway/index.ts' +import { RESTManager } from './rest.ts' +import EventEmitter from 'https://deno.land/std@0.74.0/node/events.ts' +import { DefaultCacheAdapter, ICacheAdapter } from './cacheAdapter.ts' +import { UserManager } from '../managers/users.ts' +import { GuildManager } from '../managers/guilds.ts' +import { ChannelsManager } from '../managers/channels.ts' +import { + ClientPresence +} from '../structures/presence.ts' +import { EmojisManager } from '../managers/emojis.ts' +import { ActivityGame, ClientActivity } from "../types/presence.ts" + +/** Some Client Options to modify behaviour */ +export interface ClientOptions { + /** Token of the Bot/User */ + token?: string + /** Gateway Intents */ + intents?: GatewayIntents[] + /** Cache Adapter to use, defaults to Collections one */ + cache?: ICacheAdapter, + /** Force New Session and don't use cached Session (by persistent caching) */ + forceNewSession?: boolean, + /** Startup presence of client */ + presence?: ClientPresence | ClientActivity | ActivityGame + /** Whether it's a bot user or not? Use this if selfbot! */ + bot?: boolean + /** Force all requests to Canary API */ + canary?: boolean + /** Time till which Messages are to be cached, in MS. Default is 3600000 */ + messageCacheLifetime?: number +} + +/** + * Discord Client. + */ +export class Client extends EventEmitter { + /** Gateway object */ + gateway?: Gateway + /** REST Manager - used to make all requests */ + rest: RESTManager = new RESTManager(this) + /** User which Client logs in to, undefined until logs in */ + user?: User + /** WebSocket ping of Client */ + ping = 0 + /** Token of the Bot/User */ + token?: string + /** Cache Adapter */ + cache: ICacheAdapter = new DefaultCacheAdapter() + /** Gateway Intents */ + intents?: GatewayIntents[] + /** Whether to force new session or not */ + forceNewSession?: boolean + /** Time till messages to stay cached, in MS. */ + messageCacheLifetime: number = 3600000 + + users: UserManager = new UserManager(this) + guilds: GuildManager = new GuildManager(this) + channels: ChannelsManager = new ChannelsManager(this) + emojis: EmojisManager = new EmojisManager(this) + + /** Whether this client will login as bot user or not */ + bot: boolean = true + /** Whether the REST Manager will use Canary API or not */ + canary: boolean = false + /** Client's presence. Startup one if set before connecting */ + presence: ClientPresence = new ClientPresence() + + constructor (options: ClientOptions = {}) { + super() + this.token = options.token + this.intents = options.intents + this.forceNewSession = options.forceNewSession + if (options.cache !== undefined) this.cache = options.cache + if (options.presence !== undefined) + this.presence = + options.presence instanceof ClientPresence + ? options.presence + : new ClientPresence(options.presence) + if (options.bot === false) this.bot = false + if (options.canary === true) this.canary = true + if (options.messageCacheLifetime !== undefined) this.messageCacheLifetime = options.messageCacheLifetime + } + + /** Set Cache Adapter */ + setAdapter (adapter: ICacheAdapter): Client { + this.cache = adapter + return this + } + + /** Change Presence of Client */ + setPresence (presence: ClientPresence | ClientActivity | ActivityGame): void { + if (presence instanceof ClientPresence) { + this.presence = presence + } else this.presence = new ClientPresence(presence) + this.gateway?.sendPresence(this.presence.create()) + } + + /** Emit debug event */ + debug (tag: string, msg: string): void { + this.emit('debug', `[${tag}] ${msg}`) + } + + /** + * This function is used for connect to discord. + * @param token Your token. This is required. + * @param intents Gateway intents in array. This is required. + */ + connect (token?: string, intents?: GatewayIntents[]): void { + if (token === undefined && this.token !== undefined) token = this.token + else if (this.token === undefined && token !== undefined) { + this.token = token + } else throw new Error('No Token Provided') + if (intents === undefined && this.intents !== undefined) + intents = this.intents + else if (intents !== undefined && this.intents === undefined) { + this.intents = intents + } else throw new Error('No Gateway Intents were provided') + this.gateway = new Gateway(this, token, intents) + } +} diff --git a/src/structures/textChannel.ts b/src/structures/textChannel.ts index 9ab87dd..26b8f88 100644 --- a/src/structures/textChannel.ts +++ b/src/structures/textChannel.ts @@ -1,143 +1,143 @@ -import { MessagesManager } from "../../mod.ts" -import { Client } from '../models/client.ts' -import { GuildTextChannelPayload, MessageOption, MessageReference, Overwrite, TextChannelPayload } from '../types/channel.ts' -import { CHANNEL_MESSAGE, CHANNEL_MESSAGES } from '../types/endpoint.ts' -import { Channel } from './channel.ts' -import { Embed } from './embed.ts' -import { Guild } from "./guild.ts" -import { Message } from './message.ts' - -type AllMessageOptions = MessageOption | Embed - -export class TextChannel extends Channel { - lastMessageID?: string - lastPinTimestamp?: string - messages: MessagesManager - - constructor(client: Client, data: TextChannelPayload) { - super(client, data) - this.messages = new MessagesManager(this.client, this) - this.lastMessageID = data.last_message_id - this.lastPinTimestamp = data.last_pin_timestamp - } - - protected readFromData(data: TextChannelPayload): void { - super.readFromData(data) - this.lastMessageID = data.last_message_id ?? this.lastMessageID - this.lastPinTimestamp = data.last_pin_timestamp ?? this.lastPinTimestamp - } - - async send(text?: string | AllMessageOptions, option?: AllMessageOptions, reply?: Message): Promise { - if (typeof text === "object") { - option = text - text = undefined - } - if (text === undefined && option === undefined) { - throw new Error('Either text or option is necessary.') - } - if (option instanceof Embed) option = { - embed: option - } - - const payload: any = { - content: text, - embed: option?.embed, - file: option?.file, - tts: option?.tts, - allowed_mentions: option?.allowedMention - } - - if (reply !== undefined) { - const reference: MessageReference = { - message_id: reply.id, - channel_id: reply.channel.id, - guild_id: reply.guild?.id, - } - payload.message_reference = reference - } - - const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), payload) - - const res = new Message(this.client, resp, this, this.client.user as any) - await res.mentions.fromPayload(resp) - return res - } - - async editMessage( - message: Message | string, - text?: string, - option?: MessageOption - ): Promise { - if (text === undefined && option === undefined) { - throw new Error('Either text or option is necessary.') - } - - if (this.client.user === undefined) { - throw new Error('Client user has not initialized.') - } - - const newMsg = await this.client.rest.patch( - CHANNEL_MESSAGE( - this.id, - typeof message === 'string' ? message : message.id - ), - { - content: text, - embed: option?.embed.toJSON(), - file: option?.file, - tts: option?.tts, - allowed_mentions: option?.allowedMention - } - ) - - const res = new Message(this.client, newMsg, this, this.client.user) - await res.mentions.fromPayload(newMsg) - return res - } -} - -export class GuildTextChannel extends TextChannel { - guildID: string - name: string - position: number - permissionOverwrites: Overwrite[] - nsfw: boolean - parentID?: string - rateLimit: number - topic?: string - guild: Guild - - get mention(): string { - return `<#${this.id}>` - } - - toString(): string { - return this.mention - } - - constructor(client: Client, data: GuildTextChannelPayload, guild: Guild) { - super(client, data) - this.guildID = data.guild_id - this.name = data.name - this.guild = guild - this.position = data.position - this.permissionOverwrites = data.permission_overwrites - this.nsfw = data.nsfw - this.parentID = data.parent_id - this.topic = data.topic - this.rateLimit = data.rate_limit_per_user - } - - protected readFromData(data: GuildTextChannelPayload): void { - super.readFromData(data) - this.guildID = data.guild_id ?? this.guildID - this.name = data.name ?? this.name - this.position = data.position ?? this.position - this.permissionOverwrites = - data.permission_overwrites ?? this.permissionOverwrites - this.nsfw = data.nsfw ?? this.nsfw - this.parentID = data.parent_id ?? this.parentID - this.topic = data.topic ?? this.topic - this.rateLimit = data.rate_limit_per_user ?? this.rateLimit - } -} +import { MessagesManager } from "../../mod.ts" +import { Client } from '../models/client.ts' +import { GuildTextChannelPayload, MessageOption, MessageReference, Overwrite, TextChannelPayload } from '../types/channel.ts' +import { CHANNEL_MESSAGE, CHANNEL_MESSAGES } from '../types/endpoint.ts' +import { Channel } from './channel.ts' +import { Embed } from './embed.ts' +import { Guild } from "./guild.ts" +import { Message } from './message.ts' + +type AllMessageOptions = MessageOption | Embed + +export class TextChannel extends Channel { + lastMessageID?: string + lastPinTimestamp?: string + messages: MessagesManager + + constructor(client: Client, data: TextChannelPayload) { + super(client, data) + this.messages = new MessagesManager(this.client, this) + this.lastMessageID = data.last_message_id + this.lastPinTimestamp = data.last_pin_timestamp + } + + protected readFromData(data: TextChannelPayload): void { + super.readFromData(data) + this.lastMessageID = data.last_message_id ?? this.lastMessageID + this.lastPinTimestamp = data.last_pin_timestamp ?? this.lastPinTimestamp + } + + async send(text?: string | AllMessageOptions, option?: AllMessageOptions, reply?: Message): Promise { + if (typeof text === "object") { + option = text + text = undefined + } + if (text === undefined && option === undefined) { + throw new Error('Either text or option is necessary.') + } + if (option instanceof Embed) option = { + embed: option + } + + const payload: any = { + content: text, + embed: option?.embed, + file: option?.file, + tts: option?.tts, + allowed_mentions: option?.allowedMention + } + + if (reply !== undefined) { + const reference: MessageReference = { + message_id: reply.id, + channel_id: reply.channel.id, + guild_id: reply.guild?.id, + } + payload.message_reference = reference + } + + const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), payload) + + const res = new Message(this.client, resp, this, this.client.user as any) + await res.mentions.fromPayload(resp) + return res + } + + async editMessage( + message: Message | string, + text?: string, + option?: MessageOption + ): Promise { + if (text === undefined && option === undefined) { + throw new Error('Either text or option is necessary.') + } + + if (this.client.user === undefined) { + throw new Error('Client user has not initialized.') + } + + const newMsg = await this.client.rest.patch( + CHANNEL_MESSAGE( + this.id, + typeof message === 'string' ? message : message.id + ), + { + content: text, + embed: option?.embed !== undefined ? option.embed.toJSON() : undefined, + file: option?.file, + tts: option?.tts, + allowed_mentions: option?.allowedMention + } + ) + + const res = new Message(this.client, newMsg, this, this.client.user) + await res.mentions.fromPayload(newMsg) + return res + } +} + +export class GuildTextChannel extends TextChannel { + guildID: string + name: string + position: number + permissionOverwrites: Overwrite[] + nsfw: boolean + parentID?: string + rateLimit: number + topic?: string + guild: Guild + + get mention(): string { + return `<#${this.id}>` + } + + toString(): string { + return this.mention + } + + constructor(client: Client, data: GuildTextChannelPayload, guild: Guild) { + super(client, data) + this.guildID = data.guild_id + this.name = data.name + this.guild = guild + this.position = data.position + this.permissionOverwrites = data.permission_overwrites + this.nsfw = data.nsfw + this.parentID = data.parent_id + this.topic = data.topic + this.rateLimit = data.rate_limit_per_user + } + + protected readFromData(data: GuildTextChannelPayload): void { + super.readFromData(data) + this.guildID = data.guild_id ?? this.guildID + this.name = data.name ?? this.name + this.position = data.position ?? this.position + this.permissionOverwrites = + data.permission_overwrites ?? this.permissionOverwrites + this.nsfw = data.nsfw ?? this.nsfw + this.parentID = data.parent_id ?? this.parentID + this.topic = data.topic ?? this.topic + this.rateLimit = data.rate_limit_per_user ?? this.rateLimit + } +} diff --git a/src/types/gateway.ts b/src/types/gateway.ts index 59c2092..723ad22 100644 --- a/src/types/gateway.ts +++ b/src/types/gateway.ts @@ -191,7 +191,7 @@ export interface GuildIntegrationsUpdatePayload { guild_id: string } -export interface GuildMemberAddPayload { +export interface GuildMemberAddPayload extends MemberPayload { guild_id: string }