@discord-selfbot/core 14.0.1 → 14.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,3 @@
1
- import { createRequire } from 'node:module';
2
-
3
- const require = createRequire(import.meta.url);
4
1
  import process from 'node:process';
5
2
  import Base from './Base';
6
3
  import type { Client } from '../client/Client';
@@ -8,64 +5,14 @@ import type { Guild } from './Guild';
8
5
  import type { RawChannelData } from '../../typings/rawDataTypes';
9
6
  import ChannelFlags from '../util/ChannelFlags';
10
7
  import _ConstantsModule from '../util/Constants';
11
-
12
- const { ChannelTypes, ThreadChannelTypes, VoiceBasedChannelTypes } =
13
- _ConstantsModule;
14
8
  import SnowflakeUtil from '../util/SnowflakeUtil';
15
9
  import type { ChannelEntity } from '../types/entities/channel';
16
10
  import type { PatchOf } from '../types/schema';
17
11
  import type ClientType from '../client/Client';
18
- import type ThreadChannelType from './ThreadChannel';
19
- import type { Snowflake } from 'discord-api-types/v10';
20
- import { isThreadParentChannel } from '../types/channels';
12
+ import { constructChannel } from './ChannelConstruction';
21
13
 
22
- let CategoryChannel: new (
23
- guild: Guild,
24
- data: RawChannelData,
25
- client: Client
26
- ) => Channel;
27
- let DMChannel: new (client: Client, data: RawChannelData) => Channel;
28
- let NewsChannel: new (
29
- guild: Guild,
30
- data: RawChannelData,
31
- client: Client
32
- ) => Channel;
33
- let StageChannel: new (
34
- guild: Guild,
35
- data: RawChannelData,
36
- client: Client
37
- ) => Channel;
38
- let StoreChannel: new (
39
- guild: Guild,
40
- data: RawChannelData,
41
- client: Client
42
- ) => Channel;
43
- let TextChannel: new (
44
- guild: Guild,
45
- data: RawChannelData,
46
- client: Client
47
- ) => Channel;
48
- let ThreadChannel: new (
49
- guild: Guild,
50
- data: RawChannelData,
51
- client: Client
52
- ) => ThreadChannelType;
53
- let VoiceChannel: new (
54
- guild: Guild,
55
- data: RawChannelData,
56
- client: Client
57
- ) => Channel;
58
- let DirectoryChannel: new (client: Client, data: RawChannelData) => Channel;
59
- let ForumChannel: new (
60
- guild: Guild,
61
- data: RawChannelData,
62
- client: Client
63
- ) => Channel;
64
- let MediaChannel: new (
65
- guild: Guild,
66
- data: RawChannelData,
67
- client: Client
68
- ) => Channel;
14
+ const { ChannelTypes, ThreadChannelTypes, VoiceBasedChannelTypes } =
15
+ _ConstantsModule;
69
16
 
