diff --git a/src/client/websocket/handlers/MESSAGE_ACK.js b/src/client/websocket/handlers/MESSAGE_ACK.js index 2b6fc19..cae8c5b 100644 --- a/src/client/websocket/handlers/MESSAGE_ACK.js +++ b/src/client/websocket/handlers/MESSAGE_ACK.js @@ -1,5 +1,16 @@ 'use strict'; -module.exports = (client, { d: data }) => - // Client.user.messageMentions.delete(data.channel_id); - `${client}:${data}`; +const { Events } = require('../../../util/Constants'); + +module.exports = (client, { d: data }) => { + const channel = client.channels.cache.get(data.channel_id); + /** + * Emitted whenever message is acknowledged (mark read / unread) + * @event Client#messageAck + * @param {TextChannel} channel Channel + * @param {Snowflake} message_id Message ID + * @param {boolean} isRead Whether the message is read + * @param {Object} raw Raw data + */ + client.emit(Events.MESSAGE_ACK, channel, data.message_id, !data.manual, data); +}; diff --git a/src/client/websocket/handlers/index.js b/src/client/websocket/handlers/index.js index 26a15c0..a44d719 100644 --- a/src/client/websocket/handlers/index.js +++ b/src/client/websocket/handlers/index.js @@ -34,6 +34,7 @@ const handlers = Object.fromEntries([ ['CHANNEL_DELETE', require('./CHANNEL_DELETE')], ['CHANNEL_UPDATE', require('./CHANNEL_UPDATE')], ['CHANNEL_PINS_UPDATE', require('./CHANNEL_PINS_UPDATE')], + ['MESSAGE_ACK', require('./MESSAGE_ACK')], ['MESSAGE_CREATE', require('./MESSAGE_CREATE')], ['MESSAGE_DELETE', require('./MESSAGE_DELETE')], ['MESSAGE_UPDATE', require('./MESSAGE_UPDATE')], diff --git a/src/structures/Message.js b/src/structures/Message.js index a66da33..11029d7 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -1014,6 +1014,20 @@ class Message extends Base { }); return true; } + + /** + * Marks the message as read. + * @returns {boolean} + */ + async markRead() { + await this.client.api.channels[this.channelId].messages[this.id].ack.post({ + data: { + token: null, + }, + }); + return true; + } + /** * Click specific button [Suggestion: Dux#2925] * @param {string} buttonID Button ID diff --git a/src/structures/RichPresence.js b/src/structures/RichPresence.js index 5ac89f0..8481bbf 100644 --- a/src/structures/RichPresence.js +++ b/src/structures/RichPresence.js @@ -80,11 +80,11 @@ class CustomStatus { class RichPresence { /** - * @param {Client} client Discord client + * @param {Client} [client] Discord client * @param {RichPresence} [data={}] RichPresence to clone or raw data * @param {boolean} [IPC=false] Whether to use IPC (RPC for Discord Apps) */ - constructor(client, data = {}, IPC = false) { + constructor(client = {}, data = {}, IPC = false) { Object.defineProperty(this, 'client', { value: client }); /** * The activity's name diff --git a/src/util/Constants.js b/src/util/Constants.js index c968eb0..792468f 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -320,6 +320,7 @@ exports.Opcodes = { * * CHANNEL_DELETE: channelDelete * * CHANNEL_UPDATE: channelUpdate * * CHANNEL_PINS_UPDATE: channelPinsUpdate + * * MESSAGE_ACK: messageAck * * MESSAGE_CREATE: messageCreate * * MESSAGE_DELETE: messageDelete * * MESSAGE_UPDATE: messageUpdate @@ -404,6 +405,7 @@ exports.Events = { CHANNEL_DELETE: 'channelDelete', CHANNEL_UPDATE: 'channelUpdate', CHANNEL_PINS_UPDATE: 'channelPinsUpdate', + MESSAGE_ACK: 'messageAck', MESSAGE_CREATE: 'messageCreate', MESSAGE_DELETE: 'messageDelete', MESSAGE_UPDATE: 'messageUpdate', diff --git a/typings/index.d.ts b/typings/index.d.ts index 57554c9..d22b1bf 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1883,6 +1883,7 @@ export class Message extends Base { public inGuild(): this is Message & this; // Added public markUnread(): Promise; + public markRead(): Promise; public clickButton(buttonID: string): Promise; public selectMenu(menuID: string, options: string[]): Promise; public selectMenu(options: string[]): Promise; @@ -4285,6 +4286,7 @@ export interface ClientEvents extends BaseClientEvents { inviteDelete: [invite: Invite]; /** @deprecated Use messageCreate instead */ message: [message: Message]; + messageAck: [channel: TextChannel, message_id: Snowflake, isRead: boolean, raw: Object]; messageCreate: [message: Message]; messageDelete: [message: Message | PartialMessage]; messageReactionRemoveAll: [ @@ -4385,6 +4387,7 @@ export interface ConstantsEvents { CHANNEL_DELETE: 'channelDelete'; CHANNEL_UPDATE: 'channelUpdate'; CHANNEL_PINS_UPDATE: 'channelPinsUpdate'; + MESSAGE_ACK: 'messageAck'; MESSAGE_CREATE: 'messageCreate'; MESSAGE_DELETE: 'messageDelete'; MESSAGE_UPDATE: 'messageUpdate'; @@ -5068,88 +5071,6 @@ export interface ConstantsColors { NOT_QUITE_BLACK: 0x23272a; } -export interface ConstantsEvents { - RATE_LIMIT: 'rateLimit'; - INVALID_REQUEST_WARNING: 'invalidRequestWarning'; - API_RESPONSE: 'apiResponse'; - API_REQUEST: 'apiRequest'; - CLIENT_READY: 'ready'; - APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE: 'applicationCommandAutocompleteResponse'; - /** @deprecated See [this issue](https://github.com/discord/discord-api-docs/issues/3690) for more information. */ - APPLICATION_COMMAND_CREATE: 'applicationCommandCreate'; - /** @deprecated See [this issue](https://github.com/discord/discord-api-docs/issues/3690) for more information. */ - APPLICATION_COMMAND_DELETE: 'applicationCommandDelete'; - /** @deprecated See [this issue](https://github.com/discord/discord-api-docs/issues/3690) for more information. */ - APPLICATION_COMMAND_UPDATE: 'applicationCommandUpdate'; - GUILD_CREATE: 'guildCreate'; - GUILD_DELETE: 'guildDelete'; - GUILD_UPDATE: 'guildUpdate'; - INVITE_CREATE: 'inviteCreate'; - INVITE_DELETE: 'inviteDelete'; - GUILD_UNAVAILABLE: 'guildUnavailable'; - GUILD_MEMBER_ADD: 'guildMemberAdd'; - GUILD_MEMBER_REMOVE: 'guildMemberRemove'; - GUILD_MEMBER_UPDATE: 'guildMemberUpdate'; - GUILD_MEMBER_AVAILABLE: 'guildMemberAvailable'; - GUILD_MEMBERS_CHUNK: 'guildMembersChunk'; - GUILD_INTEGRATIONS_UPDATE: 'guildIntegrationsUpdate'; - GUILD_ROLE_CREATE: 'roleCreate'; - GUILD_ROLE_DELETE: 'roleDelete'; - GUILD_ROLE_UPDATE: 'roleUpdate'; - GUILD_EMOJI_CREATE: 'emojiCreate'; - GUILD_EMOJI_DELETE: 'emojiDelete'; - GUILD_EMOJI_UPDATE: 'emojiUpdate'; - GUILD_BAN_ADD: 'guildBanAdd'; - GUILD_BAN_REMOVE: 'guildBanRemove'; - CHANNEL_CREATE: 'channelCreate'; - CHANNEL_DELETE: 'channelDelete'; - CHANNEL_UPDATE: 'channelUpdate'; - CHANNEL_PINS_UPDATE: 'channelPinsUpdate'; - MESSAGE_CREATE: 'messageCreate'; - MESSAGE_DELETE: 'messageDelete'; - MESSAGE_UPDATE: 'messageUpdate'; - MESSAGE_BULK_DELETE: 'messageDeleteBulk'; - MESSAGE_REACTION_ADD: 'messageReactionAdd'; - MESSAGE_REACTION_REMOVE: 'messageReactionRemove'; - MESSAGE_REACTION_REMOVE_ALL: 'messageReactionRemoveAll'; - MESSAGE_REACTION_REMOVE_EMOJI: 'messageReactionRemoveEmoji'; - THREAD_CREATE: 'threadCreate'; - THREAD_DELETE: 'threadDelete'; - THREAD_UPDATE: 'threadUpdate'; - THREAD_LIST_SYNC: 'threadListSync'; - THREAD_MEMBER_UPDATE: 'threadMemberUpdate'; - THREAD_MEMBERS_UPDATE: 'threadMembersUpdate'; - USER_UPDATE: 'userUpdate'; - PRESENCE_UPDATE: 'presenceUpdate'; - VOICE_SERVER_UPDATE: 'voiceServerUpdate'; - VOICE_STATE_UPDATE: 'voiceStateUpdate'; - TYPING_START: 'typingStart'; - WEBHOOKS_UPDATE: 'webhookUpdate'; - INTERACTION_CREATE: 'interactionCreate'; - ERROR: 'error'; - WARN: 'warn'; - DEBUG: 'debug'; - CACHE_SWEEP: 'cacheSweep'; - SHARD_DISCONNECT: 'shardDisconnect'; - SHARD_ERROR: 'shardError'; - SHARD_RECONNECTING: 'shardReconnecting'; - SHARD_READY: 'shardReady'; - SHARD_RESUME: 'shardResume'; - INVALIDATED: 'invalidated'; - RAW: 'raw'; - STAGE_INSTANCE_CREATE: 'stageInstanceCreate'; - STAGE_INSTANCE_UPDATE: 'stageInstanceUpdate'; - STAGE_INSTANCE_DELETE: 'stageInstanceDelete'; - GUILD_STICKER_CREATE: 'stickerCreate'; - GUILD_STICKER_DELETE: 'stickerDelete'; - GUILD_STICKER_UPDATE: 'stickerUpdate'; - GUILD_SCHEDULED_EVENT_CREATE: 'guildScheduledEventCreate'; - GUILD_SCHEDULED_EVENT_UPDATE: 'guildScheduledEventUpdate'; - GUILD_SCHEDULED_EVENT_DELETE: 'guildScheduledEventDelete'; - GUILD_SCHEDULED_EVENT_USER_ADD: 'guildScheduledEventUserAdd'; - GUILD_SCHEDULED_EVENT_USER_REMOVE: 'guildScheduledEventUserRemove'; -} - export interface ConstantsOpcodes { DISPATCH: 0; HEARTBEAT: 1;