From 0873f9a4c3a817ce9cf3821f713a871bc3902eb3 Mon Sep 17 00:00:00 2001 From: Vlad Frangu Date: Sun, 29 Sep 2024 14:20:02 +0300 Subject: [PATCH 1/3] chore(discord.js): release discord.js@14.16.3 (#10522) --- packages/discord.js/CHANGELOG.md | 11 +++++++++++ packages/discord.js/package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/discord.js/CHANGELOG.md b/packages/discord.js/CHANGELOG.md index f435d2fee4c96..9225e4601fc88 100644 --- a/packages/discord.js/CHANGELOG.md +++ b/packages/discord.js/CHANGELOG.md @@ -2,6 +2,17 @@ All notable changes to this project will be documented in this file. +# [14.16.3](https://github.com/discordjs/discord.js/compare/14.16.2...14.16.3) - (2024-09-29) + +## Bug Fixes + +- **BaseInteraction:** Add missing props (#10517) ([6c77fee](https://github.com/discordjs/discord.js/commit/6c77fee41b1aabc243bff623debd157a4c7fad6a)) by @monbrey +- `GuildChannel#guildId` not being patched to `undefined` (#10505) ([2adee06](https://github.com/discordjs/discord.js/commit/2adee06b6e92b7854ebb1c2bfd04940aab68dd10)) by @Qjuh + +## Typings + +- **MessageEditOptions:** Omit `poll` (#10509) ([665bf14](https://github.com/discordjs/discord.js/commit/665bf1486aec62e9528f5f7b5a6910ae6b5a6c9c)) by @TAEMBO + # [14.16.2](https://github.com/discordjs/discord.js/compare/14.16.1...14.16.2) - (2024-09-12) ## Bug Fixes diff --git a/packages/discord.js/package.json b/packages/discord.js/package.json index 6995478375256..22e27f87dd426 100644 --- a/packages/discord.js/package.json +++ b/packages/discord.js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "discord.js", - "version": "14.16.2", + "version": "14.16.3", "description": "A powerful library for interacting with the Discord API", "scripts": { "test": "pnpm run docs:test && pnpm run test:typescript", From e1012cc54a7b28a99c10d11d5ae899bdc7f6b9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=86MB=C3=98?= <69138346+TAEMBO@users.noreply.github.com> Date: Sun, 29 Sep 2024 04:35:40 -0700 Subject: [PATCH 2/3] feat: message forwarding (#10464) * feat: message forwarding * fix: redundant usage * feat: add additional snapshot fields * refactor: use collection to store snapshots --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/discord.js/src/structures/Message.js | 25 +++++++++++++++++++ packages/discord.js/src/util/APITypes.js | 5 ++++ packages/discord.js/typings/index.d.ts | 23 +++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/packages/discord.js/src/structures/Message.js b/packages/discord.js/src/structures/Message.js index 8e7ee42f79fb9..642524f0b6b7f 100644 --- a/packages/discord.js/src/structures/Message.js +++ b/packages/discord.js/src/structures/Message.js @@ -364,6 +364,7 @@ class Message extends Base { * @property {Snowflake} channelId The channel id that was referenced * @property {Snowflake|undefined} guildId The guild id that was referenced * @property {Snowflake|undefined} messageId The message id that was referenced + * @property {MessageReferenceType} type The type of message reference */ if ('message_reference' in data) { @@ -375,6 +376,7 @@ class Message extends Base { channelId: data.message_reference.channel_id, guildId: data.message_reference.guild_id, messageId: data.message_reference.message_id, + type: data.message_reference.type, }; } else { this.reference ??= null; @@ -448,6 +450,29 @@ class Message extends Base { this.poll ??= null; } + if (data.message_snapshots) { + /** + * The message associated with the message reference + * @type {Collection} + */ + this.messageSnapshots = data.message_snapshots.reduce((coll, snapshot) => { + const channel = this.client.channels.resolve(this.reference.channelId); + const snapshotData = { + ...snapshot.message, + id: this.reference.messageId, + channel_id: this.reference.channelId, + guild_id: this.reference.guildId, + }; + + return coll.set( + this.reference.messageId, + channel ? channel.messages._add(snapshotData) : new this.constructor(this.client, snapshotData), + ); + }, new Collection()); + } else { + this.messageSnapshots ??= new Collection(); + } + /** * A call associated with a message * @typedef {Object} MessageCall diff --git a/packages/discord.js/src/util/APITypes.js b/packages/discord.js/src/util/APITypes.js index 89e3827eeb953..42b2ddae09432 100644 --- a/packages/discord.js/src/util/APITypes.js +++ b/packages/discord.js/src/util/APITypes.js @@ -455,6 +455,11 @@ * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageActivityType} */ +/** + * @external MessageReferenceType + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageReferenceType} + */ + /** * @external MessageType * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageType} diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 25eaab5839ed6..f29e646f7c94a 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -185,6 +185,7 @@ import { InviteType, ReactionType, APIAuthorizingIntegrationOwnersMap, + MessageReferenceType, } from 'discord-api-types/v10'; import { ChildProcess } from 'node:child_process'; import { EventEmitter } from 'node:events'; @@ -2185,6 +2186,7 @@ export class Message extends Base { public webhookId: Snowflake | null; public flags: Readonly; public reference: MessageReference | null; + public messageSnapshots: Collection; public awaitMessageComponent( options?: AwaitMessageCollectorOptionsParams, ): Promise[ComponentType]>; @@ -6442,6 +6444,26 @@ export interface MessageMentionOptions { export type MessageMentionTypes = 'roles' | 'users' | 'everyone'; +export interface MessageSnapshot + extends Partialize< + Message, + null, + Exclude< + keyof Message, + | 'attachments' + | 'client' + | 'components' + | 'content' + | 'createdTimestamp' + | 'editedTimestamp' + | 'embeds' + | 'flags' + | 'mentions' + | 'stickers' + | 'type' + > + > {} + export interface BaseMessageOptions { content?: string; embeds?: readonly (JSONEncodable | APIEmbed)[]; @@ -6497,6 +6519,7 @@ export interface MessageReference { channelId: Snowflake; guildId: Snowflake | undefined; messageId: Snowflake | undefined; + type: MessageReferenceType; } export type MessageResolvable = Message | Snowflake; From 9aa3b635ef2ed6d6bb17af2422ef1cf7bbe16ab5 Mon Sep 17 00:00:00 2001 From: Almeida Date: Sun, 29 Sep 2024 19:41:57 +0100 Subject: [PATCH 3/3] feat: recurring scheduled events (#10447) * feat: recurring scheduled events * fix: nullable on patch * docs: remove unnecessary parenthesis Co-authored-by: Vlad Frangu --------- Co-authored-by: Vlad Frangu --- .../managers/GuildScheduledEventManager.js | 24 +++++++++ .../src/structures/GuildScheduledEvent.js | 50 +++++++++++++++++++ packages/discord.js/src/util/APITypes.js | 20 ++++++++ packages/discord.js/src/util/Transformers.js | 29 ++++++++++- packages/discord.js/test/random.js | 5 +- packages/discord.js/typings/index.d.ts | 41 ++++++++++++++- packages/discord.js/typings/index.test-d.ts | 4 ++ 7 files changed, 169 insertions(+), 4 deletions(-) diff --git a/packages/discord.js/src/managers/GuildScheduledEventManager.js b/packages/discord.js/src/managers/GuildScheduledEventManager.js index a0d0c8375e723..383875d70002e 100644 --- a/packages/discord.js/src/managers/GuildScheduledEventManager.js +++ b/packages/discord.js/src/managers/GuildScheduledEventManager.js @@ -7,6 +7,7 @@ const CachedManager = require('./CachedManager'); const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../errors'); const { GuildScheduledEvent } = require('../structures/GuildScheduledEvent'); const { resolveImage } = require('../util/DataResolver'); +const { _transformGuildScheduledEventRecurrenceRule } = require('../util/Transformers'); /** * Manages API methods for GuildScheduledEvents and stores their cache. @@ -36,6 +37,21 @@ class GuildScheduledEventManager extends CachedManager { * @typedef {Snowflake|GuildScheduledEvent} GuildScheduledEventResolvable */ + /** + * Options for setting a recurrence rule for a guild scheduled event. + * @typedef {Object} GuildScheduledEventRecurrenceRuleOptions + * @property {DateResolvable} startAt The time the recurrence rule interval starts at + * @property {?DateResolvable} endAt The time the recurrence rule interval ends at + * @property {GuildScheduledEventRecurrenceRuleFrequency} frequency How often the event occurs + * @property {number} interval The spacing between the events + * @property {?GuildScheduledEventRecurrenceRuleWeekday[]} byWeekday The days within a week to recur on + * @property {?GuildScheduledEventRecurrenceRuleNWeekday[]} byNWeekday The days within a week to recur on + * @property {?GuildScheduledEventRecurrenceRuleMonth[]} byMonth The months to recur on + * @property {?number[]} byMonthDay The days within a month to recur on + * @property {?number[]} byYearDay The days within a year to recur on + * @property {?number} count The total amount of times the event is allowed to recur before stopping + */ + /** * Options used to create a guild scheduled event. * @typedef {Object} GuildScheduledEventCreateOptions @@ -54,6 +70,8 @@ class GuildScheduledEventManager extends CachedManager { * This is required if `entityType` is {@link GuildScheduledEventEntityType.External} * @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event * @property {string} [reason] The reason for creating the guild scheduled event + * @property {GuildScheduledEventRecurrenceRuleOptions} [recurrenceRule] + * The recurrence rule of the guild scheduled event */ /** @@ -81,6 +99,7 @@ class GuildScheduledEventManager extends CachedManager { entityMetadata, reason, image, + recurrenceRule, } = options; let entity_metadata, channel_id; @@ -104,6 +123,7 @@ class GuildScheduledEventManager extends CachedManager { entity_type: entityType, entity_metadata, image: image && (await resolveImage(image)), + recurrence_rule: recurrenceRule && _transformGuildScheduledEventRecurrenceRule(recurrenceRule), }, reason, }); @@ -178,6 +198,8 @@ class GuildScheduledEventManager extends CachedManager { * {@link GuildScheduledEventEntityType.External} * @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event * @property {string} [reason] The reason for editing the guild scheduled event + * @property {?GuildScheduledEventRecurrenceRuleOptions} [recurrenceRule] + * The recurrence rule of the guild scheduled event */ /** @@ -203,6 +225,7 @@ class GuildScheduledEventManager extends CachedManager { entityMetadata, reason, image, + recurrenceRule, } = options; let entity_metadata; @@ -224,6 +247,7 @@ class GuildScheduledEventManager extends CachedManager { status, image: image && (await resolveImage(image)), entity_metadata, + recurrence_rule: recurrenceRule && _transformGuildScheduledEventRecurrenceRule(recurrenceRule), }, reason, }); diff --git a/packages/discord.js/src/structures/GuildScheduledEvent.js b/packages/discord.js/src/structures/GuildScheduledEvent.js index f5a5291232e5e..9f6124f0198cd 100644 --- a/packages/discord.js/src/structures/GuildScheduledEvent.js +++ b/packages/discord.js/src/structures/GuildScheduledEvent.js @@ -189,6 +189,56 @@ class GuildScheduledEvent extends Base { } else { this.image ??= null; } + + /** + * Represents the recurrence rule for a {@link GuildScheduledEvent}. + * @typedef {Object} GuildScheduledEventRecurrenceRule + * @property {number} startTimestamp The timestamp the recurrence rule interval starts at + * @property {Date} startAt The time the recurrence rule interval starts at + * @property {?number} endTimestamp The timestamp the recurrence rule interval ends at + * @property {?Date} endAt The time the recurrence rule interval ends at + * @property {GuildScheduledEventRecurrenceRuleFrequency} frequency How often the event occurs + * @property {number} interval The spacing between the events + * @property {?GuildScheduledEventRecurrenceRuleWeekday[]} byWeekday The days within a week to recur on + * @property {?GuildScheduledEventRecurrenceRuleNWeekday[]} byNWeekday The days within a week to recur on + * @property {?GuildScheduledEventRecurrenceRuleMonth[]} byMonth The months to recur on + * @property {?number[]} byMonthDay The days within a month to recur on + * @property {?number[]} byYearDay The days within a year to recur on + * @property {?number} count The total amount of times the event is allowed to recur before stopping + */ + + /** + * @typedef {Object} GuildScheduledEventRecurrenceRuleNWeekday + * @property {number} n The week to recur on + * @property {GuildScheduledEventRecurrenceRuleWeekday} day The day within the week to recur on + */ + + if ('recurrence_rule' in data) { + /** + * The recurrence rule for this scheduled event + * @type {?GuildScheduledEventRecurrenceRule} + */ + this.recurrenceRule = { + startTimestamp: Date.parse(data.recurrence_rule.start), + get startAt() { + return new Date(this.startTimestamp); + }, + endTimestamp: data.recurrence_rule.end && Date.parse(data.recurrence_rule.end), + get endAt() { + return this.endTimestamp && new Date(this.endTimestamp); + }, + frequency: data.recurrence_rule.frequency, + interval: data.recurrence_rule.interval, + byWeekday: data.recurrence_rule.by_weekday, + byNWeekday: data.recurrence_rule.by_n_weekday, + byMonth: data.recurrence_rule.by_month, + byMonthDay: data.recurrence_rule.by_month_day, + byYearDay: data.recurrence_rule.by_year_day, + count: data.recurrence_rule.count, + }; + } else { + this.recurrenceRule ??= null; + } } /** diff --git a/packages/discord.js/src/util/APITypes.js b/packages/discord.js/src/util/APITypes.js index 42b2ddae09432..43a8bcf81adaf 100644 --- a/packages/discord.js/src/util/APITypes.js +++ b/packages/discord.js/src/util/APITypes.js @@ -100,6 +100,11 @@ * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildMember} */ +/** + * @external APIGuildScheduledEventRecurrenceRule + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildScheduledEventRecurrenceRule} + */ + /** * @external APIInteraction * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIInteraction} @@ -390,6 +395,21 @@ * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventPrivacyLevel} */ +/** + * @external GuildScheduledEventRecurrenceRuleFrequency + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventRecurrenceRuleFrequency} + */ + +/** + * @external GuildScheduledEventRecurrenceRuleMonth + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventRecurrenceRuleMonth} + */ + +/** + * @external GuildScheduledEventRecurrenceRuleWeekday + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventRecurrenceRuleWeekday} + */ + /** * @external GuildScheduledEventStatus * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventStatus} diff --git a/packages/discord.js/src/util/Transformers.js b/packages/discord.js/src/util/Transformers.js index 0e6148a100345..e37fb456c65ae 100644 --- a/packages/discord.js/src/util/Transformers.js +++ b/packages/discord.js/src/util/Transformers.js @@ -54,4 +54,31 @@ function _transformAPIMessageInteractionMetadata(client, messageInteractionMetad }; } -module.exports = { toSnakeCase, _transformAPIAutoModerationAction, _transformAPIMessageInteractionMetadata }; +/** + * Transforms a guild scheduled event recurrence rule object to a snake-cased variant. + * @param {GuildScheduledEventRecurrenceRuleOptions} recurrenceRule The recurrence rule to transform + * @returns {APIGuildScheduledEventRecurrenceRule} + * @ignore + */ +function _transformGuildScheduledEventRecurrenceRule(recurrenceRule) { + return { + start: new Date(recurrenceRule.startAt).toISOString(), + // eslint-disable-next-line eqeqeq + end: recurrenceRule.endAt != null ? new Date(recurrenceRule.endAt).toISOString() : recurrenceRule.endAt, + frequency: recurrenceRule.frequency, + interval: recurrenceRule.interval, + by_weekday: recurrenceRule.byWeekday, + by_n_weekday: recurrenceRule.byNWeekday, + by_month: recurrenceRule.byMonth, + by_month_day: recurrenceRule.byMonthDay, + by_year_day: recurrenceRule.byYearDay, + count: recurrenceRule.count, + }; +} + +module.exports = { + toSnakeCase, + _transformAPIAutoModerationAction, + _transformAPIMessageInteractionMetadata, + _transformGuildScheduledEventRecurrenceRule, +}; diff --git a/packages/discord.js/test/random.js b/packages/discord.js/test/random.js index e33af44d76757..48d5ab847b777 100644 --- a/packages/discord.js/test/random.js +++ b/packages/discord.js/test/random.js @@ -2,7 +2,7 @@ 'use strict'; -const { token } = require('./auth.js'); +const { token, owner } = require('./auth.js'); const { Client } = require('../src'); const { ChannelType, GatewayIntentBits } = require('discord-api-types/v10'); @@ -14,6 +14,7 @@ const client = new Client({ GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions, GatewayIntentBits.GuildMembers, + GatewayIntentBits.MessageContent, ], }); @@ -186,7 +187,7 @@ client.on('messageCreate', msg => { msg.channel.send(`\`\`\`${msg.content}\`\`\``); } - if (msg.content.startsWith('#eval') && msg.author.id === '66564597481480192') { + if (msg.content.startsWith('#eval') && msg.author.id === owner) { try { const com = eval(msg.content.split(' ').slice(1).join(' ')); msg.channel.send(`\`\`\`\n${com}\`\`\``); diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index f29e646f7c94a..57eed8b24e48f 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -186,6 +186,9 @@ import { ReactionType, APIAuthorizingIntegrationOwnersMap, MessageReferenceType, + GuildScheduledEventRecurrenceRuleWeekday, + GuildScheduledEventRecurrenceRuleMonth, + GuildScheduledEventRecurrenceRuleFrequency, } from 'discord-api-types/v10'; import { ChildProcess } from 'node:child_process'; import { EventEmitter } from 'node:events'; @@ -1779,6 +1782,7 @@ export class GuildScheduledEvent; } +export interface GuildScheduledEventRecurrenceRule { + startTimestamp: number; + get startAt(): Date; + endTimestamp: number | null; + get endAt(): Date | null; + frequency: GuildScheduledEventRecurrenceRuleFrequency; + interval: number; + byWeekday: readonly GuildScheduledEventRecurrenceRuleWeekday[] | null; + byNWeekday: readonly GuildScheduledEventRecurrenceRuleNWeekday[] | null; + byMonth: readonly GuildScheduledEventRecurrenceRuleMonth[] | null; + byMonthDay: readonly number[] | null; + byYearDay: readonly number[] | null; + count: number | null; +} + +export interface GuildScheduledEventRecurrenceRuleNWeekday { + n: number; + day: GuildScheduledEventRecurrenceRuleWeekday; +} + export class GuildTemplate extends Base { private constructor(client: Client, data: RawGuildTemplateData); public createdTimestamp: number; @@ -6167,14 +6191,29 @@ export interface GuildScheduledEventCreateOptions { entityMetadata?: GuildScheduledEventEntityMetadataOptions; image?: BufferResolvable | Base64Resolvable | null; reason?: string; + recurrenceRule?: GuildScheduledEventRecurrenceRuleOptions; +} + +export interface GuildScheduledEventRecurrenceRuleOptions { + startAt: DateResolvable; + endAt: DateResolvable; + frequency: GuildScheduledEventRecurrenceRuleFrequency; + interval: number; + byWeekday: readonly GuildScheduledEventRecurrenceRuleWeekday[]; + byNWeekday: readonly GuildScheduledEventRecurrenceRuleNWeekday[]; + byMonth: readonly GuildScheduledEventRecurrenceRuleMonth[]; + byMonthDay: readonly number[]; + byYearDay: readonly number[]; + count: number; } export interface GuildScheduledEventEditOptions< Status extends GuildScheduledEventStatus, AcceptableStatus extends GuildScheduledEventSetStatusArg, -> extends Omit, 'channel'> { +> extends Omit, 'channel' | 'recurrenceRule'> { channel?: GuildVoiceChannelResolvable | null; status?: AcceptableStatus; + recurrenceRule?: GuildScheduledEventRecurrenceRuleOptions | null; } export interface GuildScheduledEventEntityMetadata { diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index f23023f1accaa..1f1b34f3a0b6e 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -209,6 +209,7 @@ import { ApplicationEmoji, ApplicationEmojiManager, StickerPack, + GuildScheduledEventManager, SendableChannels, PollData, } from '.'; @@ -2618,3 +2619,6 @@ client.on('interactionCreate', interaction => { interaction.channel.send({ embeds: [] }); } }); + +declare const guildScheduledEventManager: GuildScheduledEventManager; +await guildScheduledEventManager.edit(snowflake, { recurrenceRule: null });