70
17
  /**
71
18
  * @type {WeakSet<Channel>}
@@ -75,116 +22,6 @@ let MediaChannel: new (
75
22
  const deletedChannels = new WeakSet();
76
23
  let deprecationEmittedForDeleted = false;
77
24
 
78
- function loadChannelClasses() {
79
- CategoryChannel ??= require('./CategoryChannel').default;
80
- DMChannel ??= require('./DMChannel').default;
81
- NewsChannel ??= require('./NewsChannel').default;
82
- StageChannel ??= require('./StageChannel').default;
83
- StoreChannel ??= require('./StoreChannel').default;
84
- TextChannel ??= require('./TextChannel').default;
85
- ThreadChannel ??= require('./ThreadChannel').default;
86
- VoiceChannel ??= require('./VoiceChannel').default;
87
- DirectoryChannel ??= require('./DirectoryChannel').default;
88
- ForumChannel ??= require('./ForumChannel').default;
89
- MediaChannel ??= require('./MediaChannel').default;
90
- }
91
-
92
- function cacheGuildChannel(cache: Map<Snowflake, unknown>, channel: Channel) {
93
- cache.set(channel.id, channel);
94
- }
95
-
96
- function requireGuild(guild: Guild | null | undefined): Guild {
97
- if (!guild) {
98
- throw new TypeError('A guild is required to create a guild channel');
99
- }
100
- return guild;
101
- }
102
-
103
- function createDirectMessageChannel(client: Client, data: RawChannelData) {
104
- let channel;
105
- if (
106
- ('recipients' in data &&
107
- data.recipients &&
108
- data.type !== ChannelTypes.GROUP_DM) ||
109
- data.type === ChannelTypes.DM
110
- ) {
111
- channel = new DMChannel(client, data);
112
- } else if (data.type === ChannelTypes.GROUP_DM) {
113
- const GroupDMChannel = require('./GroupDMChannel').default;
114
- channel = new GroupDMChannel(client, data);
115
- }
116
- return channel;
117
- }
118
-
119
- function createGuildChannel(
120
- client: Client,
121
- data: RawChannelData,
122
- guild: Guild | undefined,
123
- allowUnknownGuild: boolean
124
- ) {
125
- let channel;
126
- switch (data.type) {
127
- case ChannelTypes.GUILD_TEXT: {
128
- channel = new TextChannel(requireGuild(guild), data, client);
129
- break;
130
- }
131
- case ChannelTypes.GUILD_VOICE: {
132
- channel = new VoiceChannel(requireGuild(guild), data, client);
133
- break;
134
- }
135
- case ChannelTypes.GUILD_CATEGORY: {
136
- channel = new CategoryChannel(requireGuild(guild), data, client);
137
- break;
138
- }
139
- case ChannelTypes.GUILD_NEWS: {
140
- channel = new NewsChannel(requireGuild(guild), data, client);
141
- break;
142
- }
143
- case ChannelTypes.GUILD_STORE: {
144
- channel = new StoreChannel(requireGuild(guild), data, client);
145
- break;
146
- }
147
- case ChannelTypes.GUILD_STAGE_VOICE: {
148
- channel = new StageChannel(requireGuild(guild), data, client);
149
- break;
150
- }
151
- case ChannelTypes.GUILD_NEWS_THREAD:
152
- case ChannelTypes.GUILD_PUBLIC_THREAD:
153
- case ChannelTypes.GUILD_PRIVATE_THREAD: {
154
- const thread = new ThreadChannel(requireGuild(guild), data, client);
155
- if (
156
- !allowUnknownGuild &&
157
- thread.parent &&
158
- isThreadParentChannel(thread.parent)
159
- ) {
160
- thread.parent.threads.cache.set(thread.id, thread);
161
- }
162
- channel = thread;
163
- break;
164
- }
165
-
166
- case ChannelTypes.GUILD_DIRECTORY: {
167
- channel = new DirectoryChannel(client, data);
168
- break;
169
- }
170
-
171
- case ChannelTypes.GUILD_FORUM: {
172
- channel = new ForumChannel(requireGuild(guild), data, client);
173
- break;
174
- }
175
-
176
- case ChannelTypes.GUILD_MEDIA: {
177
- channel = new MediaChannel(requireGuild(guild), data, client);
178
- break;
179
- }
180
-
181
- default: {
182
- break;
183
- }
184
- }
185
- return channel;
186
- }
187
-
188
25
  class Channel extends Base implements ChannelEntity {
189
26
  declare id: ChannelEntity['id'];
190
27
  declare type: ChannelEntity['type'];
@@ -295,33 +132,35 @@ class Channel extends Base implements ChannelEntity {
295
132
  return this.type === 'GUILD_DIRECTORY';
296
133
  }
297
134
 
298
- static create(
135
+ static construct(
299
136
  client: Client,
300
137
  data: RawChannelData,
301
138
  guild?: Guild | null,
302
139
  { allowUnknownGuild = false }: { allowUnknownGuild?: boolean } = {}
303
140
  ) {
304
- loadChannelClasses();
305
-
306
- let channel;
307
- const guildId = 'guild_id' in data ? data.guild_id : undefined;
308
- if (!guildId && !guild) {
309
- channel = createDirectMessageChannel(client, data);
310
- } else {
311
- const resolvedGuild =
312
- guild ?? (guildId ? client.guilds.cache.get(guildId) : undefined);
141
+ return constructChannel(client, data, guild, { allowUnknownGuild });
142
+ }
313
143
 
314
- if (resolvedGuild || allowUnknownGuild) {
315
- channel = createGuildChannel(
316
- client,
317
- data,
318
- resolvedGuild,
319
- allowUnknownGuild
320
- );
321
- if (channel && !allowUnknownGuild && resolvedGuild) {
322
- cacheGuildChannel(resolvedGuild.channels.cache, channel);
323
- }
324
- }
144
+ static create(
145
+ client: Client,
146
+ data: RawChannelData,
147
+ guild?: Guild | null,
148
+ { allowUnknownGuild = false }: { allowUnknownGuild?: boolean } = {}
149
+ ) {
150
+ const { channel, relations } = constructChannel(client, data, guild, {
151
+ allowUnknownGuild,
152
+ });
153
+ if (!channel) {
154
+ return channel;
155
+ }
156
+ if (!allowUnknownGuild && relations.guild) {
157
+ relations.guild.channels.cache.set(channel.id, channel as never);
158
+ }
159
+ if (!allowUnknownGuild && relations.threadParent) {
160
+ const parent = relations.threadParent as {
161
+ threads?: { cache?: Map<string, Channel> };
162
+ };
163
+ parent.threads?.cache?.set(channel.id, channel);
325
164
  }
326
165
  return channel;
327
166
  }
@@ -0,0 +1,177 @@
1
+ import { createRequire } from 'node:module';
2
+
3
+ const require = createRequire(import.meta.url);
4
+ import type { Client } from '../client/Client';
5
+ import type { Guild } from './Guild';
6
+ import type { RawChannelData } from '../../typings/rawDataTypes';
7
+ import _ConstantsModule from '../util/Constants';
8
+ import { isThreadParentChannel } from '../types/channels';
9
+ import type { Channel } from './Channel';
10
+
11
+ const { ChannelTypes } = _ConstantsModule;
12
+
13
+ type GuildChannelConstructor = new (
14
+ guild: Guild,
15
+ data: RawChannelData,
16
+ client: Client
17
+ ) => Channel;
18
+
19
+ type ClientChannelConstructor = new (
20
+ client: Client,
21
+ data: RawChannelData
22
+ ) => Channel;
23
+
24
+ let channelFactory:
25
+ | ((
26
+ client: Client,
27
+ data: RawChannelData,
28
+ guild?: Guild
29
+ ) => Channel | undefined)
30
+ | null = null;
31
+
32
+ function requireGuild(guild: Guild | null | undefined): Guild {
33
+ if (!guild) {
34
+ throw new TypeError('A guild is required to create a guild channel');
35
+ }
36
+ return guild;
37
+ }
38
+
39
+ function buildChannelFactory() {
40
+ const CategoryChannel = require('./CategoryChannel')
41
+ .default as GuildChannelConstructor;
42
+ const DMChannel = require('./DMChannel').default as ClientChannelConstructor;
43
+ const GroupDMChannel = require('./GroupDMChannel')
44
+ .default as ClientChannelConstructor;
45
+ const NewsChannel = require('./NewsChannel')
46
+ .default as GuildChannelConstructor;
47
+ const StageChannel = require('./StageChannel')
48
+ .default as GuildChannelConstructor;
49
+ const StoreChannel = require('./StoreChannel')
50
+ .default as GuildChannelConstructor;
51
+ const TextChannel = require('./TextChannel')
52
+ .default as GuildChannelConstructor;
53
+ const ThreadChannel = require('./ThreadChannel')
54
+ .default as GuildChannelConstructor;
55
+ const VoiceChannel = require('./VoiceChannel')
56
+ .default as GuildChannelConstructor;
57
+ const DirectoryChannel = require('./DirectoryChannel')
58
+ .default as ClientChannelConstructor;
59
+ const ForumChannel = require('./ForumChannel')
60
+ .default as GuildChannelConstructor;
61
+ const MediaChannel = require('./MediaChannel')
62
+ .default as GuildChannelConstructor;
63
+
64
+ const constructDirect = (
65
+ client: Client,
66
+ data: RawChannelData
67
+ ): Channel | undefined => {
68
+ if (
69
+ ('recipients' in data &&
70
+ data.recipients &&
71
+ data.type !== ChannelTypes.GROUP_DM) ||
72
+ data.type === ChannelTypes.DM
73
+ ) {
74
+ return new DMChannel(client, data);
75
+ }
76
+ if (data.type === ChannelTypes.GROUP_DM) {
77
+ return new GroupDMChannel(client, data);
78
+ }
79
+ return undefined;
80
+ };
81
+
82
+ const constructGuild = (
83
+ client: Client,
84
+ data: RawChannelData,
85
+ guild?: Guild
86
+ ): Channel | undefined => {
87
+ switch (data.type) {
88
+ case ChannelTypes.GUILD_TEXT: {
89
+ return new TextChannel(requireGuild(guild), data, client);
90
+ }
91
+ case ChannelTypes.GUILD_VOICE: {
92
+ return new VoiceChannel(requireGuild(guild), data, client);
93
+ }
94
+ case ChannelTypes.GUILD_CATEGORY: {
95
+ return new CategoryChannel(requireGuild(guild), data, client);
96
+ }
97
+ case ChannelTypes.GUILD_NEWS: {
98
+ return new NewsChannel(requireGuild(guild), data, client);
99
+ }
100
+ case ChannelTypes.GUILD_STORE: {
101
+ return new StoreChannel(requireGuild(guild), data, client);
102
+ }
103
+ case ChannelTypes.GUILD_STAGE_VOICE: {
104
+ return new StageChannel(requireGuild(guild), data, client);
105
+ }
106
+ case ChannelTypes.GUILD_NEWS_THREAD:
107
+ case ChannelTypes.GUILD_PUBLIC_THREAD:
108
+ case ChannelTypes.GUILD_PRIVATE_THREAD: {
109
+ return new ThreadChannel(requireGuild(guild), data, client);
110
+ }
111
+ case ChannelTypes.GUILD_DIRECTORY: {
112
+ return new DirectoryChannel(client, data);
113
+ }
114
+ case ChannelTypes.GUILD_FORUM: {
115
+ return new ForumChannel(requireGuild(guild), data, client);
116
+ }
117
+ case ChannelTypes.GUILD_MEDIA: {
118
+ return new MediaChannel(requireGuild(guild), data, client);
119
+ }
120
+ default: {
121
+ return undefined;
122
+ }
123
+ }
124
+ };
125
+
126
+ return (client: Client, data: RawChannelData, guild?: Guild) => {
127
+ const guildId = 'guild_id' in data ? data.guild_id : undefined;
128
+ if (!guildId && !guild) {
129
+ return constructDirect(client, data);
130
+ }
131
+ return constructGuild(client, data, guild);
132
+ };
133
+ }
134
+
135
+ export interface ConstructedChannelRelations {
136
+ guild?: Guild;
137
+ threadParent?: unknown;
138
+ }
139
+
140
+ export function constructChannel(
141
+ client: Client,
142
+ data: RawChannelData,
143
+ guild?: Guild | null,
144
+ { allowUnknownGuild = false }: { allowUnknownGuild?: boolean } = {}
145
+ ): { channel: Channel | undefined; relations: ConstructedChannelRelations } {
146
+ channelFactory ??= buildChannelFactory();
147
+
148
+ const relations: ConstructedChannelRelations = {};
149
+ const guildId = 'guild_id' in data ? data.guild_id : undefined;
150
+ if (!guildId && !guild) {
151
+ return { channel: channelFactory(client, data), relations };
152
+ }
153
+
154
+ const resolvedGuild =
155
+ guild ?? (guildId ? client.guilds.cache.get(guildId) : undefined);
156
+
157
+ if (!resolvedGuild && !allowUnknownGuild) {
158
+ return { channel: undefined, relations };
159
+ }
160
+
161
+ const channel = channelFactory(client, data, resolvedGuild);
162
+ if (channel && resolvedGuild) {
163
+ relations.guild = resolvedGuild;
164
+ }
165
+ if (
166
+ channel &&
167
+ typeof channel.isThread === 'function' &&
168
+ channel.isThread() &&
169
+ 'parent' in channel &&
170
+ channel.parent &&
171
+ isThreadParentChannel(channel.parent as never)
172
+ ) {
173
+ relations.threadParent = channel.parent;
174
+ }
175
+
176
+ return { channel, relations };
177
+ }
@@ -11,6 +11,7 @@ import SnowflakeUtil from '../../util/SnowflakeUtil';
11
11
  import { setTimeout } from 'node:timers';
12
12
  import { s } from '@sapphire/shapeshift';
13
13
  import Util from '../../util/Util';
14
+ import { uploadMessageAttachments } from '../../util/OutboundMessagePipeline';
14
15
  import User from '../User';
15
16
  import _GuildMemberModule from '../GuildMember';
16
17
 
@@ -27,7 +28,6 @@ import type {
27
28
  } from '../../../typings';
28
29
  import type { SendOptions } from '../../types/channels';
29
30
  import type { RawMessageData } from '../../../typings/rawDataTypes';
30
- import type { UploadAttachment } from '../../types/uploads';
31
31
  import type ClientType from '../../client/Client';
32
32
  import type { Guild } from '../Guild';
33
33
 
@@ -615,30 +615,10 @@ class TextBasedChannel {
615
615
  : MessagePayload.create(this, options).resolveData();
616
616
 
617
617
  const { data, files } = await messagePayload.resolveFiles();
618
- const fileList = files ?? [];
619
- // New API
620
- const attachments = await Util.getUploadURL(this.client, this.id, fileList);
621
- const requestPromises = attachments.map(
622
- async (attachment: UploadAttachment) => {
623
- const file = fileList[Number(attachment.id)];
624
- if (!file) {
625
- throw new Error('INVALID_TYPE', 'attachment', 'FileOptions');
626
- }
627
- await Util.uploadFile(file.file, attachment.upload_url);
628
- return {
629
- description: file.description,
630
- duration_secs: file.duration_secs,
631
- filename: file.name,
632
- id: attachment.id,
633
- uploaded_filename: attachment.upload_filename,
634
- waveform: file.waveform,
635
- };
636
- }
637
- );
638
- const attachmentsData = await Promise.all(requestPromises);
639
- attachmentsData.sort(
640
- (left, right) =>
641
- Math.trunc(Number(left.id)) - Math.trunc(Number(right.id))
618
+ const attachmentsData = await uploadMessageAttachments(
619
+ this.client,
620
+ this.id,
621
+ files ?? []
642
622
  );
643
623
  if (data) {
644
624
  Object.assign(data, { attachments: attachmentsData });
@@ -0,0 +1,54 @@
1
+ import Util from './Util';
2
+ import type { Client } from '../client/Client';
3
+ import type { HTTPAttachmentData } from '../../typings';
4
+ import type { UploadAttachment } from '../types/uploads';
5
+
6
+ export interface UploadedMessageAttachment {
7
+ description?: string;
8
+ duration_secs?: number;
9
+ filename: string;
10
+ id: string;
11
+ uploaded_filename: string;
12
+ waveform?: string;
13
+ }
14
+
15
+ export async function uploadMessageAttachments(
16
+ client: Client,
17
+ channelId: string,
18
+ files: HTTPAttachmentData[]
19
+ ): Promise<UploadedMessageAttachment[]> {
20
+ if (!files.length) {
21
+ return [];
22
+ }
23
+
24
+ const uploads = (await Util.getUploadURL(
25
+ client,
26
+ channelId,
27
+ files
28
+ )) as UploadAttachment[];
29
+
30
+ const attachments = await Promise.all(
31
+ uploads.map(async (upload: UploadAttachment) => {
32
+ const file = files[Number(upload.id)];
33
+ if (!file) {
34
+ throw new TypeError('Invalid upload attachment index');
35
+ }
36
+ await Util.uploadFile(file.file, upload.upload_url);
37
+ return {
38
+ description: file.description,
39
+ duration_secs: file.duration_secs,
40
+ filename: file.name,
41
+ id: upload.id,
42
+ uploaded_filename: upload.upload_filename,
43
+ waveform: file.waveform,
44
+ } satisfies UploadedMessageAttachment;
45
+ })
46
+ );
47
+
48
+ attachments.sort(
49
+ (left, right) => Math.trunc(Number(left.id)) - Math.trunc(Number(right.id))
50
+ );
51
+ return attachments;
52
+ }
53
+
54
+ export default { uploadMessageAttachments };