feat(DMChannel)!: allow partial DMChannel without client user (#11443)

BREAKING CHANGE: `DMChannel#recipientId` is now nullable.
This commit is contained in:
Qjuh
2026-05-20 20:05:16 +02:00
committed by GitHub
parent 40ce0791a8
commit 1e88dcdc05
6 changed files with 48 additions and 14 deletions

View File

@@ -1,5 +1,6 @@
'use strict';
const { ChannelType } = require('discord-api-types/v10');
const { Poll } = require('../../structures/Poll.js');
const { PollAnswer } = require('../../structures/PollAnswer.js');
const { Partials } = require('../../util/Partials.js');
@@ -33,10 +34,16 @@ class Action {
const payloadData = {};
const id = data.channel_id ?? data.id;
if (!('recipients' in data)) {
// Try to resolve the recipient, but do not add the client user.
if ('recipients' in data) {
// Try to resolve the recipient, but do not add if already existing in recipients.
const recipient = data.author ?? data.user ?? { id: data.user_id };
if (recipient.id !== this.client.user.id) payloadData.recipients = [recipient];
if (!data.recipients.some(existingRecipient => recipient.id === existingRecipient.id)) {
payloadData.recipients = [...data.recipients, recipient];
}
} else if (data.type === ChannelType.DM || data.type === ChannelType.GroupDM) {
// Try to resolve the recipient.
const recipient = data.author ?? data.user ?? { id: data.user_id };
payloadData.recipients = [recipient];
}
if (id !== undefined) payloadData.id = id;

View File

@@ -21,7 +21,9 @@ class InteractionCreateAction extends Action {
const client = this.client;
// Resolve and cache partial channels for Interaction#channel getter
const channel = data.channel && this.getChannel(data.channel);
const channel =
data.channel &&
this.getChannel({ ...data.channel, ...('recipients' in data.channel ? { user: data.user } : undefined) });
// Do not emit this for interactions that cache messages that are non-text-based.
let InteractionClass;

View File

@@ -10,6 +10,7 @@ class MessageCreateAction extends Action {
id: data.channel_id,
author: data.author,
...('guild_id' in data && { guild_id: data.guild_id }),
...('channel_type' in data && { type: data.channel_type }),
});
if (channel) {
if (!channel.isTextBased()) return {};

View File

@@ -66,7 +66,14 @@ class UserManager extends CachedManager {
}
const data = await this.client.rest.post(Routes.userChannels(), { body: { recipient_id: id } });
return this.client.channels._add(data, null, { cache });
return this.client.channels._add(
{
...data,
...('recipients' in data ? { recipients: [...data.recipients, { id: this.client.user.id }] } : undefined),
},
null,
{ cache },
);
}
/**

View File

@@ -32,19 +32,21 @@ class DMChannel extends BaseChannel {
super._patch(data);
if (data.recipients) {
const recipient = data.recipients[0];
/**
* The recipient's id
* The recipients' ids
*
* @type {Snowflake}
* @type {Snowflake[]}
*/
this.recipientId = recipient.id;
this.recipientIds = [
...new Set([...(this.recipientIds ?? []), ...data.recipients.map(recipient => recipient.id)]),
];
for (const recipient of data.recipients) {
if ('username' in recipient || this.client.options.partials.includes(Partials.User)) {
this.client.users._add(recipient);
}
}
}
if ('last_message_id' in data) {
/**
@@ -78,7 +80,21 @@ class DMChannel extends BaseChannel {
}
/**
* The recipient on the other end of the DM
* The recipient's id, if this is a DMChannel with the client user.
*
* @type {?Snowflake}
* @readonly
*/
get recipientId() {
if (this.recipientIds.includes(this.client.user.id)) {
return this.recipientIds.find(recipientId => recipientId !== this.client.user.id) ?? null;
}
return null;
}
/**
* The recipient on the other end of the DM, if this is a DMChannel with the client user.
*
* @type {?User}
* @readonly

View File

@@ -1292,7 +1292,8 @@ export interface DMChannel
export class DMChannel extends BaseChannel {
private constructor(client: Client<true>, data?: RawDMChannelData);
public flags: Readonly<ChannelFlagsBitField>;
public recipientId: Snowflake;
public get recipientId(): Snowflake | null;
public recipientIds: Snowflake[];
public get recipient(): User | null;
public type: ChannelType.DM;
public fetch(force?: boolean): Promise<this>;