diff --git a/packages/discord.js/src/managers/GuildScheduledEventManager.js b/packages/discord.js/src/managers/GuildScheduledEventManager.js
index a0d0c8375e72..383875d70002 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 f5a5291232e5..9f6124f0198c 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 42b2ddae0943..43a8bcf81ada 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 0e6148a10034..e37fb456c65a 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 e33af44d7675..48d5ab847b77 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 f29e646f7c94..57eed8b24e48 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 f23023f1acca..1f1b34f3a0b6 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 });