Compare commits

...

35 Commits

Author SHA1 Message Date
Jiralite
8065b80cea chore: update 11135 name 2025-10-08 18:15:00 +01:00
Vlad Frangu
3b26680672 chore(discord.js): release discord.js@14.23.0 2025-10-08 20:14:05 +03:00
Jiralite
c4dbd7ee9f chore(core): release @discordjs/core@2.3.0 2025-10-08 18:09:11 +01:00
Almeida
72771b79aa feat: add {add,remove}GroupDMRecipient methods (#11135)
* feat: add `{add,delete}GroupDMRecipient methods`

* fix: requested changes

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2025-10-08 16:03:50 +01:00
Jiralite
63dbe48055 feat(guild): Support incident actions (#11131)
* feat(guild): add incident actions

* fix: add result

---------

Co-Authored-By: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2025-10-08 16:02:03 +01:00
Vlad Frangu
67c8953a10 feat: bump builders in v14 (and fix runtime crashes) (#11153)
* feat: bump builders in v14 (and fix runtime crashes)

* chore: bump dtypes

* Update packages/discord.js/src/structures/LabelBuilder.js

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* chore: requested changes

* chore: lint

---------

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
2025-10-08 14:47:39 +01:00
Pavel-Boyazov
30e35d909e types(ClientEventTypes): fix messageDeleteBulk event arg (#11122)
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
2025-10-07 17:44:32 +01:00
Pavel-Boyazov
6a5707c786 types(Webhook): specify message type (#11142)
* types(Webhook): specify message type

* test(Webhook): update types
2025-10-07 17:40:05 +01:00
Jiralite
9b821e5dfc feat(GuildMemberManager): Add new modify self fields (#11112)
* feat(GuildMemberManager): Add new modify self fields (#11089)

* fix: use correct route

* fix: add deprecation

* fix: rewrite message
2025-10-06 08:36:28 +01:00
Jiralite
a04172325a feat: Add gateway endpoints (#11130)
feat: add gateway
Co-Authored-By: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2025-10-04 17:51:37 +01:00
Almeida
154c00ded9 fix(ThreadMemberFlagsBitField): use ThreadMemberFlags enum in Flags (#11118)
feat(ThreadMemberFlagsBitField): use `ThreadMemberFlags` enum in `Flags`
2025-10-02 21:59:27 +01:00
Almeida
3b927449ae docs: use LocalizationMap where applicable (#11117) 2025-10-02 21:58:28 +01:00
Naiyar
fcce0d95bb fix: backport in operator fix from main (#11127)
fix: use in operator when resolving modal component (#11115)
2025-10-01 15:54:03 +01:00
Naiyar
93e0f4cd10 feat: text display and more selects in modal for v14 (#11096)
* feat: handle recieve label components

* chore: missed fixes

* fix: missing id when transforming

* chore: add missing things

* fix: test

* feat: send label

* fix: un-break it

* chore: test

* feat: more selects in modals

* chore: make resolved read-only

* chore: import order

* chore: add missing cached generic

* style: spacing

* docs: consistency

* docs: make it a type

* docs: Add `APISelectMenuDefaultValue`

---------

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
2025-09-21 22:28:33 +01:00
Naiyar
abaae4ff16 feat: label component and select in modal for v14 (#11090)
* feat: handle recieve label components

* chore: missed fixes

* fix: missing id when transforming

* chore: add missing things

* fix: test

* feat: send label

* fix: un-break it

* chore: test

* chore: missing required in typings
2025-09-15 21:28:07 +01:00
Jiralite
270d9f1047 chore(core): release @discordjs/core@2.2.2 2025-09-10 18:49:28 +01:00
Jiralite
9ae737708b fix(users): Correct type for editing current guild member (#11098)
* fix(users): `RESTPatchAPICurrentGuildMemberJSONBody`

* fix: imports
2025-09-10 18:45:05 +01:00
Jiralite
e382d60421 build: upgrade discord-api-types to 0.38.24 2025-09-10 18:14:11 +01:00
Jiralite
68aa202cd6 build: upgrade discord-api-types to 0.38.23 2025-09-10 11:34:34 +01:00
VAKiliner
d8ad181c19 fix: Ensure discriminator detection respects webhooks too (#11062)
* Replace discriminator === '0' to Number(discriminator)

* Fix

* Replacing !Number() to ['0', '0000'].includes

* chore: fmt

* perf: no array

---------

Co-authored-by: almeidx <github@almeidx.dev>
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
2025-09-05 13:46:27 +01:00
Jiralite
0dff969e16 refactor(ActionsManager): Register actions without using class name (#11080)
* refactor: register actions without using class name

* fix: this is `module.exports`
2025-09-02 10:28:15 +01:00
Jiralite
79d999e4c1 feat: Guest invites (#11079)
feat(Invite): add `flags`
2025-09-02 09:21:11 +01:00
Amgelo563
215f8dc5e0 fix: Do not omit falsy default values (#10755)
* fix(docs): fix default falsy values being omitted

* fix(docs): swap defaultValue check to avoid negated condition

* fix: fix pr by removing everything it added and committing something entirely different

---------

Co-authored-by: almeidx <github@almeidx.dev>
2025-09-02 01:11:24 +01:00
Jiralite
b6089e585e build: upgrade discord-api-types to 0.38.22 2025-09-02 00:53:31 +01:00
Jiralite
fe025c0a9f docs(GuildEditOptions): deprecate owner property 2025-08-29 11:01:16 +01:00
Almeida
4a8aeb6aee feat: polls overhaul (#11058)
* feat: polls overhaul (#10328)

* feat(Managers): add PollAnswerVoterManager

* feat(Partials): make Polls partial-safe

* types: add typings

* chore: add tests

* fix: use fetch method in manager instead

* chore: add tests for manager

* feat: add partial support to poll actions

* style: formatting

* fix: change all .users references to .voters

* refactor: add additional logic for partials

* fix: actually add the partials

* fix: fixed issue where event does not emit on first event

* fix: align property type with DAPI documentation

* fix: resolve additional bugs with partials

* typings: update typings to reflect property type change

* fix: tests

* fix: adjust tests

* refactor: combine partials logic into one statement

* docs: mark getter as readonly

* refactor: apply suggestions

Co-authored-by: Almeida <github@almeidx.dev>

* refactor(Actions): apply suggestions

* refactor(PollAnswerVoterManager): apply suggestions

* refactor(Message): check for existing poll before creating a poll

* refactor(Polls): apply suggestions

* revert(types): remove unused method from Poll class

* refactor(Actions): consolidate poll creation logic into action class

* refactor(PollAnswerVoterManager): set default for fetch parameter

* refactor(Message): apply suggestion

* fix: remove partial setter

* refactor(Polls): apply suggestions

* types: apply suggestions

* refactor: remove clones

* docs: spacing

* refactor: move setters from constructor to _patch

* types: adjust partials for poll classes

* test: add more tests for polls

* refactor: move updates around, more correct partial types

* fix: handle more cases

* refactor: requested changes

* fix: missing imports

* fix: update imports

* fix: require file extensions

---------

Co-authored-by: Almeida <github@almeidx.dev>
Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com>

* fix(Poll): ensure `this.answers` is set before we reference it (#10809)

* Ensure 	his.answers is set sooner if it's null during a patch

* Move data.answers block up as well to ensure the patched answers are set

* Ensure collection is set in constructor instead

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* fix(PollAnswer): only define _emoji property once (#10811)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

---------

Co-authored-by: Kevin <uhkevinmc@eedo.app>
Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com>
Co-authored-by: Jacob Morrison <jake.morrison24@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2025-08-29 10:58:04 +01:00
Jiralite
3dd57c2eaf docs: Deprecate API related to guild ownership (#11054)
* docs: deprecate API usage for guild ownership

* docs: remove pointless example
2025-08-29 10:53:34 +01:00
Jiralite
740da4ce5e docs: deprecate setting owner 2025-08-29 10:51:13 +01:00
Jiralite
6fb0b1cef6 docs(guild): deprecate API related to guild ownership 2025-08-22 12:48:29 +01:00
Jiralite
ac6ff15b7d fix(guild): Creating a template actually creates a template (#11030)
feat(guild): add creating a template
2025-08-22 12:41:53 +01:00
Jiralite
a294b47db0 chore(discord.js): release discord.js@14.22.1 2025-08-22 12:05:56 +01:00
Souji
ecef7bdf22 fix(GuildChannel): account for everyone base permissions (#11053)
When calculating permissions after overwrites, the base permission of the at-everyone role need to be accounted for.
Role#permissions is not sufficient, as it only describes base permissions of the role itself.

fixes #11052
2025-08-22 12:04:35 +01:00
Jiralite
40578393c3 chore: add @discordjs/collection in api-extractor.json 2025-08-22 08:57:02 +01:00
Vlad Frangu
86ecb37c9e chore(discord.js): correct changelog and version 2025-08-21 00:58:23 +03:00
Vlad Frangu
311e826b12 chore(discord.js): release discord.js@15.0.0 2025-08-21 00:52:53 +03:00
54 changed files with 1535 additions and 313 deletions

View File

@@ -1270,7 +1270,7 @@ export class ApiModelGenerator {
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
const docComment: tsdoc.DocComment | undefined = jsDoc
? this._tsDocParser.parseString(
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}${jsDoc.default ? ` (default: ${this._escapeSpecialChars(jsDoc.default)})` : ''}\n${
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}${jsDoc.default === undefined ? '' : ` (default: ${this._escapeSpecialChars(jsDoc.default)})`}\n${
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
'deprecated' in jsDoc && jsDoc.deprecated
@@ -1348,7 +1348,7 @@ export class ApiModelGenerator {
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
const docComment: tsdoc.DocComment | undefined = jsDoc
? this._tsDocParser.parseString(
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}${jsDoc.default ? `\n * @defaultValue ${this._escapeSpecialChars(jsDoc.default)}` : ''}\n${
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}${jsDoc.default === undefined ? '' : `\n * @defaultValue ${this._escapeSpecialChars(jsDoc.default)}`}\n${
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
'deprecated' in jsDoc && jsDoc.deprecated

View File

@@ -2,6 +2,25 @@
All notable changes to this project will be documented in this file.
# [@discordjs/core@2.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@2.2.2...@discordjs/core@2.3.0) - (2025-10-08)
## Features
- Add `{add,remove}GroupDMRecipient` methods (#11135) ([72771b7](https://github.com/discordjs/discord.js/commit/72771b79aa3a78967be92ea2e4c523755d0d2ec0))
- **guild:** Support incident actions (#11131) ([63dbe48](https://github.com/discordjs/discord.js/commit/63dbe48055347413ec70f36bce4f645688776413))
- Add gateway endpoints (#11130) ([a041723](https://github.com/discordjs/discord.js/commit/a04172325af5a3a9880253bb8dc7c057a0426d83))
# [@discordjs/core@2.2.2](https://github.com/discordjs/discord.js/compare/@discordjs/core@2.2.1...@discordjs/core@2.2.2) - (2025-09-10)
## Bug Fixes
- **users:** Correct type for editing current guild member (#11098) ([9ae7377](https://github.com/discordjs/discord.js/commit/9ae737708b24400320a2da4a85a6c977475a05a5))
- **guild:** Creating a template actually creates a template (#11030) ([ac6ff15](https://github.com/discordjs/discord.js/commit/ac6ff15b7dc4a88753b7cfdf1bca1b4bcc1cc260))
## Documentation
- **guild:** Deprecate API related to guild ownership ([6fb0b1c](https://github.com/discordjs/discord.js/commit/6fb0b1cef6e479be3d47370438d8a588a7c2b850))
# [@discordjs/core@2.2.1](https://github.com/discordjs/discord.js/compare/@discordjs/core@2.2.0...@discordjs/core@2.2.1) - (2025-08-20)
## Bug Fixes

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@discordjs/core",
"version": "2.2.1",
"version": "2.3.0",
"description": "A thinly abstracted wrapper around the rest API, and gateway.",
"scripts": {
"test": "vitest run",
@@ -70,7 +70,7 @@
"@discordjs/ws": "workspace:^",
"@sapphire/snowflake": "^3.5.3",
"@vladfrangu/async_event_emitter": "^2.4.6",
"discord-api-types": "^0.38.16"
"discord-api-types": "^0.38.29"
},
"devDependencies": {
"@discordjs/api-extractor": "workspace:^",

View File

@@ -0,0 +1,34 @@
import { Routes } from 'discord-api-types/v10';
import { glob, readFile } from 'node:fs/promises';
const usedRoutes = new Set();
const ignoredRoutes = new Set([
// Deprecated
'channelPins',
'channelPin',
'guilds',
'guildCurrentMemberNickname',
'guildMFA',
'nitroStickerPacks',
]);
for await (const file of glob('src/api/*.ts')) {
const content = await readFile(file, 'utf-8');
const routes = content.matchAll(/Routes\.([\w\d_]+)/g);
for (const route of routes) {
usedRoutes.add(route[1]);
}
}
const unusedRoutes = Object.keys(Routes).filter((route) => !usedRoutes.has(route) && !ignoredRoutes.has(route));
if (unusedRoutes.length > 0) {
console.warn('The following routes are not implemented:');
for (const route of unusedRoutes) {
console.warn(` - ${route}`);
}
} else {
console.log('No missing routes.');
}

View File

@@ -1,10 +1,9 @@
/* eslint-disable jsdoc/check-param-names */
import { makeURLSearchParams, type RawFile, type REST, type RequestData } from '@discordjs/rest';
import { makeURLSearchParams, type RawFile, type RequestData, type REST } from '@discordjs/rest';
import {
Routes,
type RESTPostAPIChannelWebhookJSONBody,
type RESTPostAPIChannelWebhookResult,
type APIThreadChannel,
type RESTDeleteAPIChannelResult,
type RESTGetAPIChannelInvitesResult,
type RESTGetAPIChannelMessageReactionUsersQuery,
@@ -17,8 +16,8 @@ import {
type RESTGetAPIChannelThreadsArchivedQuery,
type RESTGetAPIChannelUsersThreadsArchivedResult,
type RESTGetAPIChannelWebhooksResult,
type RESTPatchAPIChannelMessageJSONBody,
type RESTPatchAPIChannelJSONBody,
type RESTPatchAPIChannelMessageJSONBody,
type RESTPatchAPIChannelMessageResult,
type RESTPatchAPIChannelResult,
type RESTPostAPIChannelFollowersResult,
@@ -27,12 +26,14 @@ import {
type RESTPostAPIChannelMessageCrosspostResult,
type RESTPostAPIChannelMessageJSONBody,
type RESTPostAPIChannelMessageResult,
type RESTPutAPIChannelPermissionJSONBody,
type Snowflake,
type RESTPostAPIChannelThreadsJSONBody,
type RESTPostAPIChannelThreadsResult,
type APIThreadChannel,
type RESTPostAPIChannelWebhookJSONBody,
type RESTPostAPIChannelWebhookResult,
type RESTPostAPIGuildForumThreadsJSONBody,
type RESTPutAPIChannelPermissionJSONBody,
type RESTPutAPIChannelRecipientJSONBody,
type Snowflake,
} from 'discord-api-types/v10';
export interface StartForumThreadOptions extends RESTPostAPIGuildForumThreadsJSONBody {
@@ -593,4 +594,43 @@ export class ChannelsAPI {
signal,
});
}
/**
* Adds a recipient to a group DM channel
*
* @see {@link https://discord.com/developers/docs/resources/channel#group-dm-add-recipient}
* @param channelId - The id of the channel to add the recipient to
* @param userId - The id of the user to add as a recipient
* @param body - The data for adding the recipient
* @param options - The options for adding the recipient
*/
public async addGroupDMRecipient(
channelId: Snowflake,
userId: Snowflake,
body: RESTPutAPIChannelRecipientJSONBody,
{ signal }: Pick<RequestData, 'signal'> = {},
) {
await this.rest.put(Routes.channelRecipient(channelId, userId), {
body,
signal,
});
}
/**
* Removes a recipient from a group DM channel
*
* @see {@link https://discord.com/developers/docs/resources/channel#group-dm-remove-recipient}
* @param channelId - The id of the channel to remove the recipient from
* @param userId - The id of the user to remove as a recipient
* @param options - The options for removing the recipient
*/
public async removeGroupDMRecipient(
channelId: Snowflake,
userId: Snowflake,
{ signal }: Pick<RequestData, 'signal'> = {},
) {
await this.rest.delete(Routes.channelRecipient(channelId, userId), {
signal,
});
}
}

View File

@@ -0,0 +1,31 @@
/* eslint-disable jsdoc/check-param-names */
import type { RequestData, REST } from '@discordjs/rest';
import { Routes, type RESTGetAPIGatewayBotResult, type RESTGetAPIGatewayResult } from 'discord-api-types/v10';
export class GatewayAPI {
public constructor(private readonly rest: REST) {}
/**
* Gets gateway information.
*
* @see {@link https://discord.com/developers/docs/events/gateway#get-gateway}
* @param options - The options for fetching the gateway information
*/
public async get({ signal }: Pick<RequestData, 'signal'> = {}) {
return this.rest.get(Routes.gateway(), {
auth: false,
signal,
}) as Promise<RESTGetAPIGatewayResult>;
}
/**
* Gets gateway information with additional metadata.
*
* @see {@link https://discord.com/developers/docs/events/gateway#get-gateway-bot}
* @param options - The options for fetching the gateway information
*/
public async getBot({ signal }: Pick<RequestData, 'signal'> = {}) {
return this.rest.get(Routes.gatewayBot(), { signal }) as Promise<RESTGetAPIGatewayBotResult>;
}
}

View File

@@ -95,6 +95,8 @@ import {
type RESTPostAPIGuildsMFAResult,
type RESTPostAPIGuildsResult,
type RESTPutAPIGuildBanJSONBody,
type RESTPutAPIGuildIncidentActionsJSONBody,
type RESTPutAPIGuildIncidentActionsResult,
type RESTPutAPIGuildMemberJSONBody,
type RESTPutAPIGuildMemberResult,
type RESTPutAPIGuildOnboardingJSONBody,
@@ -166,6 +168,7 @@ export class GuildsAPI {
* @see {@link https://discord.com/developers/docs/resources/guild#create-guild}
* @param body - The guild to create
* @param options - The options for creating the guild
* @deprecated API related to guild ownership may no longer be used.
*/
public async create(body: RESTPostAPIGuildsJSONBody, { signal }: Pick<RequestData, 'signal'> = {}) {
return this.rest.post(Routes.guilds(), { body, signal }) as Promise<RESTPostAPIGuildsResult>;
@@ -197,6 +200,7 @@ export class GuildsAPI {
* @see {@link https://discord.com/developers/docs/resources/guild#delete-guild}
* @param guildId - The id of the guild to delete
* @param options - The options for deleting this guild
* @deprecated API related to guild ownership may no longer be used.
*/
public async delete(guildId: Snowflake, { signal }: Pick<RequestData, 'signal'> = {}) {
await this.rest.delete(Routes.guild(guildId), { signal });
@@ -491,6 +495,7 @@ export class GuildsAPI {
* @param guildId - The id of the guild to edit the MFA level for
* @param level - The new MFA level
* @param options - The options for editing the MFA level
* @deprecated API related to guild ownership may no longer be used.
*/
public async editMFALevel(
guildId: Snowflake,
@@ -1287,16 +1292,16 @@ export class GuildsAPI {
* Creates a new template
*
* @see {@link https://discord.com/developers/docs/resources/guild-template#create-guild-template}
* @param templateCode - The code of the template
* @param guildId - The id of the guild
* @param body - The data for creating the template
* @param options - The options for creating the template
*/
public async createTemplate(
templateCode: string,
guildId: Snowflake,
body: RESTPostAPIGuildTemplatesJSONBody,
{ signal }: Pick<RequestData, 'signal'> = {},
) {
return this.rest.post(Routes.template(templateCode), { body, signal }) as Promise<RESTPostAPIGuildTemplatesResult>;
return this.rest.post(Routes.guildTemplates(guildId), { body, signal }) as Promise<RESTPostAPIGuildTemplatesResult>;
}
/**
@@ -1356,4 +1361,23 @@ export class GuildsAPI {
signal,
}) as Promise<RESTPutAPIGuildOnboardingResult>;
}
/**
* Modifies incident actions for a guild.
*
* @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-incident-actions}
* @param guildId - The id of the guild
* @param body - The data for modifying guild incident actions
* @param options - The options for modifying guild incident actions
*/
public async editIncidentActions(
guildId: Snowflake,
body: RESTPutAPIGuildIncidentActionsJSONBody,
{ signal }: Pick<RequestData, 'signal'> = {},
) {
return this.rest.put(Routes.guildIncidentActions(guildId), {
body,
signal,
}) as Promise<RESTPutAPIGuildIncidentActionsResult>;
}
}

View File

@@ -2,6 +2,7 @@ import type { REST } from '@discordjs/rest';
import { ApplicationCommandsAPI } from './applicationCommands.js';
import { ApplicationsAPI } from './applications.js';
import { ChannelsAPI } from './channel.js';
import { GatewayAPI } from './gateway.js';
import { GuildsAPI } from './guild.js';
import { InteractionsAPI } from './interactions.js';
import { InvitesAPI } from './invite.js';
@@ -19,6 +20,7 @@ import { WebhooksAPI } from './webhook.js';
export * from './applicationCommands.js';
export * from './applications.js';
export * from './channel.js';
export * from './gateway.js';
export * from './guild.js';
export * from './interactions.js';
export * from './invite.js';
@@ -40,6 +42,8 @@ export class API {
public readonly channels: ChannelsAPI;
public readonly gateway: GatewayAPI;
public readonly guilds: GuildsAPI;
public readonly interactions: InteractionsAPI;
@@ -70,6 +74,7 @@ export class API {
this.applicationCommands = new ApplicationCommandsAPI(rest);
this.applications = new ApplicationsAPI(rest);
this.channels = new ChannelsAPI(rest);
this.gateway = new GatewayAPI(rest);
this.guilds = new GuildsAPI(rest);
this.invites = new InvitesAPI(rest);
this.monetization = new MonetizationAPI(rest);

View File

@@ -10,9 +10,9 @@ import {
type RESTGetAPICurrentUserResult,
type RESTGetAPIUserResult,
type RESTGetCurrentUserGuildMemberResult,
type RESTPatchAPICurrentGuildMemberJSONBody,
type RESTPatchAPICurrentUserJSONBody,
type RESTPatchAPICurrentUserResult,
type RESTPatchAPIGuildMemberJSONBody,
type RESTPatchAPIGuildMemberResult,
type RESTPostAPICurrentUserCreateDMChannelResult,
type RESTPutAPICurrentUserApplicationRoleConnectionJSONBody,
@@ -101,7 +101,7 @@ export class UsersAPI {
*/
public async editCurrentGuildMember(
guildId: Snowflake,
body: RESTPatchAPIGuildMemberJSONBody = {},
body: RESTPatchAPICurrentGuildMemberJSONBody = {},
{ reason, signal }: Pick<RequestData, 'reason' | 'signal'> = {},
) {
return this.rest.patch(Routes.guildMember(guildId, '@me'), {

View File

@@ -2,6 +2,80 @@
All notable changes to this project will be documented in this file.
# [14.23.0](https://github.com/discordjs/discord.js/compare/14.22.1...14.23.0) - (2025-10-08)
## Bug Fixes
- **ThreadMemberFlagsBitField:** Use `ThreadMemberFlags` enum in `Flags` (#11118) ([154c00d](https://github.com/discordjs/discord.js/commit/154c00ded932109c59ff0759609424fcb95140a0))
- Backport in operator fix from main (#11127) ([fcce0d9](https://github.com/discordjs/discord.js/commit/fcce0d95bb6cd415f40f9f7a052e01ddcf625ed0))
- Ensure discriminator detection respects webhooks too (#11062) ([d8ad181](https://github.com/discordjs/discord.js/commit/d8ad181c191e3a908e3c8e133ccb1d961d9d79e0))
## Documentation
- Use LocalizationMap where applicable (#11117) ([3b92744](https://github.com/discordjs/discord.js/commit/3b927449ae728175f04d67376642b20ba4a93069))
- **GuildEditOptions:** Deprecate owner property ([fe025c0](https://github.com/discordjs/discord.js/commit/fe025c0a9f722c6225fff6501e9b3981cfe134ba))
- Deprecate API related to guild ownership (#11054) ([3dd57c2](https://github.com/discordjs/discord.js/commit/3dd57c2eaf220b08f2b6f6562c34acf8524b5b17))
- Deprecate setting owner ([740da4c](https://github.com/discordjs/discord.js/commit/740da4ce5e189391c7a0904da32a96fe1c8534e6))
## Features
- Bump builders in v14 (and fix runtime crashes) (#11153) ([67c8953](https://github.com/discordjs/discord.js/commit/67c8953a10d150074ba848cd8bfb30961d46b662))
- **GuildMemberManager:** Add new modify self fields (#11112) ([9b821e5](https://github.com/discordjs/discord.js/commit/9b821e5dfcfb92a9d23ef96dd947c0bd11ee7b86))
- Text display and more selects in modal for v14 (#11096) ([93e0f4c](https://github.com/discordjs/discord.js/commit/93e0f4cd10af6d85ccdcb6a6aeae3e1a9f14a8fe))
- Guest invites (#11079) ([79d999e](https://github.com/discordjs/discord.js/commit/79d999e4c10e36330ee897065987ad99d558edca))
- Polls overhaul (#11058) ([4a8aeb6](https://github.com/discordjs/discord.js/commit/4a8aeb6aee78b23a25e8d5be1309cc7c64b066fb))
## Refactor
- **ActionsManager:** Register actions without using class name (#11080) ([0dff969](https://github.com/discordjs/discord.js/commit/0dff969e16a8879a0fc889567bd540cb1b82a682))
## Typings
- **ClientEventTypes:** Fix `messageDeleteBulk` event arg (#11122) ([30e35d9](https://github.com/discordjs/discord.js/commit/30e35d909e0058db701c82744b13da26ddefcf0e))
- **Webhook:** Specify message type (#11142) ([6a5707c](https://github.com/discordjs/discord.js/commit/6a5707c78669bb65d03ae76ab591e053787891f1))
# [14.22.1](https://github.com/discordjs/discord.js/compare/14.22.0...14.22.1) - (2025-08-22)
## Bug Fixes
- **GuildChannel:** Account for everyone base permissions (#11053) ([ecef7bd](https://github.com/discordjs/discord.js/commit/ecef7bdf22cc3e7c1fc47d828a55f6139672b2a8))
# [14.22.0](https://github.com/discordjs/discord.js/compare/14.21.0...14.22.0) - (2025-08-20)
## Bug Fixes
- Remove trailing `color` references (#11007) ([b532df6](https://github.com/discordjs/discord.js/commit/b532df61ed346e2289831f2905984583a53d3fa5))
- **Emoji:** Remove incorrect nullables, add `ApplicationEmoji#available` (#10990) ([90d3b28](https://github.com/discordjs/discord.js/commit/90d3b282684f5a4bbf9ce2672fa5efd5ec802e95))
- **GuildChannelManager:** Properly resolve avatar for createWebhook (#10772) ([63f5261](https://github.com/discordjs/discord.js/commit/63f5261f4c351cd1b6befca1163254300f7424f4))
- **Message:** Forwarded messages are not `crosspostable` (#10821) ([b36b751](https://github.com/discordjs/discord.js/commit/b36b751bde5f5de286d748465619147619959d4f))
- **DirectoryChannel:** Export class (#10985) ([51ceb20](https://github.com/discordjs/discord.js/commit/51ceb203fa218accab47f604f91f74b49af7e51f))
- **Events:** `WebhooksUpdate` enum value (#10970) ([1404e32](https://github.com/discordjs/discord.js/commit/1404e328492549f4a17ab997eb648f3263e8ec25))
## Documentation
- Remove hardcoded locale from links (#10794) ([5be774d](https://github.com/discordjs/discord.js/commit/5be774db641b60669505645861d721200d335a7b))
- **ApplicationCommand:** Incorrect method in example (#10837) ([040c66a](https://github.com/discordjs/discord.js/commit/040c66ae15fd3cc7cb40bdbb5384ede445c40973))
## Features
- Support user guilds (#10995) ([baa08b8](https://github.com/discordjs/discord.js/commit/baa08b8fbb64abd8265890413c95f81e2c61303f))
- **MessageManager:** New pinned messages routes (#10993) ([f469f74](https://github.com/discordjs/discord.js/commit/f469f74acaa14f126fd02af4a032ca8e56dbb534))
- `fetchPinned()` has been renamed to `fetchPins()`, which is a paginated endpoint to fetch pinned messages.
- **User:** Add `collectibles` (#10939) ([8ac0e1e](https://github.com/discordjs/discord.js/commit/8ac0e1e5d6df9c51fd3a41d9f8c9dbe8f786229a))
- Role gradient colours (#10986) ([9d6fdf8](https://github.com/discordjs/discord.js/commit/9d6fdf8979d29787a13912cfa55f1ff3961c6b68))
- Support animated WebP (#10987) ([cafe58b](https://github.com/discordjs/discord.js/commit/cafe58b3bd9defb5050a7a90bd07568f3b509c89))
## Refactor
- Deprecate `ready` event in favor of `clientReady` (#10969) ([82378fc](https://github.com/discordjs/discord.js/commit/82378fc2e8f4fd7e56b5a80eb6a6d3a8315e388e))
- **ThreadChannel:** Remove trimming of name (#10984) ([d4f742e](https://github.com/discordjs/discord.js/commit/d4f742e99e31b4eb9e84afce3bab48ed549f8ae3))
## Typings
- **Invite:** Approximate fields should be nullable (#10997) ([d60e0bf](https://github.com/discordjs/discord.js/commit/d60e0bf30bac05921063d010fab253ca829ae3bb))
- **ModalSubmitFields:** Fix `fields` type (#10816) ([500712d](https://github.com/discordjs/discord.js/commit/500712d5eaef1a75133e088e0f260842d12f3419))
- **InteractionCallbackResponse:** Add missing InGuild generic (#10963) ([19e74b1](https://github.com/discordjs/discord.js/commit/19e74b153317cf8b910317c56beb95a698acc00c))
# [14.21.0](https://github.com/discordjs/discord.js/compare/14.20.0...14.21.0) - (2025-06-25)
## Bug Fixes

View File

@@ -3,6 +3,7 @@
"mainEntryPointFilePath": "<projectFolder>/typings/index.d.ts",
"bundledPackages": [
"discord-api-types",
"@discordjs/collection",
"@discordjs/builders",
"@discordjs/formatters",
"@discordjs/rest",

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "discord.js",
"version": "14.21.0",
"version": "14.23.0",
"description": "A powerful library for interacting with the Discord API",
"scripts": {
"test": "pnpm run docs:test && pnpm run test:typescript",
@@ -66,14 +66,14 @@
"homepage": "https://discord.js.org",
"funding": "https://github.com/discordjs/discord.js?sponsor",
"dependencies": {
"@discordjs/builders": "^1.11.2",
"@discordjs/builders": "^1.12.0",
"@discordjs/collection": "1.5.3",
"@discordjs/formatters": "^0.6.1",
"@discordjs/rest": "workspace:^",
"@discordjs/util": "workspace:^",
"@discordjs/ws": "^1.2.3",
"@sapphire/snowflake": "3.5.3",
"discord-api-types": "^0.38.16",
"discord-api-types": "^0.38.29",
"fast-deep-equal": "3.1.3",
"lodash.snakecase": "4.1.1",
"magic-bytes.js": "^1.10.0",

View File

@@ -36,12 +36,14 @@ async function writeClientActionImports() {
for (const file of (await readdir(actionsDirectory)).sort()) {
if (file === 'Action.js' || file === 'ActionsManager.js') continue;
lines.push(` this.register(require('./${file.slice(0, -3)}'));`);
const actionName = file.slice(0, -3);
lines.push(` this.${actionName} = this.load(require('./${file}'));`);
}
lines.push(' }\n');
lines.push(' register(Action) {');
lines.push(" this[Action.name.replace(/Action$/, '')] = new Action(this.client);");
lines.push(' load(Action) {');
lines.push(' return new Action(this.client);');
lines.push(' }');
lines.push('}\n');
lines.push('module.exports = ActionsManager;\n');

View File

@@ -1,6 +1,8 @@
'use strict';
const Partials = require('../../util/Partials');
const { Poll } = require('../../structures/Poll.js');
const { PollAnswer } = require('../../structures/PollAnswer.js');
const Partials = require('../../util/Partials.js');
/*
@@ -63,6 +65,23 @@ class GenericAction {
);
}
getPoll(data, message, channel) {
const includePollPartial = this.client.options.partials.includes(Partials.Poll);
const includePollAnswerPartial = this.client.options.partials.includes(Partials.PollAnswer);
if (message.partial && (!includePollPartial || !includePollAnswerPartial)) return null;
if (!message.poll && includePollPartial) {
message.poll = new Poll(this.client, data, message, channel);
}
if (message.poll && !message.poll.answers.has(data.answer_id) && includePollAnswerPartial) {
const pollAnswer = new PollAnswer(this.client, data, message.poll);
message.poll.answers.set(data.answer_id, pollAnswer);
}
return message.poll;
}
getReaction(data, message, user) {
const id = data.emoji.id ?? decodeURIComponent(data.emoji.name);
return this.getPayload(

View File

@@ -11,74 +11,74 @@ class ActionsManager {
constructor(client) {
this.client = client;
this.register(require('./ApplicationCommandPermissionsUpdate'));
this.register(require('./AutoModerationActionExecution'));
this.register(require('./AutoModerationRuleCreate'));
this.register(require('./AutoModerationRuleDelete'));
this.register(require('./AutoModerationRuleUpdate'));
this.register(require('./ChannelCreate'));
this.register(require('./ChannelDelete'));
this.register(require('./ChannelUpdate'));
this.register(require('./EntitlementCreate'));
this.register(require('./EntitlementDelete'));
this.register(require('./EntitlementUpdate'));
this.register(require('./GuildAuditLogEntryCreate'));
this.register(require('./GuildBanAdd'));
this.register(require('./GuildBanRemove'));
this.register(require('./GuildChannelsPositionUpdate'));
this.register(require('./GuildDelete'));
this.register(require('./GuildEmojiCreate'));
this.register(require('./GuildEmojiDelete'));
this.register(require('./GuildEmojiUpdate'));
this.register(require('./GuildEmojisUpdate'));
this.register(require('./GuildIntegrationsUpdate'));
this.register(require('./GuildMemberRemove'));
this.register(require('./GuildMemberUpdate'));
this.register(require('./GuildRoleCreate'));
this.register(require('./GuildRoleDelete'));
this.register(require('./GuildRoleUpdate'));
this.register(require('./GuildRolesPositionUpdate'));
this.register(require('./GuildScheduledEventCreate'));
this.register(require('./GuildScheduledEventDelete'));
this.register(require('./GuildScheduledEventUpdate'));
this.register(require('./GuildScheduledEventUserAdd'));
this.register(require('./GuildScheduledEventUserRemove'));
this.register(require('./GuildSoundboardSoundDelete.js'));
this.register(require('./GuildStickerCreate'));
this.register(require('./GuildStickerDelete'));
this.register(require('./GuildStickerUpdate'));
this.register(require('./GuildStickersUpdate'));
this.register(require('./GuildUpdate'));
this.register(require('./InteractionCreate'));
this.register(require('./InviteCreate'));
this.register(require('./InviteDelete'));
this.register(require('./MessageCreate'));
this.register(require('./MessageDelete'));
this.register(require('./MessageDeleteBulk'));
this.register(require('./MessagePollVoteAdd'));
this.register(require('./MessagePollVoteRemove'));
this.register(require('./MessageReactionAdd'));
this.register(require('./MessageReactionRemove'));
this.register(require('./MessageReactionRemoveAll'));
this.register(require('./MessageReactionRemoveEmoji'));
this.register(require('./MessageUpdate'));
this.register(require('./PresenceUpdate'));
this.register(require('./StageInstanceCreate'));
this.register(require('./StageInstanceDelete'));
this.register(require('./StageInstanceUpdate'));
this.register(require('./ThreadCreate'));
this.register(require('./ThreadDelete'));
this.register(require('./ThreadListSync'));
this.register(require('./ThreadMemberUpdate'));
this.register(require('./ThreadMembersUpdate'));
this.register(require('./TypingStart'));
this.register(require('./UserUpdate'));
this.register(require('./VoiceStateUpdate'));
this.register(require('./WebhooksUpdate'));
this.ApplicationCommandPermissionsUpdate = this.load(require('./ApplicationCommandPermissionsUpdate.js'));
this.AutoModerationActionExecution = this.load(require('./AutoModerationActionExecution.js'));
this.AutoModerationRuleCreate = this.load(require('./AutoModerationRuleCreate.js'));
this.AutoModerationRuleDelete = this.load(require('./AutoModerationRuleDelete.js'));
this.AutoModerationRuleUpdate = this.load(require('./AutoModerationRuleUpdate.js'));
this.ChannelCreate = this.load(require('./ChannelCreate.js'));
this.ChannelDelete = this.load(require('./ChannelDelete.js'));
this.ChannelUpdate = this.load(require('./ChannelUpdate.js'));
this.EntitlementCreate = this.load(require('./EntitlementCreate.js'));
this.EntitlementDelete = this.load(require('./EntitlementDelete.js'));
this.EntitlementUpdate = this.load(require('./EntitlementUpdate.js'));
this.GuildAuditLogEntryCreate = this.load(require('./GuildAuditLogEntryCreate.js'));
this.GuildBanAdd = this.load(require('./GuildBanAdd.js'));
this.GuildBanRemove = this.load(require('./GuildBanRemove.js'));
this.GuildChannelsPositionUpdate = this.load(require('./GuildChannelsPositionUpdate.js'));
this.GuildDelete = this.load(require('./GuildDelete.js'));
this.GuildEmojiCreate = this.load(require('./GuildEmojiCreate.js'));
this.GuildEmojiDelete = this.load(require('./GuildEmojiDelete.js'));
this.GuildEmojiUpdate = this.load(require('./GuildEmojiUpdate.js'));
this.GuildEmojisUpdate = this.load(require('./GuildEmojisUpdate.js'));
this.GuildIntegrationsUpdate = this.load(require('./GuildIntegrationsUpdate.js'));
this.GuildMemberRemove = this.load(require('./GuildMemberRemove.js'));
this.GuildMemberUpdate = this.load(require('./GuildMemberUpdate.js'));
this.GuildRoleCreate = this.load(require('./GuildRoleCreate.js'));
this.GuildRoleDelete = this.load(require('./GuildRoleDelete.js'));
this.GuildRoleUpdate = this.load(require('./GuildRoleUpdate.js'));
this.GuildRolesPositionUpdate = this.load(require('./GuildRolesPositionUpdate.js'));
this.GuildScheduledEventCreate = this.load(require('./GuildScheduledEventCreate.js'));
this.GuildScheduledEventDelete = this.load(require('./GuildScheduledEventDelete.js'));
this.GuildScheduledEventUpdate = this.load(require('./GuildScheduledEventUpdate.js'));
this.GuildScheduledEventUserAdd = this.load(require('./GuildScheduledEventUserAdd.js'));
this.GuildScheduledEventUserRemove = this.load(require('./GuildScheduledEventUserRemove.js'));
this.GuildSoundboardSoundDelete = this.load(require('./GuildSoundboardSoundDelete.js'));
this.GuildStickerCreate = this.load(require('./GuildStickerCreate.js'));
this.GuildStickerDelete = this.load(require('./GuildStickerDelete.js'));
this.GuildStickerUpdate = this.load(require('./GuildStickerUpdate.js'));
this.GuildStickersUpdate = this.load(require('./GuildStickersUpdate.js'));
this.GuildUpdate = this.load(require('./GuildUpdate.js'));
this.InteractionCreate = this.load(require('./InteractionCreate.js'));
this.InviteCreate = this.load(require('./InviteCreate.js'));
this.InviteDelete = this.load(require('./InviteDelete.js'));
this.MessageCreate = this.load(require('./MessageCreate.js'));
this.MessageDelete = this.load(require('./MessageDelete.js'));
this.MessageDeleteBulk = this.load(require('./MessageDeleteBulk.js'));
this.MessagePollVoteAdd = this.load(require('./MessagePollVoteAdd.js'));
this.MessagePollVoteRemove = this.load(require('./MessagePollVoteRemove.js'));
this.MessageReactionAdd = this.load(require('./MessageReactionAdd.js'));
this.MessageReactionRemove = this.load(require('./MessageReactionRemove.js'));
this.MessageReactionRemoveAll = this.load(require('./MessageReactionRemoveAll.js'));
this.MessageReactionRemoveEmoji = this.load(require('./MessageReactionRemoveEmoji.js'));
this.MessageUpdate = this.load(require('./MessageUpdate.js'));
this.PresenceUpdate = this.load(require('./PresenceUpdate.js'));
this.StageInstanceCreate = this.load(require('./StageInstanceCreate.js'));
this.StageInstanceDelete = this.load(require('./StageInstanceDelete.js'));
this.StageInstanceUpdate = this.load(require('./StageInstanceUpdate.js'));
this.ThreadCreate = this.load(require('./ThreadCreate.js'));
this.ThreadDelete = this.load(require('./ThreadDelete.js'));
this.ThreadListSync = this.load(require('./ThreadListSync.js'));
this.ThreadMemberUpdate = this.load(require('./ThreadMemberUpdate.js'));
this.ThreadMembersUpdate = this.load(require('./ThreadMembersUpdate.js'));
this.TypingStart = this.load(require('./TypingStart.js'));
this.UserUpdate = this.load(require('./UserUpdate.js'));
this.VoiceStateUpdate = this.load(require('./VoiceStateUpdate.js'));
this.WebhooksUpdate = this.load(require('./WebhooksUpdate.js'));
}
register(Action) {
this[Action.name.replace(/Action$/, '')] = new Action(this.client);
load(Action) {
return new Action(this.client);
}
}

View File

@@ -11,11 +11,18 @@ class MessagePollVoteAddAction extends Action {
const message = this.getMessage(data, channel);
if (!message) return false;
const { poll } = message;
const poll = this.getPoll(data, message, channel);
if (!poll) return false;
const answer = poll?.answers.get(data.answer_id);
const answer = poll.answers.get(data.answer_id);
if (!answer) return false;
const user = this.getUser(data);
if (user) {
answer.voters._add(user);
}
answer.voteCount++;
/**

View File

@@ -11,12 +11,17 @@ class MessagePollVoteRemoveAction extends Action {
const message = this.getMessage(data, channel);
if (!message) return false;
const { poll } = message;
const poll = this.getPoll(data, message, channel);
if (!poll) return false;
const answer = poll?.answers.get(data.answer_id);
const answer = poll.answers.get(data.answer_id);
if (!answer) return false;
answer.voteCount--;
answer.voters.cache.delete(data.user_id);
if (answer.voteCount > 0) {
answer.voteCount--;
}
/**
* Emitted whenever a user removes their vote in a poll.

View File

@@ -32,10 +32,10 @@ const handlers = Object.fromEntries([
['GUILD_SCHEDULED_EVENT_UPDATE', require('./GUILD_SCHEDULED_EVENT_UPDATE')],
['GUILD_SCHEDULED_EVENT_USER_ADD', require('./GUILD_SCHEDULED_EVENT_USER_ADD')],
['GUILD_SCHEDULED_EVENT_USER_REMOVE', require('./GUILD_SCHEDULED_EVENT_USER_REMOVE')],
['GUILD_SOUNDBOARD_SOUNDS_UPDATE', require('./GUILD_SOUNDBOARD_SOUNDS_UPDATE.js')],
['GUILD_SOUNDBOARD_SOUND_CREATE', require('./GUILD_SOUNDBOARD_SOUND_CREATE.js')],
['GUILD_SOUNDBOARD_SOUND_DELETE', require('./GUILD_SOUNDBOARD_SOUND_DELETE.js')],
['GUILD_SOUNDBOARD_SOUND_UPDATE', require('./GUILD_SOUNDBOARD_SOUND_UPDATE.js')],
['GUILD_SOUNDBOARD_SOUNDS_UPDATE', require('./GUILD_SOUNDBOARD_SOUNDS_UPDATE')],
['GUILD_SOUNDBOARD_SOUND_CREATE', require('./GUILD_SOUNDBOARD_SOUND_CREATE')],
['GUILD_SOUNDBOARD_SOUND_DELETE', require('./GUILD_SOUNDBOARD_SOUND_DELETE')],
['GUILD_SOUNDBOARD_SOUND_UPDATE', require('./GUILD_SOUNDBOARD_SOUND_UPDATE')],
['GUILD_STICKERS_UPDATE', require('./GUILD_STICKERS_UPDATE')],
['GUILD_UPDATE', require('./GUILD_UPDATE')],
['INTERACTION_CREATE', require('./INTERACTION_CREATE')],
@@ -54,7 +54,7 @@ const handlers = Object.fromEntries([
['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')],
['READY', require('./READY')],
['RESUMED', require('./RESUMED')],
['SOUNDBOARD_SOUNDS', require('./SOUNDBOARD_SOUNDS.js')],
['SOUNDBOARD_SOUNDS', require('./SOUNDBOARD_SOUNDS')],
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')],
['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')],
['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')],

View File

@@ -168,6 +168,8 @@
* @property {'ModalSubmitInteractionFieldNotFound'} ModalSubmitInteractionFieldNotFound
* @property {'ModalSubmitInteractionFieldType'} ModalSubmitInteractionFieldType
* @property {'ModalSubmitInteractionFieldEmpty'} ModalSubmitInteractionFieldEmpty
* @property {'ModalSubmitInteractionFieldInvalidChannelType'} ModalSubmitInteractionFieldInvalidChannelType
* @property {'InvalidMissingScopes'} InvalidMissingScopes
* @property {'InvalidScopesWithPermissions'} InvalidScopesWithPermissions
@@ -327,6 +329,8 @@ const keys = [
'ModalSubmitInteractionFieldNotFound',
'ModalSubmitInteractionFieldType',
'ModalSubmitInteractionFieldEmpty',
'ModalSubmitInteractionFieldInvalidChannelType',
'InvalidMissingScopes',
'InvalidScopesWithPermissions',

View File

@@ -161,6 +161,10 @@ const Messages = {
`Required field with custom id "${customId}" not found.`,
[DjsErrorCodes.ModalSubmitInteractionFieldType]: (customId, type, expected) =>
`Field with custom id "${customId}" is of type: ${type}; expected ${expected}.`,
[DjsErrorCodes.ModalSubmitInteractionFieldEmpty]: (customId, type) =>
`Required field with custom id "${customId}" is of type: ${type}; expected a non-empty value.`,
[DjsErrorCodes.ModalSubmitInteractionFieldInvalidChannelType]: (customId, type, expected) =>
`The type of channel of the field with custom id "${customId}" is: ${type}; expected ${expected}.`,
[DjsErrorCodes.InvalidMissingScopes]: 'At least one valid scope must be provided for the invite',
[DjsErrorCodes.InvalidScopesWithPermissions]: 'Permissions cannot be set without the bot scope.',

View File

@@ -33,6 +33,7 @@ exports.Events = require('./util/Events');
exports.Formatters = require('./util/Formatters');
exports.GuildMemberFlagsBitField = require('./util/GuildMemberFlagsBitField').GuildMemberFlagsBitField;
exports.IntentsBitField = require('./util/IntentsBitField');
exports.InviteFlagsBitField = require('./util/InviteFlagsBitField.js').InviteFlagsBitField;
exports.LimitedCollection = require('./util/LimitedCollection');
exports.MessageFlagsBitField = require('./util/MessageFlagsBitField');
exports.Options = require('./util/Options');
@@ -80,6 +81,7 @@ exports.GuildStickerManager = require('./managers/GuildStickerManager');
exports.GuildTextThreadManager = require('./managers/GuildTextThreadManager');
exports.MessageManager = require('./managers/MessageManager');
exports.PermissionOverwriteManager = require('./managers/PermissionOverwriteManager');
exports.PollAnswerVoterManager = require('./managers/PollAnswerVoterManager.js').PollAnswerVoterManager;
exports.PresenceManager = require('./managers/PresenceManager');
exports.ReactionManager = require('./managers/ReactionManager');
exports.ReactionUserManager = require('./managers/ReactionUserManager');
@@ -160,6 +162,7 @@ exports.InteractionWebhook = require('./structures/InteractionWebhook');
exports.Invite = require('./structures/Invite');
exports.InviteStageInstance = require('./structures/InviteStageInstance');
exports.InviteGuild = require('./structures/InviteGuild');
exports.LabelComponent = require('./structures/LabelComponent');
exports.Message = require('./structures/Message').Message;
exports.Attachment = require('./structures/Attachment');
exports.AttachmentBuilder = require('./structures/AttachmentBuilder');

View File

@@ -163,6 +163,7 @@ class GuildManager extends CachedManager {
* Creates a guild.
* <warn>This is only available to bots in fewer than 10 guilds.</warn>
* @param {GuildCreateOptions} options Options for creating the guild
* @deprecated API related to guild ownership may no longer be used.
* @returns {Promise<Guild>} The guild that was created
*/
async create({

View File

@@ -1,5 +1,6 @@
'use strict';
const { process } = require('node:process');
const { setTimeout, clearTimeout } = require('node:timers');
const { Collection } = require('@discordjs/collection');
const { makeURLSearchParams } = require('@discordjs/rest');
@@ -10,10 +11,13 @@ const { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } =
const BaseGuildVoiceChannel = require('../structures/BaseGuildVoiceChannel');
const { GuildMember } = require('../structures/GuildMember');
const { Role } = require('../structures/Role');
const { resolveImage } = require('../util/DataResolver');
const Events = require('../util/Events');
const { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField');
const Partials = require('../util/Partials');
let deprecatedEmittedForEditSoleNickname = false;
/**
* Manages API methods for GuildMembers and stores their cache.
* @extends {CachedManager}
@@ -336,8 +340,8 @@ class GuildMemberManager extends CachedManager {
*/
/**
* Edits a member of the guild.
* <info>The user must be a member of the guild</info>
* Edits a member of a guild.
*
* @param {UserResolvable} user The member to edit
* @param {GuildMemberEditOptions} options The options to provide
* @returns {Promise<GuildMember>}
@@ -372,13 +376,30 @@ class GuildMemberManager extends CachedManager {
}
let endpoint;
if (id === this.client.user.id) {
const keys = Object.keys(options);
if (keys.length === 1 && keys[0] === 'nick') endpoint = Routes.guildMember(this.guild.id);
else endpoint = Routes.guildMember(this.guild.id, id);
} else {
endpoint = Routes.guildMember(this.guild.id, id);
if (keys.length === 1 && keys[0] === 'nick') {
// For modifying the current application's nickname only, we use the /guilds/{guild.id}/members/@me endpoint.
// This endpoint only requires the CHANGE_NICKNAME permission.
// The other endpoint would require the MANAGE_NICKNAMES permission.
// In v15, this will be split out, so emit a deprecation.
endpoint = Routes.guildMember(this.guild.id, '@me');
if (!deprecatedEmittedForEditSoleNickname) {
process.emitWarning(
// eslint-disable-next-line max-len
"You should use GuildMemberManager#editMe() when changing your nickname. Due to Discord's API changes, GuildMemberManager#edit() will end up requiring MANAGE_NICKNAMES in v15.",
'DeprecationWarning',
);
deprecatedEmittedForEditSoleNickname = true;
}
}
}
endpoint ??= Routes.guildMember(this.guild.id, id);
const d = await this.client.rest.patch(endpoint, { body: options, reason });
const clone = this.cache.get(id)?._clone();
@@ -386,6 +407,38 @@ class GuildMemberManager extends CachedManager {
return clone ?? this._add(d, false);
}
/**
* The data for editing the current application's guild member.
*
* @typedef {Object} GuildMemberEditMeOptions
* @property {?string} [nick] The nickname to set
* @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner to set
* @property {?(BufferResolvable|Base64Resolvable)} [avatar] The avatar to set
* @property {?string} [bio] The bio to set
* @property {string} [reason] The reason to use
*/
/**
* Edits the current application's guild member in a guild.
*
* @param {GuildMemberEditMeOptions} options The options to provide
* @returns {Promise<GuildMember>}
*/
async editMe({ reason, ...options }) {
const data = await this.client.rest.patch(Routes.guildMember(this.guild.id, '@me'), {
body: {
...options,
banner: options.banner && (await resolveImage(options.banner)),
avatar: options.avatar && (await resolveImage(options.avatar)),
},
reason,
});
const clone = this.me?._clone();
clone?._patch(data);
return clone ?? this._add(data, false);
}
/**
* Options used for pruning guild members.
* <info>It's recommended to set {@link GuildPruneMembersOptions#count options.count}

View File

@@ -0,0 +1,50 @@
'use strict';
const { Collection } = require('@discordjs/collection');
const { makeURLSearchParams } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v10');
const CachedManager = require('./CachedManager.js');
const User = require('../structures/User.js');
/**
* Manages API methods for users who voted on a poll and stores their cache.
* @extends {CachedManager}
*/
class PollAnswerVoterManager extends CachedManager {
constructor(answer) {
super(answer.client, User);
/**
* The poll answer that this manager belongs to
* @type {PollAnswer}
*/
this.answer = answer;
}
/**
* The cache of this manager
* @type {Collection<Snowflake, User>}
* @name PollAnswerVoterManager#cache
*/
/**
* Fetches the users that voted on this poll answer. Resolves with a collection of users, mapped by their ids.
* @param {BaseFetchPollAnswerVotersOptions} [options={}] Options for fetching the users
* @returns {Promise<Collection<Snowflake, User>>}
*/
async fetch({ after, limit } = {}) {
const poll = this.answer.poll;
const query = makeURLSearchParams({ limit, after });
const data = await this.client.rest.get(Routes.pollAnswerVoters(poll.channelId, poll.messageId, this.answer.id), {
query,
});
return data.users.reduce((coll, rawUser) => {
const user = this.client.users._add(rawUser);
this.cache.set(user.id, user);
return coll.set(user.id, user);
}, new Collection());
}
}
exports.PollAnswerVoterManager = PollAnswerVoterManager;

View File

@@ -73,7 +73,7 @@ class ApplicationCommand extends Base {
if ('name_localizations' in data) {
/**
* The name localizations for this command
* @type {?Object<Locale, string>}
* @type {?LocalizationMap}
*/
this.nameLocalizations = data.name_localizations;
} else {
@@ -101,7 +101,7 @@ class ApplicationCommand extends Base {
if ('description_localizations' in data) {
/**
* The description localizations for this command
* @type {?Object<Locale, string>}
* @type {?LocalizationMap}
*/
this.descriptionLocalizations = data.description_localizations;
} else {
@@ -227,11 +227,11 @@ class ApplicationCommand extends Base {
* @typedef {Object} ApplicationCommandData
* @property {string} name The name of the command, must be in all lowercase if type is
* {@link ApplicationCommandType.ChatInput}
* @property {Object<Locale, string>} [nameLocalizations] The localizations for the command name
* @property {LocalizationMap} [nameLocalizations] The localizations for the command name
* @property {string} description The description of the command,
* if type is {@link ApplicationCommandType.ChatInput} or {@link ApplicationCommandType.PrimaryEntryPoint}
* @property {boolean} [nsfw] Whether the command is age-restricted
* @property {Object<Locale, string>} [descriptionLocalizations] The localizations for the command description,
* @property {LocalizationMap} [descriptionLocalizations] The localizations for the command description,
* if type is {@link ApplicationCommandType.ChatInput} or {@link ApplicationCommandType.PrimaryEntryPoint}
* @property {ApplicationCommandType} [type=ApplicationCommandType.ChatInput] The type of the command
* @property {ApplicationCommandOptionData[]} [options] Options for the command
@@ -253,9 +253,9 @@ class ApplicationCommand extends Base {
* @typedef {Object} ApplicationCommandOptionData
* @property {ApplicationCommandOptionType} type The type of the option
* @property {string} name The name of the option
* @property {Object<Locale, string>} [nameLocalizations] The name localizations for the option
* @property {LocalizationMap} [nameLocalizations] The name localizations for the option
* @property {string} description The description of the option
* @property {Object<Locale, string>} [descriptionLocalizations] The description localizations for the option
* @property {LocalizationMap} [descriptionLocalizations] The description localizations for the option
* @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a
* {@link ApplicationCommandOptionType.String}, {@link ApplicationCommandOptionType.Integer} or
* {@link ApplicationCommandOptionType.Number} option
@@ -277,7 +277,7 @@ class ApplicationCommand extends Base {
/**
* @typedef {Object} ApplicationCommandOptionChoiceData
* @property {string} name The name of the choice
* @property {Object<Locale, string>} [nameLocalizations] The localized names for this choice
* @property {LocalizationMap} [nameLocalizations] The localized names for this choice
* @property {string|number} value The value of the choice
*/
@@ -308,7 +308,7 @@ class ApplicationCommand extends Base {
/**
* Edits the localized names of this ApplicationCommand
* @param {Object<Locale, string>} nameLocalizations The new localized names for the command
* @param {LocalizationMap} nameLocalizations The new localized names for the command
* @returns {Promise<ApplicationCommand>}
* @example
* // Edit the name localizations of this command
@@ -334,7 +334,7 @@ class ApplicationCommand extends Base {
/**
* Edits the localized descriptions of this ApplicationCommand
* @param {Object<Locale, string>} descriptionLocalizations The new localized descriptions for the command
* @param {LocalizationMap} descriptionLocalizations The new localized descriptions for the command
* @returns {Promise<ApplicationCommand>}
* @example
* // Edit the description localizations of this command
@@ -550,10 +550,10 @@ class ApplicationCommand extends Base {
* @typedef {Object} ApplicationCommandOption
* @property {ApplicationCommandOptionType} type The type of the option
* @property {string} name The name of the option
* @property {Object<Locale, string>} [nameLocalizations] The localizations for the option name
* @property {LocalizationMap} [nameLocalizations] The localizations for the option name
* @property {string} [nameLocalized] The localized name for this option
* @property {string} description The description of the option
* @property {Object<Locale, string>} [descriptionLocalizations] The localizations for the option description
* @property {LocalizationMap} [descriptionLocalizations] The localizations for the option description
* @property {string} [descriptionLocalized] The localized description for this option
* @property {boolean} [required] Whether the option is required
* @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a

View File

@@ -13,7 +13,7 @@ class ApplicationRoleConnectionMetadata {
/**
* The name localizations for this metadata field
* @type {?Object<Locale, string>}
* @type {?LocalizationMap}
*/
this.nameLocalizations = data.name_localizations ?? null;
@@ -25,7 +25,7 @@ class ApplicationRoleConnectionMetadata {
/**
* The description localizations for this metadata field
* @type {?Object<Locale, string>}
* @type {?LocalizationMap}
*/
this.descriptionLocalizations = data.description_localizations ?? null;

View File

@@ -375,9 +375,9 @@ class ClientApplication extends Application {
* Data for creating or editing an application role connection metadata.
* @typedef {Object} ApplicationRoleConnectionMetadataEditOptions
* @property {string} name The name of the metadata field
* @property {?Object<Locale, string>} [nameLocalizations] The name localizations for the metadata field
* @property {?LocalizationMap} [nameLocalizations] The name localizations for the metadata field
* @property {string} description The description of the metadata field
* @property {?Object<Locale, string>} [descriptionLocalizations] The description localizations for the metadata field
* @property {?LocalizationMap} [descriptionLocalizations] The description localizations for the metadata field
* @property {string} key The dictionary key of the metadata field
* @property {ApplicationRoleConnectionMetadataType} type The type of the metadata field
*/

View File

@@ -80,12 +80,17 @@ class CommandInteraction extends BaseInteraction {
}
/**
* Represents the resolved data of a received command interaction.
* @typedef {Object} CommandInteractionResolvedData
* @typedef {Object} BaseInteractionResolvedData
* @property {Collection<Snowflake, User>} [users] The resolved users
* @property {Collection<Snowflake, GuildMember|APIGuildMember>} [members] The resolved guild members
* @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles
* @property {Collection<Snowflake, BaseChannel|APIChannel>} [channels] The resolved channels
*/
/**
* Represents the resolved data of a received command interaction.
*
* @typedef {BaseInteractionResolvedData} CommandInteractionResolvedData
* @property {Collection<Snowflake, Message|APIMessage>} [messages] The resolved messages
* @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments
*/

View File

@@ -832,6 +832,7 @@ class Guild extends AnonymousGuild {
* @property {number} [afkTimeout] The AFK timeout of the guild
* @property {?(BufferResolvable|Base64Resolvable)} [icon] The icon of the guild
* @property {GuildMemberResolvable} [owner] The owner of the guild
* <warn>This property is **deprecated** as API related to guild ownership may no longer be used.</warn>
* @property {?(BufferResolvable|Base64Resolvable)} [splash] The invite splash image of the guild
* @property {?(BufferResolvable|Base64Resolvable)} [discoverySplash] The discovery splash image of the guild
* @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner of the guild
@@ -1197,12 +1198,7 @@ class Guild extends AnonymousGuild {
* @param {GuildMemberResolvable} owner The new owner of the guild
* @param {string} [reason] Reason for setting the new owner
* @returns {Promise<Guild>}
* @example
* // Edit the guild owner
* guild.setOwner(guild.members.cache.first())
* .then(guild => guild.fetchOwner())
* .then(owner => console.log(`Updated the guild owner to ${owner.displayName}`))
* .catch(console.error);
* @deprecated API related to guild ownership may no longer be used.
*/
setOwner(owner, reason) {
return this.edit({ owner, reason });
@@ -1345,11 +1341,7 @@ class Guild extends AnonymousGuild {
* @param {GuildMFALevel} level The MFA level
* @param {string} [reason] Reason for changing the guild's MFA level
* @returns {Promise<Guild>}
* @example
* // Set the MFA level of the guild to Elevated
* guild.setMFALevel(GuildMFALevel.Elevated)
* .then(guild => console.log("Set guild's MFA level to Elevated"))
* .catch(console.error);
* @deprecated API related to guild ownership may no longer be used.
*/
async setMFALevel(level, reason) {
await this.client.rest.post(Routes.guildMFA(this.id), {
@@ -1379,6 +1371,7 @@ class Guild extends AnonymousGuild {
/**
* Deletes the guild.
* @returns {Promise<Guild>}
* @deprecated API related to guild ownership may no longer be used.
* @example
* // Delete a guild
* guild.delete()

View File

@@ -250,10 +250,11 @@ class GuildChannel extends BaseChannel {
return new PermissionsBitField(PermissionsBitField.All).freeze();
}
const basePermissions = new PermissionsBitField([role.permissions, role.guild.roles.everyone.permissions]);
const everyoneOverwrites = this.permissionOverwrites.cache.get(this.guild.id);
const roleOverwrites = this.permissionOverwrites.cache.get(role.id);
return role.permissions
return basePermissions
.remove(everyoneOverwrites?.deny ?? PermissionsBitField.DefaultBit)
.add(everyoneOverwrites?.allow ?? PermissionsBitField.DefaultBit)
.remove(roleOverwrites?.deny ?? PermissionsBitField.DefaultBit)

View File

@@ -422,7 +422,9 @@ class GuildMember extends Base {
* .catch(console.error);
*/
setNickname(nick, reason) {
return this.edit({ nick, reason });
return this.user.id === this.client.user.id
? this.guild.members.editMe({ nick, reason })
: this.edit({ nick, reason });
}
/**

View File

@@ -120,6 +120,7 @@ class GuildTemplate extends Base {
* @param {string} name The name of the guild
* @param {BufferResolvable|Base64Resolvable} [icon] The icon for the guild
* @returns {Promise<Guild>}
* @deprecated API related to guild ownership may no longer be used.
*/
async createGuild(name, icon) {
const { client } = this;

View File

@@ -6,6 +6,7 @@ const { GuildScheduledEvent } = require('./GuildScheduledEvent');
const IntegrationApplication = require('./IntegrationApplication');
const InviteStageInstance = require('./InviteStageInstance');
const { DiscordjsError, ErrorCodes } = require('../errors');
const { InviteFlagsBitField } = require('../util/InviteFlagsBitField.js');
/**
* Represents an invitation to a guild channel.
@@ -222,6 +223,17 @@ class Invite extends Base {
} else {
this.guildScheduledEvent ??= null;
}
if ('flags' in data) {
/**
* The flags of this invite.
*
* @type {Readonly<InviteFlagsBitField>}
*/
this.flags = new InviteFlagsBitField(data.flags).freeze();
} else {
this.flags ??= new InviteFlagsBitField().freeze();
}
}
/**

View File

@@ -0,0 +1,54 @@
'use strict';
const Component = require('./Component');
const { createComponent } = require('../util/Components');
/**
* Represents a label component
*
* @extends {Component}
*/
class LabelComponent extends Component {
constructor({ component, ...data }) {
super(data);
/**
* The component in this label
*
* @type {Component}
* @readonly
*/
this.component = createComponent(component);
}
/**
* The label of the component
*
* @type {string}
* @readonly
*/
get label() {
return this.data.label;
}
/**
* The description of this component
*
* @type {?string}
* @readonly
*/
get description() {
return this.data.description ?? null;
}
/**
* Returns the API-compatible JSON for this component
*
* @returns {APILabelComponent}
*/
toJSON() {
return { ...this.data, component: this.component.toJSON() };
}
}
module.exports = LabelComponent;

View File

@@ -442,11 +442,15 @@ class Message extends Base {
}
if (data.poll) {
/**
* The poll that was sent with the message
* @type {?Poll}
*/
this.poll = new Poll(this.client, data.poll, this);
if (this.poll) {
this.poll._patch(data.poll);
} else {
/**
* The poll that was sent with the message
* @type {?Poll}
*/
this.poll = new Poll(this.client, data.poll, this, this.channel);
}
} else {
this.poll ??= null;
}
@@ -619,7 +623,7 @@ class Message extends Base {
* Similar to createReactionCollector but in promise form.
* Resolves with a collection of reactions that pass the specified filter.
* @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
* @returns {Promise<Collection<string | Snowflake, MessageReaction>>}
* @returns {Promise<Collection<string|Snowflake, MessageReaction>>}
* @example
* // Create a reaction collector
* const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId'

View File

@@ -4,23 +4,48 @@ const { Collection } = require('@discordjs/collection');
const { ComponentType } = require('discord-api-types/v10');
const { DiscordjsTypeError, ErrorCodes } = require('../errors');
/**
* @typedef {Object} ModalSelectedMentionables
* @property {Collection<Snowflake, User>} users The selected users
* @property {Collection<Snowflake, GuildMember | APIGuildMember>} members The selected members
* @property {Collection<Snowflake, Role | APIRole>} roles The selected roles
*/
/**
* Represents the serialized fields from a modal submit interaction
*/
class ModalSubmitFields {
constructor(components) {
constructor(components, resolved) {
/**
* The components within the modal
* @type {ActionRowModalData[]}
*
* @type {Array<ActionRowModalData|LabelModalData|TextDisplayModalData>}
*/
this.components = components;
/**
* The interaction resolved data
*
* @name ModalSubmitFields#resolved
* @type {?Readonly<BaseInteractionResolvedData>}
*/
Object.defineProperty(this, 'resolved', { value: resolved ? Object.freeze(resolved) : null });
/**
* The extracted fields from the modal
* @type {Collection<string, ModalData>}
*/
this.fields = components.reduce((accumulator, next) => {
next.components.forEach(component => accumulator.set(component.customId, component));
// For legacy support of action rows
if ('components' in next) {
for (const component of next.components) accumulator.set(component.customId, component);
}
// For label components
if ('component' in next) {
accumulator.set(next.component.customId, next.component);
}
return accumulator;
}, new Collection());
}
@@ -42,13 +67,154 @@ class ModalSubmitFields {
return field;
}
/**
* Gets a component by custom id and property and checks its type.
*
* @param {string} customId The custom id of the component.
* @param {ComponentType[]} allowedTypes The allowed types of the component.
* @param {string[]} properties The properties to check for for `required`.
* @param {boolean} required Whether to throw an error if the component value(s) are not found.
* @returns {ModalData} The option, if found.
* @private
*/
_getTypedComponent(customId, allowedTypes, properties, required) {
const component = this.getField(customId);
if (!allowedTypes.includes(component.type)) {
throw new DiscordjsTypeError(
ErrorCodes.ModalSubmitInteractionFieldNotFound,
customId,
component.type,
allowedTypes.join(', '),
);
} else if (required && properties.every(prop => component[prop] === null || component[prop] === undefined)) {
throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionFieldEmpty, customId, component.type);
}
return component;
}
/**
* Gets the value of a text input component given a custom id
* @param {string} customId The custom id of the text input component
* @returns {string}
*/
getTextInputValue(customId) {
return this.getField(customId, ComponentType.TextInput).value;
return this._getTypedComponent(customId, [ComponentType.TextInput]).value;
}
/**
* Gets the values of a string select component given a custom id
*
* @param {string} customId The custom id of the string select component
* @returns {string[]}
*/
getStringSelectValues(customId) {
return this._getTypedComponent(customId, [ComponentType.StringSelect]).values;
}
/**
* Gets users component
*
* @param {string} customId The custom id of the component
* @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty
* @returns {?Collection<Snowflake, User>} The selected users, or null if none were selected and not required
*/
getSelectedUsers(customId, required = false) {
const component = this._getTypedComponent(
customId,
[ComponentType.UserSelect, ComponentType.MentionableSelect],
['users'],
required,
);
return component.users ?? null;
}
/**
* Gets roles component
*
* @param {string} customId The custom id of the component
* @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty
* @returns {?Collection<Snowflake, Role|APIRole>} The selected roles, or null if none were selected and not required
*/
getSelectedRoles(customId, required = false) {
const component = this._getTypedComponent(
customId,
[ComponentType.RoleSelect, ComponentType.MentionableSelect],
['roles'],
required,
);
return component.roles ?? null;
}
/**
* Gets channels component
*
* @param {string} customId The custom id of the component
* @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty
* @param {ChannelType[]} [channelTypes=[]] The allowed types of channels. If empty, all channel types are allowed.
* @returns {?Collection<Snowflake, GuildChannel|ThreadChannel|APIChannel>} The selected channels,
* or null if none were selected and not required
*/
getSelectedChannels(customId, required = false, channelTypes = []) {
const component = this._getTypedComponent(customId, [ComponentType.ChannelSelect], ['channels'], required);
const channels = component.channels;
if (channels && channelTypes.length > 0) {
for (const channel of channels.values()) {
if (!channelTypes.includes(channel.type)) {
throw new DiscordjsTypeError(
ErrorCodes.ModalSubmitInteractionComponentInvalidChannelType,
customId,
channel.type,
channelTypes.join(', '),
);
}
}
}
return channels ?? null;
}
/**
* Gets members component
*
* @param {string} customId The custom id of the component
* @returns {?Collection<Snowflake, GuildMember|APIGuildMember>} The selected members,
* or null if none were selected or the users were not present in the guild
*/
getSelectedMembers(customId) {
const component = this._getTypedComponent(
customId,
[ComponentType.UserSelect, ComponentType.MentionableSelect],
['members'],
false,
);
return component.members ?? null;
}
/**
* Gets mentionables component
*
* @param {string} customId The custom id of the component
* @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty
* @returns {?ModalSelectedMentionables} The selected mentionables, or null if none were selected and not required
*/
getSelectedMentionables(customId, required = false) {
const component = this._getTypedComponent(
customId,
[ComponentType.MentionableSelect],
['users', 'members', 'roles'],
required,
);
if (component.users || component.members || component.roles) {
return {
users: component.users ?? new Collection(),
members: component.members ?? new Collection(),
roles: component.roles ?? new Collection(),
};
}
return null;
}
}

View File

@@ -1,24 +1,53 @@
'use strict';
const { Collection } = require('@discordjs/collection');
const { lazy } = require('@discordjs/util');
const BaseInteraction = require('./BaseInteraction');
const InteractionWebhook = require('./InteractionWebhook');
const ModalSubmitFields = require('./ModalSubmitFields');
const InteractionResponses = require('./interfaces/InteractionResponses');
const { transformResolved } = require('../util/Util');
const getMessage = lazy(() => require('./Message').Message);
/**
* @typedef {Object} ModalData
* @property {string} value The value of the field
* @typedef {Object} BaseModalData
* @property {ComponentType} type The component type of the field
* @property {string} customId The custom id of the field
* @property {number} id The id of the field
*/
/**
* @typedef {Object} ActionRowModalData
* @property {ModalData[]} components The components of this action row
* @property {ComponentType} type The component type of the action row
* @typedef {BaseModalData} TextInputModalData
* @property {string} customId The custom id of the field
* @property {string} value The value of the field
*/
/**
* @typedef {BaseModalData} SelectMenuModalData
* @property {string} customId The custom id of the field
* @property {string[]} values The values of the field
* @property {Collection<string, GuildMember|APIGuildMember>} [members] The resolved members
* @property {Collection<string, User|APIUser>} [users] The resolved users
* @property {Collection<string, Role|APIRole>} [roles] The resolved roles
* @property {Collection<string, BaseChannel|APIChannel>} [channels] The resolved channels
*/
/**
* @typedef {BaseModalData} TextDisplayModalData
*/
/**
* @typedef {SelectMenuModalData|TextInputModalData} ModalData
*/
/**
* @typedef {BaseModalData} LabelModalData
* @property {ModalData} component The component within the label
*/
/**
* @typedef {BaseModalData} ActionRowModalData
* @property {TextInputModalData[]} components The components of this action row
*/
/**
@@ -47,15 +76,21 @@ class ModalSubmitInteraction extends BaseInteraction {
/**
* The components within the modal
* @type {ActionRowModalData[]}
*
* @type {Array<ActionRowModalData | LabelModalData | TextDisplayModalData>}
*/
this.components = data.data.components?.map(component => ModalSubmitInteraction.transformComponent(component));
this.components = data.data.components?.map(component =>
ModalSubmitInteraction.transformComponent(component, data.data.resolved),
);
/**
* The fields within the modal
* @type {ModalSubmitFields}
*/
this.fields = new ModalSubmitFields(this.components);
this.fields = new ModalSubmitFields(
this.components,
transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved),
);
/**
* Whether the reply to this interaction has been deferred
@@ -85,19 +120,68 @@ class ModalSubmitInteraction extends BaseInteraction {
/**
* Transforms component data to discord.js-compatible data
* @param {*} rawComponent The data to transform
* @param {APIInteractionDataResolved} [resolved] The resolved data for the interaction
* @returns {ModalData[]}
*/
static transformComponent(rawComponent) {
return rawComponent.components
? {
type: rawComponent.type,
components: rawComponent.components.map(component => this.transformComponent(component)),
}
: {
value: rawComponent.value,
type: rawComponent.type,
customId: rawComponent.custom_id,
static transformComponent(rawComponent, resolved) {
if ('components' in rawComponent) {
return {
type: rawComponent.type,
id: rawComponent.id,
components: rawComponent.components.map(component => this.transformComponent(component, resolved)),
};
}
if ('component' in rawComponent) {
return {
type: rawComponent.type,
id: rawComponent.id,
component: this.transformComponent(rawComponent.component, resolved),
};
}
const data = {
type: rawComponent.type,
id: rawComponent.id,
};
// Text display components do not have custom ids.
if ('custom_id' in rawComponent) data.customId = rawComponent.custom_id;
if ('value' in rawComponent) data.value = rawComponent.value;
if (rawComponent.values) {
data.values = rawComponent.values;
if (resolved) {
const resolveCollection = (resolvedData, resolver) => {
const collection = new Collection();
for (const value of data.values) {
if (resolvedData?.[value]) {
collection.set(value, resolver(resolvedData[value]));
}
}
return collection.size ? collection : null;
};
const users = resolveCollection(resolved.users, user => this.client.users._add(user));
if (users) data.users = users;
const channels = resolveCollection(
resolved.channels,
channel => this.client.channels._add(channel, this.guild) ?? channel,
);
if (channels) data.channels = channels;
const members = resolveCollection(resolved.members, member => this.guild?.members._add(member) ?? member);
if (members) data.members = members;
const roles = resolveCollection(resolved.roles, role => this.guild?.roles._add(role) ?? role);
if (roles) data.roles = roles;
}
}
return data;
}
/**

View File

@@ -11,9 +11,30 @@ const { ErrorCodes } = require('../errors/index');
* @extends {Base}
*/
class Poll extends Base {
constructor(client, data, message) {
constructor(client, data, message, channel) {
super(client);
/**
* The id of the channel that this poll is in
* @type {Snowflake}
*/
this.channelId = data.channel_id ?? channel.id;
/**
* The channel that this poll is in
* @name Poll#channel
* @type {TextBasedChannel}
* @readonly
*/
Object.defineProperty(this, 'channel', { value: channel });
/**
* The id of the message that started this poll
* @type {Snowflake}
*/
this.messageId = data.message_id ?? message.id;
/**
* The message that started this poll
* @name Poll#message
@@ -23,51 +44,27 @@ class Poll extends Base {
Object.defineProperty(this, 'message', { value: message });
/**
* The media for a poll's question
* @typedef {Object} PollQuestionMedia
* @property {string} text The text of this question
*/
/**
* The media for this poll's question
* @type {PollQuestionMedia}
*/
this.question = {
text: data.question.text,
};
/**
* The answers of this poll
* @type {Collection<number, PollAnswer>}
* @type {Collection<number, PollAnswer|PartialPollAnswer>}
*/
this.answers = data.answers.reduce(
(acc, answer) => acc.set(answer.answer_id, new PollAnswer(this.client, answer, this)),
new Collection(),
);
/**
* The timestamp when this poll expires
* @type {number}
*/
this.expiresTimestamp = Date.parse(data.expiry);
/**
* Whether this poll allows multiple answers
* @type {boolean}
*/
this.allowMultiselect = data.allow_multiselect;
/**
* The layout type of this poll
* @type {PollLayoutType}
*/
this.layoutType = data.layout_type;
this.answers = new Collection();
this._patch(data);
}
_patch(data) {
if (data.answers) {
for (const answer of data.answers) {
const existing = this.answers.get(answer.answer_id);
if (existing) {
existing._patch(answer);
} else {
this.answers.set(answer.answer_id, new PollAnswer(this.client, answer, this));
}
}
}
if (data.results) {
/**
* Whether this poll's results have been precisely counted
@@ -82,15 +79,84 @@ class Poll extends Base {
} else {
this.resultsFinalized ??= false;
}
if ('allow_multiselect' in data) {
/**
* Whether this poll allows multiple answers
* @type {boolean}
*/
this.allowMultiselect = data.allow_multiselect;
} else {
this.allowMultiselect ??= null;
}
if ('layout_type' in data) {
/**
* The layout type of this poll
* @type {PollLayoutType}
*/
this.layoutType = data.layout_type;
} else {
this.layoutType ??= null;
}
if ('expiry' in data) {
/**
* The timestamp when this poll expires
* @type {?number}
*/
this.expiresTimestamp = data.expiry && Date.parse(data.expiry);
} else {
this.expiresTimestamp ??= null;
}
if (data.question) {
/**
* The media for a poll's question
* @typedef {Object} PollQuestionMedia
* @property {?string} text The text of this question
*/
/**
* The media for this poll's question
* @type {PollQuestionMedia}
*/
this.question = {
text: data.question.text,
};
} else {
this.question ??= {
text: null,
};
}
}
/**
* The date when this poll expires
* @type {Date}
* @type {?Date}
* @readonly
*/
get expiresAt() {
return new Date(this.expiresTimestamp);
return this.expiresTimestamp && new Date(this.expiresTimestamp);
}
/**
* Whether this poll is a partial
* @type {boolean}
* @readonly
*/
get partial() {
return this.allowMultiselect === null;
}
/**
* Fetches the message that started this poll, then updates the poll from the fetched message.
* @returns {Promise<Poll>}
*/
async fetch() {
await this.channel.messages.fetch(this.messageId);
return this;
}
/**
@@ -102,7 +168,7 @@ class Poll extends Base {
throw new DiscordjsError(ErrorCodes.PollAlreadyExpired);
}
return this.message.channel.messages.endPoll(this.message.id);
return this.channel.messages.endPoll(this.messageId);
}
}

View File

@@ -1,7 +1,11 @@
'use strict';
const Base = require('./Base');
const { Emoji } = require('./Emoji');
const process = require('node:process');
const Base = require('./Base.js');
const { Emoji } = require('./Emoji.js');
const { PollAnswerVoterManager } = require('../managers/PollAnswerVoterManager.js');
let deprecationEmittedForFetchVoters = false;
/**
* Represents an answer to a {@link Poll}
@@ -14,7 +18,7 @@ class PollAnswer extends Base {
/**
* The {@link Poll} this answer is part of
* @name PollAnswer#poll
* @type {Poll}
* @type {Poll|PartialPoll}
* @readonly
*/
Object.defineProperty(this, 'poll', { value: poll });
@@ -26,10 +30,10 @@ class PollAnswer extends Base {
this.id = data.answer_id;
/**
* The text of this answer
* @type {?string}
* The manager of the voters for this answer
* @type {PollAnswerVoterManager}
*/
this.text = data.poll_media.text ?? null;
this.voters = new PollAnswerVoterManager(this);
/**
* The raw emoji of this answer
@@ -37,7 +41,7 @@ class PollAnswer extends Base {
* @type {?APIPartialEmoji}
* @private
*/
Object.defineProperty(this, '_emoji', { value: data.poll_media.emoji ?? null });
Object.defineProperty(this, '_emoji', { value: null, writable: true });
this._patch(data);
}
@@ -51,7 +55,17 @@ class PollAnswer extends Base {
*/
this.voteCount = data.count;
} else {
this.voteCount ??= 0;
this.voteCount ??= this.voters.cache.size;
}
/**
* The text of this answer
* @type {?string}
*/
this.text ??= data.poll_media?.text ?? null;
if (data.poll_media?.emoji) {
this._emoji = data.poll_media.emoji;
}
}
@@ -64,6 +78,15 @@ class PollAnswer extends Base {
return this.client.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji);
}
/**
* Whether this poll answer is a partial.
* @type {boolean}
* @readonly
*/
get partial() {
return this.poll.partial || (this.text === null && this.emoji === null);
}
/**
* Options used for fetching voters of a poll answer.
* @typedef {Object} BaseFetchPollAnswerVotersOptions
@@ -75,14 +98,16 @@ class PollAnswer extends Base {
* Fetches the users that voted for this answer.
* @param {BaseFetchPollAnswerVotersOptions} [options={}] The options for fetching voters
* @returns {Promise<Collection<Snowflake, User>>}
* @deprecated Use {@link PollAnswerVoterManager#fetch} instead
*/
fetchVoters({ after, limit } = {}) {
return this.poll.message.channel.messages.fetchPollAnswerVoters({
messageId: this.poll.message.id,
answerId: this.id,
after,
limit,
});
if (!deprecationEmittedForFetchVoters) {
process.emitWarning('PollAnswer#fetchVoters is deprecated. Use PollAnswer#voters#fetch instead.');
deprecationEmittedForFetchVoters = true;
}
return this.voters.fetch({ after, limit });
}
}

View File

@@ -267,7 +267,11 @@ class User extends Base {
* @readonly
*/
get defaultAvatarURL() {
const index = this.discriminator === '0' ? calculateUserDefaultAvatarIndex(this.id) : this.discriminator % 5;
const index =
this.discriminator === '0' || this.discriminator === '0000'
? calculateUserDefaultAvatarIndex(this.id)
: this.discriminator % 5;
return this.client.rest.cdn.defaultAvatar(index);
}
@@ -322,7 +326,7 @@ class User extends Base {
*/
get tag() {
return typeof this.username === 'string'
? this.discriminator === '0'
? this.discriminator === '0' || this.discriminator === '0000'
? this.username
: `${this.username}#${this.discriminator}`
: null;

View File

@@ -15,13 +15,6 @@ const MessagePayload = require('../MessagePayload');
let deprecationEmittedForEphemeralOption = false;
let deprecationEmittedForFetchReplyOption = false;
/**
* @typedef {Object} ModalComponentData
* @property {string} title The title of the modal
* @property {string} customId The custom id of the modal
* @property {ActionRow[]} components The components within this modal
*/
/**
* Interface for classes that support shared interaction response types.
* @interface

View File

@@ -245,6 +245,11 @@
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuOption}
*/
/**
* @external APISelectMenuDefaultValue
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuDefaultValue}
*/
/**
* @external APISticker
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISticker}
@@ -515,6 +520,11 @@
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionResponseType}
*/
/**
* @external InviteFlags
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InviteFlags}
*/
/**
* @external InviteType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InviteType}
@@ -530,6 +540,11 @@
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/Locale}
*/
/**
* @external LocalizationMap
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#LocalizationMap}
*/
/**
* @external MessageActivityType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageActivityType}
@@ -645,6 +660,11 @@
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ThreadAutoArchiveDuration}
*/
/**
* @external ThreadMemberFlags
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ThreadMemberFlags}
*/
/**
* @external UserFlags
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/UserFlags}

View File

@@ -14,6 +14,25 @@ const { ComponentType } = require('discord-api-types/v10');
* @property {ComponentData[]} components The components in this action row
*/
/**
* @typedef {Object} ModalComponentData
* @property {string} title The title of the modal
* @property {string} customId The custom id of the modal
* @property {Array<ActionRow|TextDisplayComponentData|LabelData>} components The components within this modal
*/
/**
* @typedef {StringSelectMenuComponentData|TextInputComponentData|UserSelectMenuComponentData|
* RoleSelectMenuComponentData|MentionableSelectMenuComponentData|ChannelSelectMenuComponentData} ComponentInLabelData
*/
/**
* @typedef {BaseComponentData} LabelData
* @property {string} label The label to use
* @property {string} [description] The optional description for the label
* @property {ComponentInLabelData} component The component within the label
*/
/**
* @typedef {BaseComponentData} ButtonComponentData
* @property {ButtonStyle} style The style of the button
@@ -24,6 +43,42 @@ const { ComponentType } = require('discord-api-types/v10');
* @property {string} [url] The URL of the button
*/
/**
* @typedef {BaseComponentData} BaseSelectMenuComponentData
* @property {string} customId The custom id of the select menu
* @property {boolean} [disabled] Whether the select menu is disabled or not
* @property {number} [maxValues] The maximum amount of options that can be selected
* @property {number} [minValues] The minimum amount of options that can be selected
* @property {string} [placeholder] The placeholder of the select menu
* @property {boolean} [required] Whether this component is required in modals
*/
/**
* @typedef {BaseSelectMenuComponentData} StringSelectMenuComponentData
* @property {SelectMenuComponentOptionData[]} [options] The options in this select menu
*/
/**
* @typedef {BaseSelectMenuComponentData} UserSelectMenuComponentData
* @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu
*/
/**
* @typedef {BaseSelectMenuComponentData} RoleSelectMenuComponentData
* @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu
*/
/**
* @typedef {BaseSelectMenuComponentData} MentionableSelectMenuComponentData
* @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu
*/
/**
* @typedef {BaseSelectMenuComponentData} ChannelSelectMenuComponentData
* @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu
* @property {ChannelType[]} [channelTypes] The types of channels that can be selected
*/
/**
* @typedef {object} SelectMenuComponentOptionData
* @property {string} label The label of the option
@@ -199,6 +254,7 @@ const ChannelSelectMenuComponent = require('../structures/ChannelSelectMenuCompo
const Component = require('../structures/Component');
const ContainerComponent = require('../structures/ContainerComponent');
const FileComponent = require('../structures/FileComponent');
const LabelComponent = require('../structures/LabelComponent');
const MediaGalleryComponent = require('../structures/MediaGalleryComponent');
const MentionableSelectMenuBuilder = require('../structures/MentionableSelectMenuBuilder');
const MentionableSelectMenuComponent = require('../structures/MentionableSelectMenuComponent');
@@ -231,6 +287,7 @@ const ComponentTypeToComponent = {
[ComponentType.Section]: SectionComponent,
[ComponentType.Separator]: SeparatorComponent,
[ComponentType.Thumbnail]: ThumbnailComponent,
[ComponentType.Label]: LabelComponent,
};
const ComponentTypeToBuilder = {

View File

@@ -0,0 +1,28 @@
'use strict';
const { InviteFlags } = require('discord-api-types/v10');
const BitField = require('./BitField');
/**
* Data structure that makes it easy to interact with a {@link GuildInvite#flags} bit field.
*
* @extends {BitField}
*/
class InviteFlagsBitField extends BitField {
/**
* Numeric invite flags.
*
* @type {InviteFlags}
* @memberof InviteFlagsBitField
*/
static Flags = InviteFlags;
}
/**
* @name InviteFlagsBitField
* @kind constructor
* @memberof InviteFlagsBitField
* @param {BitFieldResolvable} [bits=0] Bit(s) to read from
*/
exports.InviteFlagsBitField = InviteFlagsBitField;

View File

@@ -27,6 +27,8 @@ const { createEnum } = require('./Enums');
* @property {number} GuildScheduledEvent The partial to receive uncached guild scheduled events.
* @property {number} ThreadMember The partial to receive uncached thread members.
* @property {number} SoundboardSound The partial to receive uncached soundboard sounds.
* @property {number} Poll The partial to receive uncached polls.
* @property {number} PollAnswer The partial to receive uncached poll answers.
*/
// JSDoc for IntelliSense purposes
@@ -43,4 +45,6 @@ module.exports = createEnum([
'GuildScheduledEvent',
'ThreadMember',
'SoundboardSound',
'Poll',
'PollAnswer',
]);

View File

@@ -1,5 +1,6 @@
'use strict';
const { ThreadMemberFlags } = require('discord-api-types/v10');
const BitField = require('./BitField');
/**
@@ -9,10 +10,10 @@ const BitField = require('./BitField');
class ThreadMemberFlagsBitField extends BitField {
/**
* Numeric thread member flags. There are currently no bitflags relevant to bots for this.
* @type {Object<string, number>}
* @type {ThreadMemberFlags}
* @memberof ThreadMemberFlagsBitField
*/
static Flags = {};
static Flags = ThreadMemberFlags;
}
/**

View File

@@ -37,7 +37,15 @@ import {
} from '@discordjs/formatters';
import { Awaitable, JSONEncodable } from '@discordjs/util';
import { Collection, ReadonlyCollection } from '@discordjs/collection';
import { BaseImageURLOptions, EmojiURLOptions, ImageURLOptions, RawFile, REST, RESTOptions } from '@discordjs/rest';
import {
BaseImageURLOptions,
EmojiURLOptions,
ImageURLOptions,
RawFile,
REST,
RESTOptions,
ImageSize,
} from '@discordjs/rest';
import {
WebSocketManager as WSWebSocketManager,
IShardingStrategy,
@@ -55,6 +63,7 @@ import {
APIInteractionDataResolvedChannel,
APIInteractionDataResolvedGuildMember,
APIInteractionGuildMember,
APILabelComponent,
APIMessage,
APIMessageComponent,
APIOverwrite,
@@ -215,6 +224,7 @@ import {
APIFileComponent,
APIMessageTopLevelComponent,
EntryPointCommandHandlerType,
InviteFlags,
} from 'discord-api-types/v10';
import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events';
@@ -351,6 +361,21 @@ export class ActionRowBuilder<
): ActionRowBuilder<ComponentType>;
}
export type ComponentInLabelData =
| StringSelectMenuComponentData
| TextInputComponentData
| UserSelectMenuComponentData
| ChannelSelectMenuComponentData
| RoleSelectMenuComponentData
| MentionableSelectMenuComponentData;
export interface LabelComponentData extends BaseComponentData {
type: ComponentType.Label;
component: ComponentInLabelData;
description?: string;
label: string;
}
export type MessageActionRowComponent =
| ButtonComponent
| StringSelectMenuComponent
@@ -911,6 +936,12 @@ export class TextInputComponent extends Component<APITextInputComponent> {
public get value(): string;
}
export class LabelComponent extends Component<APILabelComponent> {
public component: StringSelectMenuComponent | TextInputComponent;
public get label(): string;
public get description(): string | null;
}
export class BaseSelectMenuComponent<Data extends APISelectMenuComponent> extends Component<Data> {
protected constructor(data: Data);
public get placeholder(): string | null;
@@ -1671,6 +1702,7 @@ export class Guild extends AnonymousGuild {
): Promise<Guild>;
public setIcon(icon: BufferResolvable | Base64Resolvable | null, reason?: string): Promise<Guild>;
public setName(name: string, reason?: string): Promise<Guild>;
/** @deprecated API related to guild ownership may no longer be used. */
public setOwner(owner: GuildMemberResolvable, reason?: string): Promise<Guild>;
public setPreferredLocale(preferredLocale: Locale | null, reason?: string): Promise<Guild>;
public setPublicUpdatesChannel(publicUpdatesChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>;
@@ -1682,6 +1714,7 @@ export class Guild extends AnonymousGuild {
public setVerificationLevel(verificationLevel: GuildVerificationLevel | null, reason?: string): Promise<Guild>;
public setPremiumProgressBarEnabled(enabled?: boolean, reason?: string): Promise<Guild>;
public setWidgetSettings(settings: GuildWidgetSettingsData, reason?: string): Promise<Guild>;
/** @deprecated API related to guild ownership may no longer be used. */
public setMFALevel(level: GuildMFALevel, reason?: string): Promise<Guild>;
public toJSON(): unknown;
}
@@ -2020,6 +2053,7 @@ export class GuildTemplate extends Base {
public guildId: Snowflake;
public serializedGuild: APITemplateSerializedSourceGuild;
public unSynced: boolean | null;
/** @deprecated API related to guild ownership may no longer be used. */
public createGuild(name: string, icon?: BufferResolvable | Base64Resolvable): Promise<Guild>;
public delete(): Promise<GuildTemplate>;
public edit(options?: GuildTemplateEditOptions): Promise<GuildTemplate>;
@@ -2271,6 +2305,7 @@ export class Invite extends Base {
/** @deprecated Public Stage Instances don't exist anymore */
public stageInstance: InviteStageInstance | null;
public guildScheduledEvent: GuildScheduledEvent | null;
public flags: Readonly<InviteFlagsBitField>;
}
/** @deprecated Public Stage Instances don't exist anymore */
@@ -2291,6 +2326,13 @@ export class InviteGuild extends AnonymousGuild {
public welcomeScreen: WelcomeScreen | null;
}
export type InviteFlagsString = keyof typeof InviteFlags;
export class InviteFlagsBitField extends BitField<InviteFlagsString> {
public static Flags: typeof InviteFlags;
public static resolve(bit?: BitFieldResolvable<InviteFlagsString, number>): number;
}
export class LimitedCollection<Key, Value> extends Collection<Key, Value> {
public constructor(options?: LimitedCollectionOptions<Key, Value>, iterable?: Iterable<readonly [Key, Value]>);
public maxSize: number;
@@ -2745,33 +2787,119 @@ export interface ModalComponentData {
customId: string;
title: string;
components: readonly (
| JSONEncodable<APIActionRowComponent<APIComponentInModalActionRow>>
| JSONEncodable<APIActionRowComponent<APIComponentInModalActionRow> | APILabelComponent>
| ActionRowData<ModalActionRowComponentData>
| LabelComponentData
| TextDisplayComponentData
)[];
}
export interface BaseModalData {
customId: string;
type: ComponentType;
export interface BaseModalData<Type extends ComponentType> {
id: number;
type: Type;
}
export interface TextInputModalData extends BaseModalData {
type: ComponentType.TextInput;
export interface TextInputModalData extends BaseModalData<ComponentType.TextInput> {
customId: string;
value: string;
}
export interface ActionRowModalData {
type: ComponentType.ActionRow;
export interface SelectMenuModalData<Cached extends CacheType = CacheType>
extends BaseModalData<
| ComponentType.ChannelSelect
| ComponentType.MentionableSelect
| ComponentType.RoleSelect
| ComponentType.StringSelect
| ComponentType.UserSelect
> {
channels?: ReadonlyCollection<
Snowflake,
CacheTypeReducer<Cached, GuildBasedChannel, APIInteractionDataResolvedChannel>
>;
customId: string;
members?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>;
roles?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
users?: ReadonlyCollection<Snowflake, User>;
values: readonly string[];
}
export type ModalData = SelectMenuModalData | TextInputModalData;
export interface LabelModalData extends BaseModalData<ComponentType.Label> {
component: readonly ModalData[];
}
export interface ActionRowModalData extends BaseModalData<ComponentType.ActionRow> {
components: readonly TextInputModalData[];
}
export class ModalSubmitFields {
private constructor(components: readonly (readonly ModalActionRowComponent[])[]);
public components: ActionRowModalData[];
public fields: Collection<string, TextInputModalData>;
public getField<Type extends ComponentType>(customId: string, type: Type): { type: Type } & TextInputModalData;
public getField(customId: string, type?: ComponentType): TextInputModalData;
export interface TextDisplayModalData extends BaseModalData<ComponentType.TextDisplay> {}
export interface ModalSelectedMentionables<Cached extends CacheType = CacheType> {
members: NonNullable<SelectMenuModalData<Cached>['members']>;
roles: NonNullable<SelectMenuModalData<Cached>['roles']>;
users: NonNullable<SelectMenuModalData<Cached>['users']>;
}
export class ModalSubmitFields<Cached extends CacheType = CacheType> {
private constructor(
components: readonly (ActionRowModalData | LabelModalData | TextDisplayModalData)[],
resolved?: BaseInteractionResolvedData,
);
public components: (ActionRowModalData | LabelModalData | TextDisplayModalData)[];
public resolved: Readonly<BaseInteractionResolvedData<Cached>> | null;
public fields: Collection<string, ModalData>;
public getField<Type extends ComponentType>(customId: string, type: Type): Extract<ModalData, { type: Type }>;
public getField(customId: string, type?: ComponentType): ModalData;
private _getTypedComponent(
customId: string,
allowedTypes: readonly ComponentType[],
properties: string,
required: boolean,
): ModalData;
public getTextInputValue(customId: string): string;
public getStringSelectValues(customId: string): readonly string[];
public getSelectedUsers(customId: string, required: true): ReadonlyCollection<Snowflake, User>;
public getSelectedUsers(customId: string, required?: boolean): ReadonlyCollection<Snowflake, User> | null;
public getSelectedMembers(customId: string): NonNullable<SelectMenuModalData<Cached>['members']> | null;
public getSelectedChannels<const Type extends ChannelType = ChannelType>(
customId: string,
required: true,
channelTypes?: readonly Type[],
): ReadonlyCollection<
Snowflake,
Extract<
NonNullable<CommandInteractionOption<Cached>['channel']>,
{
type: Type extends ChannelType.AnnouncementThread | ChannelType.PublicThread
? ChannelType.AnnouncementThread | ChannelType.PublicThread
: Type;
}
>
>;
public getSelectedChannels<const Type extends ChannelType = ChannelType>(
customId: string,
required?: boolean,
channelTypes?: readonly Type[],
): ReadonlyCollection<
Snowflake,
Extract<
NonNullable<CommandInteractionOption<Cached>['channel']>,
{
type: Type extends ChannelType.AnnouncementThread | ChannelType.PublicThread
? ChannelType.AnnouncementThread | ChannelType.PublicThread
: Type;
}
>
> | null;
public getSelectedRoles(customId: string, required: true): NonNullable<SelectMenuModalData<Cached>['roles']>;
public getSelectedRoles(
customId: string,
required?: boolean,
): NonNullable<SelectMenuModalData<Cached>['roles']> | null;
public getSelectedMentionables(customId: string, required: true): ModalSelectedMentionables<Cached>;
public getSelectedMentionables(customId: string, required?: boolean): ModalSelectedMentionables<Cached> | null;
}
export interface ModalMessageModalSubmitInteraction<Cached extends CacheType = CacheType>
@@ -2795,8 +2923,8 @@ export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extend
private constructor(client: Client<true>, data: APIModalSubmitInteraction);
public type: InteractionType.ModalSubmit;
public readonly customId: string;
public readonly components: ActionRowModalData[];
public readonly fields: ModalSubmitFields;
public readonly components: (ActionRowModalData | LabelModalData)[];
public readonly fields: ModalSubmitFields<Cached>;
public deferred: boolean;
public ephemeral: boolean | null;
public message: Message<BooleanCache<Cached>> | null;
@@ -3002,19 +3130,30 @@ export class Presence extends Base {
}
export interface PollQuestionMedia {
text: string;
text: string | null;
}
export class PollAnswerVoterManager extends CachedManager<Snowflake, User, UserResolvable> {
private constructor(answer: PollAnswer);
public answer: PollAnswer;
public fetch(options?: BaseFetchPollAnswerVotersOptions): Promise<Collection<Snowflake, User>>;
}
export class Poll extends Base {
private constructor(client: Client<true>, data: APIPoll, message: Message);
private constructor(client: Client<true>, data: APIPoll, message: Message, channel: TextBasedChannel);
public readonly channel: TextBasedChannel;
public channelId: Snowflake;
public readonly message: Message;
public messageId: Snowflake;
public question: PollQuestionMedia;
public answers: Collection<number, PollAnswer>;
public expiresTimestamp: number;
public get expiresAt(): Date;
public answers: Collection<number, PollAnswer | PartialPollAnswer>;
public expiresTimestamp: number | null;
public get expiresAt(): Date | null;
public allowMultiselect: boolean;
public layoutType: PollLayoutType;
public resultsFinalized: boolean;
public get partial(): false;
public fetch(): Promise<this>;
public end(): Promise<Message>;
}
@@ -3026,11 +3165,14 @@ export interface BaseFetchPollAnswerVotersOptions {
export class PollAnswer extends Base {
private constructor(client: Client<true>, data: APIPollAnswer & { count?: number }, poll: Poll);
private _emoji: APIPartialEmoji | null;
public readonly poll: Poll;
public readonly poll: Poll | PartialPoll;
public id: number;
public text: string | null;
public voteCount: number;
public voters: PollAnswerVoterManager;
public get emoji(): GuildEmoji | Emoji | null;
public get partial(): false;
/** @deprecated Use {@link PollAnswerVoterManager.fetch} instead */
public fetchVoters(options?: BaseFetchPollAnswerVotersOptions): Promise<Collection<Snowflake, User>>;
}
@@ -4010,6 +4152,8 @@ export class Formatters extends null {
export type ComponentData =
| MessageActionRowComponentData
| ModalActionRowComponentData
| LabelComponentData
| ComponentInLabelData
| ComponentInContainerData
| ContainerComponentData
| ThumbnailComponentData;
@@ -4109,9 +4253,9 @@ export class Webhook<Type extends WebhookType = WebhookType> {
public editMessage(
message: MessageResolvable,
options: string | MessagePayload | WebhookMessageEditOptions,
): Promise<Message>;
public fetchMessage(message: Snowflake, options?: WebhookFetchMessageOptions): Promise<Message>;
public send(options: string | MessagePayload | WebhookMessageCreateOptions): Promise<Message>;
): Promise<Message<true>>;
public fetchMessage(message: Snowflake, options?: WebhookFetchMessageOptions): Promise<Message<true>>;
public send(options: string | MessagePayload | WebhookMessageCreateOptions): Promise<Message<true>>;
}
// tslint:disable-next-line no-empty-interface
@@ -4497,6 +4641,8 @@ export enum DiscordjsErrorCodes {
ModalSubmitInteractionFieldNotFound = 'ModalSubmitInteractionFieldNotFound',
ModalSubmitInteractionFieldType = 'ModalSubmitInteractionFieldType',
ModalSubmitInteractionFieldEmpty = 'ModalSubmitInteractionComponentEmpty',
ModalSubmitInteractionFieldInvalidChannelType = 'ModalSubmitInteractionFieldInvalidChannelType',
InvalidMissingScopes = 'InvalidMissingScopes',
InvalidScopesWithPermissions = 'InvalidScopesWithPermissions',
@@ -4845,6 +4991,7 @@ export interface FetchSoundboardSoundsOptions {
export class GuildManager extends CachedManager<Snowflake, Guild, GuildResolvable> {
private constructor(client: Client<true>, iterable?: Iterable<RawGuildData>);
/** @deprecated API related to guild ownership may no longer be used. */
public create(options: GuildCreateOptions): Promise<Guild>;
public fetch(options: Snowflake | FetchGuildOptions): Promise<Guild>;
public fetch(options?: FetchGuildsOptions): Promise<Collection<Snowflake, OAuth2Guild>>;
@@ -4879,6 +5026,7 @@ export class GuildMemberManager extends CachedManager<Snowflake, GuildMember, Gu
options?: BulkBanOptions,
): Promise<BulkBanResult>;
public edit(user: UserResolvable, options: GuildMemberEditOptions): Promise<GuildMember>;
public editMe(options: GuildMemberEditMeOptions): Promise<GuildMember>;
public fetch(
options: UserResolvable | FetchMemberOptions | (FetchMembersOptions & { user: UserResolvable }),
): Promise<GuildMember>;
@@ -5306,7 +5454,9 @@ export type AllowedPartial =
| MessageReaction
| GuildScheduledEvent
| ThreadMember
| SoundboardSound;
| SoundboardSound
| Poll
| PollAnswer;
export type AllowedThreadTypeForNewsChannel = ChannelType.AnnouncementThread;
@@ -5878,15 +6028,15 @@ export interface ClientEvents {
inviteDelete: [invite: Invite];
messageCreate: [message: OmitPartialGroupDMChannel<Message>];
messageDelete: [message: OmitPartialGroupDMChannel<Message | PartialMessage>];
messagePollVoteAdd: [pollAnswer: PollAnswer, userId: Snowflake];
messagePollVoteRemove: [pollAnswer: PollAnswer, userId: Snowflake];
messagePollVoteAdd: [pollAnswer: PollAnswer | PartialPollAnswer, userId: Snowflake];
messagePollVoteRemove: [pollAnswer: PollAnswer | PartialPollAnswer, userId: Snowflake];
messageReactionRemoveAll: [
message: OmitPartialGroupDMChannel<Message | PartialMessage>,
reactions: ReadonlyCollection<string | Snowflake, MessageReaction>,
];
messageReactionRemoveEmoji: [reaction: MessageReaction | PartialMessageReaction];
messageDeleteBulk: [
messages: ReadonlyCollection<Snowflake, OmitPartialGroupDMChannel<Message | PartialMessage>>,
messages: ReadonlyCollection<Snowflake, Message<true> | PartialMessage<true>>,
channel: GuildTextBasedChannel,
];
messageReactionAdd: [
@@ -6033,13 +6183,17 @@ export interface CommandInteractionOption<Cached extends CacheType = CacheType>
message?: Message<BooleanCache<Cached>>;
}
export interface CommandInteractionResolvedData<Cached extends CacheType = CacheType> {
users?: ReadonlyCollection<Snowflake, User>;
export interface BaseInteractionResolvedData<Cached extends CacheType = CacheType> {
channels?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Channel, APIInteractionDataResolvedChannel>>;
members?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>;
roles?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
channels?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Channel, APIInteractionDataResolvedChannel>>;
messages?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Message, APIMessage>>;
users?: ReadonlyCollection<Snowflake, User>;
}
export interface CommandInteractionResolvedData<Cached extends CacheType = CacheType>
extends BaseInteractionResolvedData<Cached> {
attachments?: ReadonlyCollection<Snowflake, Attachment>;
messages?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Message, APIMessage>>;
}
export interface AutocompleteFocusedOption extends Pick<CommandInteractionOption, 'name'> {
@@ -6645,6 +6799,7 @@ export interface GuildChannelOverwriteOptions {
type?: OverwriteType;
}
/** @deprecated API related to guild ownership may no longer be used. */
export interface GuildCreateOptions {
name: string;
icon?: BufferResolvable | Base64Resolvable | null;
@@ -6672,6 +6827,7 @@ export interface GuildEditOptions {
afkTimeout?: number;
afkChannel?: VoiceChannelResolvable | null;
icon?: BufferResolvable | Base64Resolvable | null;
/** @deprecated API related to guild ownership may no longer be used. */
owner?: GuildMemberResolvable;
splash?: BufferResolvable | Base64Resolvable | null;
discoverySplash?: BufferResolvable | Base64Resolvable | null;
@@ -6729,6 +6885,14 @@ export interface GuildMemberEditOptions {
export type GuildMemberResolvable = GuildMember | UserResolvable;
export interface GuildMemberEditMeOptions {
avatar?: Base64Resolvable | BufferResolvable | null;
banner?: Base64Resolvable | BufferResolvable | null;
bio?: string | null;
nick?: string | null;
reason?: string;
}
export type GuildResolvable = Guild | NonThreadGuildBasedChannel | GuildMember | GuildEmoji | Invite | Role | Snowflake;
export interface GuildPruneMembersOptions {
@@ -7202,6 +7366,7 @@ export interface BaseSelectMenuComponentData extends BaseComponentData {
maxValues?: number;
minValues?: number;
placeholder?: string;
required?: true;
}
export interface StringSelectMenuComponentData extends BaseSelectMenuComponentData {
@@ -7320,6 +7485,7 @@ export interface PresenceData {
export type PresenceResolvable = Presence | UserResolvable | Snowflake;
/** @deprecated API related to guild ownership may no longer be used. */
export interface PartialChannelData {
id?: Snowflake | number;
parentId?: Snowflake | number;
@@ -7366,11 +7532,28 @@ export interface PartialDMChannel extends Partialize<DMChannel, null, null, 'las
export interface PartialGuildMember extends Partialize<GuildMember, 'joinedAt' | 'joinedTimestamp' | 'pending'> {}
export interface PartialMessage
extends Partialize<Message, 'type' | 'system' | 'pinned' | 'tts', 'content' | 'cleanContent' | 'author'> {}
export interface PartialMessage<InGuild extends boolean = boolean>
extends Partialize<Message<InGuild>, 'type' | 'system' | 'pinned' | 'tts', 'content' | 'cleanContent' | 'author'> {}
export interface PartialMessageReaction extends Partialize<MessageReaction, 'count'> {}
export interface PartialPoll
extends Partialize<
Poll,
'allowMultiselect' | 'layoutType' | 'expiresTimestamp',
null,
'question' | 'message' | 'answers'
> {
question: { text: null };
message: PartialMessage;
// eslint-disable-next-line no-restricted-syntax
answers: Collection<number, PartialPollAnswer>;
}
export interface PartialPollAnswer extends Partialize<PollAnswer, 'emoji' | 'text', null, 'poll'> {
readonly poll: PartialPoll;
}
export interface PartialGuildScheduledEvent
extends Partialize<GuildScheduledEvent, 'userCount', 'status' | 'privacyLevel' | 'name' | 'entityType'> {}
@@ -7378,6 +7561,7 @@ export interface PartialThreadMember extends Partialize<ThreadMember, 'flags' |
export interface PartialSoundboardSound extends Partialize<SoundboardSound, 'available' | 'name' | 'volume'> {}
/** @deprecated API related to guild ownership may no longer be used. */
export interface PartialOverwriteData {
id: Snowflake | number;
type?: OverwriteType;
@@ -7385,6 +7569,7 @@ export interface PartialOverwriteData {
deny?: PermissionResolvable;
}
/** @deprecated API related to guild ownership may no longer be used. */
export interface PartialRoleData extends RoleData {
id?: Snowflake | number;
}
@@ -7398,6 +7583,8 @@ export enum Partials {
GuildScheduledEvent,
ThreadMember,
SoundboardSound,
Poll,
PollAnswer,
}
export interface PartialUser extends Partialize<User, 'username' | 'tag' | 'discriminator'> {}
@@ -7825,3 +8012,6 @@ export * from '@discordjs/formatters';
export * from '@discordjs/rest';
export * from '@discordjs/util';
export * from '@discordjs/ws';
// Solve TS compile error
export type { ImageSize };

View File

@@ -232,7 +232,11 @@ import {
ContainerComponentData,
InteractionResponse,
FetchPinnedMessagesResponse,
} from '.';
PartialPoll,
PartialPollAnswer,
PollAnswer,
PollAnswerVoterManager,
} from './index.js';
import {
expectAssignable,
expectDeprecated,
@@ -715,6 +719,48 @@ client.on('messageDeleteBulk', (messages, { client }) => {
expectType<Client<true>>(client);
});
client.on('messagePollVoteAdd', async (answer, userId) => {
expectType<Client<true>>(answer.client);
expectType<Snowflake>(userId);
if (answer.partial) {
expectType<null>(answer.emoji);
expectType<null>(answer.text);
expectNotType<null>(answer.id);
expectNotType<null>(answer.poll);
await answer.poll.fetch();
answer = answer.poll.answers?.get(answer.id) ?? answer;
expectType<User>(answer.voters.cache.get(userId)!);
}
expectType<string | null>(answer.text);
expectType<GuildEmoji | Emoji | null>(answer.emoji);
expectType<number>(answer.id);
expectType<number>(answer.voteCount!);
});
client.on('messagePollVoteRemove', async (answer, userId) => {
expectType<Client<true>>(answer.client);
expectType<Snowflake>(userId);
if (answer.partial) {
expectType<null>(answer.emoji);
expectType<null>(answer.text);
expectNotType<null>(answer.id);
expectNotType<null>(answer.poll);
await answer.poll.fetch();
answer = answer.poll.answers?.get(answer.id) ?? answer;
}
expectType<string | null>(answer.text);
expectType<GuildEmoji | Emoji | null>(answer.emoji);
expectType<number>(answer.id);
expectType<number>(answer.voteCount!);
});
client.on('messageReactionAdd', async (reaction, { client }) => {
expectType<Client<true>>(reaction.client);
expectType<Client<true>>(client);
@@ -1780,6 +1826,12 @@ declare const messageManager: MessageManager;
messageManager.fetch({ message: '1234567890', after: '1234567890', cache: true, force: false });
}
declare const pollAnswerVoterManager: PollAnswerVoterManager;
{
expectType<Promise<Collection<Snowflake, User>>>(pollAnswerVoterManager.fetch());
expectType<PollAnswer>(pollAnswerVoterManager.answer);
}
declare const roleManager: RoleManager;
expectType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch());
expectType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch(undefined, {}));
@@ -2514,6 +2566,59 @@ chatInputInteraction.showModal({
],
});
chatInputInteraction.showModal({
title: 'abc',
customId: 'abc',
components: [
{
type: ComponentType.Label,
label: 'label',
component: {
customId: 'aa',
type: ComponentType.TextInput,
style: TextInputStyle.Short,
label: 'label',
},
},
{
components: [
{
customId: 'aa',
label: 'label',
style: TextInputStyle.Short,
type: ComponentType.TextInput,
},
],
type: ComponentType.ActionRow,
},
{
type: ComponentType.Label,
label: 'Lll',
component: {
customId: 'aa',
type: ComponentType.UserSelect,
},
},
{
type: ComponentType.Label,
label: 'Lll',
component: {
customId: 'aa',
type: ComponentType.ChannelSelect,
channelTypes: [ChannelType.GuildText, ChannelType.GuildVoice],
},
},
{
type: ComponentType.Label,
label: 'Lll',
component: {
customId: 'aa',
type: ComponentType.RoleSelect,
},
},
],
});
declare const stringSelectMenuData: APIStringSelectComponent;
StringSelectMenuBuilder.from(stringSelectMenuData);
@@ -2597,9 +2702,9 @@ declare const webhookClient: WebhookClient;
declare const interactionWebhook: InteractionWebhook;
declare const snowflake: Snowflake;
expectType<Promise<Message>>(webhook.send('content'));
expectType<Promise<Message>>(webhook.editMessage(snowflake, 'content'));
expectType<Promise<Message>>(webhook.fetchMessage(snowflake));
expectType<Promise<Message<true>>>(webhook.send('content'));
expectType<Promise<Message<true>>>(webhook.editMessage(snowflake, 'content'));
expectType<Promise<Message<true>>>(webhook.fetchMessage(snowflake));
expectType<Promise<Webhook>>(webhook.edit({ name: 'name' }));
expectType<Promise<APIMessage>>(webhookClient.send('content'));
@@ -2802,16 +2907,42 @@ await textChannel.send({
},
});
declare const partialPoll: PartialPoll;
{
if (partialPoll.partial) {
expectType<null>(partialPoll.question.text);
expectType<PartialMessage>(partialPoll.message);
expectType<null>(partialPoll.allowMultiselect);
expectType<null>(partialPoll.layoutType);
expectType<null>(partialPoll.expiresTimestamp);
expectType<Collection<number, PartialPollAnswer>>(partialPoll.answers);
}
}
declare const partialPollAnswer: PartialPollAnswer;
{
if (partialPollAnswer.partial) {
expectType<PartialPoll>(partialPollAnswer.poll);
expectType<null>(partialPollAnswer.emoji);
expectType<null>(partialPollAnswer.text);
}
}
declare const poll: Poll;
declare const message: Message;
declare const pollData: PollData;
{
expectType<Message>(await poll.end());
expectType<false>(poll.partial);
expectNotType<Collection<number, PartialPollAnswer>>(poll.answers);
const answer = poll.answers.first()!;
expectType<number>(answer.voteCount);
expectType<Collection<Snowflake, User>>(await answer.fetchVoters({ after: snowflake, limit: 10 }));
if (!answer.partial) {
expectType<number>(answer.voteCount);
expectType<number>(answer.id);
expectType<PollAnswerVoterManager>(answer.voters);
expectType<Collection<Snowflake, User>>(await answer.voters.fetch({ after: snowflake, limit: 10 }));
}
await messageManager.endPoll(snowflake);
await messageManager.fetchPollAnswerVoters({

View File

@@ -55,7 +55,7 @@
"homepage": "https://discord.js.org",
"funding": "https://github.com/discordjs/discord.js?sponsor",
"dependencies": {
"discord-api-types": "^0.38.16"
"discord-api-types": "^0.38.24"
},
"devDependencies": {
"@discordjs/api-extractor": "workspace:^",

View File

@@ -72,7 +72,7 @@
"@discordjs/rest": "workspace:^",
"@discordjs/util": "workspace:^",
"@discordjs/ws": "workspace:^",
"discord-api-types": "^0.38.16"
"discord-api-types": "^0.38.24"
},
"devDependencies": {
"@discordjs/api-extractor": "workspace:^",

View File

@@ -88,7 +88,7 @@
"@sapphire/async-queue": "^1.5.3",
"@sapphire/snowflake": "^3.5.3",
"@vladfrangu/async_event_emitter": "^2.4.6",
"discord-api-types": "^0.38.16",
"discord-api-types": "^0.38.24",
"magic-bytes.js": "^1.10.0",
"tslib": "^2.6.3",
"undici": "6.21.3"

View File

@@ -64,7 +64,7 @@
"funding": "https://github.com/discordjs/discord.js?sponsor",
"dependencies": {
"@types/ws": "^8.5.12",
"discord-api-types": "^0.38.16",
"discord-api-types": "^0.38.24",
"prism-media": "^1.3.5",
"tslib": "^2.6.3",
"ws": "^8.18.0"

View File

@@ -79,7 +79,7 @@
"@sapphire/async-queue": "^1.5.3",
"@types/ws": "^8.5.12",
"@vladfrangu/async_event_emitter": "^2.4.6",
"discord-api-types": "^0.38.16",
"discord-api-types": "^0.38.24",
"tslib": "^2.6.3",
"ws": "^8.18.0"
},

77
pnpm-lock.yaml generated
View File

@@ -816,8 +816,8 @@ importers:
specifier: ^2.4.6
version: 2.4.6
discord-api-types:
specifier: ^0.38.16
version: 0.38.16
specifier: ^0.38.29
version: 0.38.29
devDependencies:
'@discordjs/api-extractor':
specifier: workspace:^
@@ -932,8 +932,8 @@ importers:
packages/discord.js:
dependencies:
'@discordjs/builders':
specifier: ^1.11.2
version: 1.11.2
specifier: ^1.12.0
version: 1.12.0
'@discordjs/collection':
specifier: 1.5.3
version: 1.5.3
@@ -953,8 +953,8 @@ importers:
specifier: 3.5.3
version: 3.5.3
discord-api-types:
specifier: ^0.38.16
version: 0.38.16
specifier: ^0.38.29
version: 0.38.29
fast-deep-equal:
specifier: 3.1.3
version: 3.1.3
@@ -1075,8 +1075,8 @@ importers:
packages/formatters:
dependencies:
discord-api-types:
specifier: ^0.38.16
version: 0.38.16
specifier: ^0.38.24
version: 0.38.24
devDependencies:
'@discordjs/api-extractor':
specifier: workspace:^
@@ -1148,8 +1148,8 @@ importers:
specifier: workspace:^
version: link:../ws
discord-api-types:
specifier: ^0.38.16
version: 0.38.16
specifier: ^0.38.24
version: 0.38.24
devDependencies:
'@discordjs/api-extractor':
specifier: workspace:^
@@ -1322,8 +1322,8 @@ importers:
specifier: ^2.4.6
version: 2.4.6
discord-api-types:
specifier: ^0.38.16
version: 0.38.16
specifier: ^0.38.24
version: 0.38.24
magic-bytes.js:
specifier: ^1.10.0
version: 1.10.0
@@ -1619,8 +1619,8 @@ importers:
specifier: ^8.5.12
version: 8.5.12
discord-api-types:
specifier: ^0.38.16
version: 0.38.16
specifier: ^0.38.24
version: 0.38.24
prism-media:
specifier: ^1.3.5
version: 1.3.5
@@ -1716,8 +1716,8 @@ importers:
specifier: ^2.4.6
version: 2.4.6
discord-api-types:
specifier: ^0.38.16
version: 0.38.16
specifier: ^0.38.24
version: 0.38.24
tslib:
specifier: ^2.6.3
version: 2.6.3
@@ -2777,20 +2777,20 @@ packages:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
'@definitelytyped/header-parser@0.2.19':
resolution: {integrity: sha512-zu+RxQpUCgorYUQZoyyrRIn9CljL1CeM4qak3NDeMO1r7tjAkodfpAGnVzx/6JR2OUk0tAgwmZxNMSwd9LVgxw==}
'@definitelytyped/header-parser@0.2.20':
resolution: {integrity: sha512-97YPAlUo8XjWNtZ+6k+My+50/ljE2iX6KEPjOZ1Az1RsZdKwJ6taAX3F5g6SY1SJr50bzdm2RZzyQNdRmHcs4w==}
engines: {node: '>=18.18.0'}
'@definitelytyped/typescript-versions@0.1.8':
resolution: {integrity: sha512-iz6q9aTwWW7CzN2g8jFQfZ955D63LA+wdIAKz4+2pCc/7kokmEHie1/jVWSczqLFOlmH+69bWQxIurryBP/sig==}
'@definitelytyped/typescript-versions@0.1.9':
resolution: {integrity: sha512-Qjalw9eNlcTjXhzx0Q6kHKuRCOUt/M5RGGRGKsiYlm/nveGvPX9liZSQlGXZVwyQ5I9qvq/GdaWiPchQ+ZXOrQ==}
engines: {node: '>=18.18.0'}
'@definitelytyped/utils@0.1.8':
resolution: {integrity: sha512-4JINx4Rttha29f50PBsJo48xZXx/He5yaIWJRwVarhYAN947+S84YciHl+AIhQNRPAFkg8+5qFngEGtKxQDWXA==}
engines: {node: '>=18.18.0'}
'@discordjs/builders@1.11.2':
resolution: {integrity: sha512-F1WTABdd8/R9D1icJzajC4IuLyyS8f3rTOz66JsSI3pKvpCAtsMBweu8cyNYsIyvcrKAVn9EPK+Psoymq+XC0A==}
'@discordjs/builders@1.12.0':
resolution: {integrity: sha512-jQ0m/fVOg6j3w2Rrzrg5VfqPpkslYNnpdTAyQzQXQ7S/5y0iScBnMlVZfu/AFLP9C34shQ4I+EpTGZV1VlN7RQ==}
engines: {node: '>=16.11.0'}
'@discordjs/collection@1.5.3':
@@ -8357,8 +8357,11 @@ packages:
discord-api-types@0.37.119:
resolution: {integrity: sha512-WasbGFXEB+VQWXlo6IpW3oUv73Yuau1Ig4AZF/m13tXcTKnMpc/mHjpztIlz4+BM9FG9BHQkEXiPto3bKduQUg==}
discord-api-types@0.38.16:
resolution: {integrity: sha512-Cz42dC5WqJD17Yk0bRy7YLTJmh3NKo4FGpxZuA8MHqT0RPxKSrll5YhlODZ2z5DiEV/gpHMeTSrTFTWpSXjT1Q==}
discord-api-types@0.38.24:
resolution: {integrity: sha512-P7/DkcFIiIoaBogStnhhcGRX7KR+gIFp0SpmwsZUIM0bgDkYMEUx+8l+t3quYc/KSgg92wvE9w/4mabO57EMug==}
discord-api-types@0.38.29:
resolution: {integrity: sha512-+5BfrjLJN1hrrcK0MxDQli6NSv5lQH7Y3/qaOfk9+k7itex8RkA/UcevVMMLe8B4IKIawr4ITBTb2fBB2vDORg==}
dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
@@ -16299,13 +16302,13 @@ snapshots:
dependencies:
'@jridgewell/trace-mapping': 0.3.9
'@definitelytyped/header-parser@0.2.19':
'@definitelytyped/header-parser@0.2.20':
dependencies:
'@definitelytyped/typescript-versions': 0.1.8
'@definitelytyped/typescript-versions': 0.1.9
'@definitelytyped/utils': 0.1.8
semver: 7.7.1
'@definitelytyped/typescript-versions@0.1.8': {}
'@definitelytyped/typescript-versions@0.1.9': {}
'@definitelytyped/utils@0.1.8':
dependencies:
@@ -16318,12 +16321,12 @@ snapshots:
tar-stream: 3.1.7
which: 4.0.0
'@discordjs/builders@1.11.2':
'@discordjs/builders@1.12.0':
dependencies:
'@discordjs/formatters': 0.6.1
'@discordjs/util': 1.1.1
'@sapphire/shapeshift': 4.0.0
discord-api-types: 0.38.16
discord-api-types: 0.38.29
fast-deep-equal: 3.1.3
ts-mixer: 6.0.4
tslib: 2.8.1
@@ -16334,7 +16337,7 @@ snapshots:
'@discordjs/formatters@0.6.1':
dependencies:
discord-api-types: 0.38.16
discord-api-types: 0.38.29
'@discordjs/rest@2.5.1':
dependencies:
@@ -16343,7 +16346,7 @@ snapshots:
'@sapphire/async-queue': 1.5.3
'@sapphire/snowflake': 3.5.3
'@vladfrangu/async_event_emitter': 2.4.6
discord-api-types: 0.38.16
discord-api-types: 0.38.29
magic-bytes.js: 1.10.0
tslib: 2.8.1
undici: 6.21.3
@@ -16358,7 +16361,7 @@ snapshots:
'@sapphire/async-queue': 1.5.3
'@types/ws': 8.5.12
'@vladfrangu/async_event_emitter': 2.4.6
discord-api-types: 0.38.16
discord-api-types: 0.38.29
tslib: 2.8.1
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
transitivePeerDependencies:
@@ -23711,7 +23714,9 @@ snapshots:
discord-api-types@0.37.119: {}
discord-api-types@0.38.16: {}
discord-api-types@0.38.24: {}
discord-api-types@0.38.29: {}
dlv@1.1.3: {}
@@ -23762,7 +23767,7 @@ snapshots:
dts-critic@3.3.11(typescript@5.5.4):
dependencies:
'@definitelytyped/header-parser': 0.2.19
'@definitelytyped/header-parser': 0.2.20
command-exists: 1.2.9
rimraf: 3.0.2
semver: 6.3.1
@@ -23772,8 +23777,8 @@ snapshots:
dtslint@4.2.1(typescript@5.5.4):
dependencies:
'@definitelytyped/header-parser': 0.2.19
'@definitelytyped/typescript-versions': 0.1.8
'@definitelytyped/header-parser': 0.2.20
'@definitelytyped/typescript-versions': 0.1.9
'@definitelytyped/utils': 0.1.8
dts-critic: 3.3.11(typescript@5.5.4)
fs-extra: 6.0.1