@ovencord/builders 1.11.1
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.
- package/LICENSE +191 -0
- package/README.md +92 -0
- package/package.json +70 -0
- package/src/Assertions.ts +15 -0
- package/src/components/ActionRow.ts +346 -0
- package/src/components/Assertions.ts +190 -0
- package/src/components/Component.ts +47 -0
- package/src/components/Components.ts +275 -0
- package/src/components/button/Button.ts +34 -0
- package/src/components/button/CustomIdButton.ts +74 -0
- package/src/components/button/LinkButton.ts +39 -0
- package/src/components/button/PremiumButton.ts +26 -0
- package/src/components/button/mixins/EmojiOrLabelButtonMixin.ts +52 -0
- package/src/components/fileUpload/Assertions.ts +12 -0
- package/src/components/fileUpload/FileUpload.ts +109 -0
- package/src/components/label/Assertions.ts +28 -0
- package/src/components/label/Label.ts +215 -0
- package/src/components/selectMenu/BaseSelectMenu.ts +89 -0
- package/src/components/selectMenu/ChannelSelectMenu.ts +115 -0
- package/src/components/selectMenu/MentionableSelectMenu.ts +126 -0
- package/src/components/selectMenu/RoleSelectMenu.ts +89 -0
- package/src/components/selectMenu/StringSelectMenu.ts +165 -0
- package/src/components/selectMenu/StringSelectMenuOption.ts +113 -0
- package/src/components/selectMenu/UserSelectMenu.ts +89 -0
- package/src/components/textInput/Assertions.ts +15 -0
- package/src/components/textInput/TextInput.ts +154 -0
- package/src/components/v2/Assertions.ts +82 -0
- package/src/components/v2/Container.ts +254 -0
- package/src/components/v2/File.ts +81 -0
- package/src/components/v2/MediaGallery.ts +128 -0
- package/src/components/v2/MediaGalleryItem.ts +85 -0
- package/src/components/v2/Section.ts +266 -0
- package/src/components/v2/Separator.ts +82 -0
- package/src/components/v2/TextDisplay.ts +63 -0
- package/src/components/v2/Thumbnail.ts +100 -0
- package/src/index.ts +109 -0
- package/src/interactions/commands/Command.ts +87 -0
- package/src/interactions/commands/SharedName.ts +68 -0
- package/src/interactions/commands/SharedNameAndDescription.ts +69 -0
- package/src/interactions/commands/chatInput/Assertions.ts +180 -0
- package/src/interactions/commands/chatInput/ChatInputCommand.ts +40 -0
- package/src/interactions/commands/chatInput/ChatInputCommandSubcommands.ts +117 -0
- package/src/interactions/commands/chatInput/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.ts +52 -0
- package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionChannelTypesMixin.ts +57 -0
- package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionWithAutocompleteMixin.ts +32 -0
- package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionWithChoicesMixin.ts +43 -0
- package/src/interactions/commands/chatInput/mixins/SharedChatInputCommandOptions.ts +204 -0
- package/src/interactions/commands/chatInput/mixins/SharedSubcommands.ts +61 -0
- package/src/interactions/commands/chatInput/options/ApplicationCommandOptionBase.ts +66 -0
- package/src/interactions/commands/chatInput/options/attachment.ts +20 -0
- package/src/interactions/commands/chatInput/options/boolean.ts +20 -0
- package/src/interactions/commands/chatInput/options/channel.ts +28 -0
- package/src/interactions/commands/chatInput/options/integer.ts +34 -0
- package/src/interactions/commands/chatInput/options/mentionable.ts +20 -0
- package/src/interactions/commands/chatInput/options/number.ts +34 -0
- package/src/interactions/commands/chatInput/options/role.ts +20 -0
- package/src/interactions/commands/chatInput/options/string.ts +71 -0
- package/src/interactions/commands/chatInput/options/user.ts +20 -0
- package/src/interactions/commands/contextMenu/Assertions.ts +31 -0
- package/src/interactions/commands/contextMenu/ContextMenuCommand.ts +42 -0
- package/src/interactions/commands/contextMenu/MessageCommand.ts +19 -0
- package/src/interactions/commands/contextMenu/UserCommand.ts +19 -0
- package/src/interactions/modals/Assertions.ts +27 -0
- package/src/interactions/modals/Modal.ts +158 -0
- package/src/messages/AllowedMentions.ts +193 -0
- package/src/messages/Assertions.ts +148 -0
- package/src/messages/Attachment.ts +209 -0
- package/src/messages/Message.ts +692 -0
- package/src/messages/MessageReference.ts +111 -0
- package/src/messages/embed/Assertions.ts +53 -0
- package/src/messages/embed/Embed.ts +352 -0
- package/src/messages/embed/EmbedAuthor.ts +83 -0
- package/src/messages/embed/EmbedField.ts +67 -0
- package/src/messages/embed/EmbedFooter.ts +65 -0
- package/src/messages/poll/Assertions.ts +20 -0
- package/src/messages/poll/Poll.ts +243 -0
- package/src/messages/poll/PollAnswer.ts +77 -0
- package/src/messages/poll/PollAnswerMedia.ts +38 -0
- package/src/messages/poll/PollMedia.ts +41 -0
- package/src/messages/poll/PollQuestion.ts +20 -0
- package/src/util/ValidationError.ts +21 -0
- package/src/util/normalizeArray.ts +19 -0
- package/src/util/resolveBuilder.ts +40 -0
- package/src/util/validation.ts +58 -0
|
@@ -0,0 +1,692 @@
|
|
|
1
|
+
import type { FileBodyEncodable, FileBodyEncodableResult, JSONEncodable, RawFile } from '@ovencord/util';
|
|
2
|
+
import type {
|
|
3
|
+
APIActionRowComponent,
|
|
4
|
+
APIAllowedMentions,
|
|
5
|
+
APIAttachment,
|
|
6
|
+
APIEmbed,
|
|
7
|
+
APIComponentInMessageActionRow,
|
|
8
|
+
APIMessageReference,
|
|
9
|
+
APIPoll,
|
|
10
|
+
RESTPostAPIChannelMessageJSONBody,
|
|
11
|
+
Snowflake,
|
|
12
|
+
MessageFlags,
|
|
13
|
+
APIContainerComponent,
|
|
14
|
+
APIFileComponent,
|
|
15
|
+
APIMediaGalleryComponent,
|
|
16
|
+
APISectionComponent,
|
|
17
|
+
APISeparatorComponent,
|
|
18
|
+
APITextDisplayComponent,
|
|
19
|
+
APIMessageTopLevelComponent,
|
|
20
|
+
} from 'discord-api-types/v10';
|
|
21
|
+
import { ActionRowBuilder } from '../components/ActionRow.js';
|
|
22
|
+
import { ComponentBuilder } from '../components/Component.js';
|
|
23
|
+
import type { MessageTopLevelComponentBuilder } from '../components/Components.js';
|
|
24
|
+
import { createComponentBuilder } from '../components/Components.js';
|
|
25
|
+
import { ContainerBuilder } from '../components/v2/Container.js';
|
|
26
|
+
import { FileBuilder } from '../components/v2/File.js';
|
|
27
|
+
import { MediaGalleryBuilder } from '../components/v2/MediaGallery.js';
|
|
28
|
+
import { SectionBuilder } from '../components/v2/Section.js';
|
|
29
|
+
import { SeparatorBuilder } from '../components/v2/Separator.js';
|
|
30
|
+
import { TextDisplayBuilder } from '../components/v2/TextDisplay.js';
|
|
31
|
+
import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';
|
|
32
|
+
import { resolveBuilder } from '../util/resolveBuilder.js';
|
|
33
|
+
import { validate } from '../util/validation.js';
|
|
34
|
+
import { AllowedMentionsBuilder } from './AllowedMentions.js';
|
|
35
|
+
import { fileBodyMessagePredicate, messagePredicate } from './Assertions.js';
|
|
36
|
+
import { AttachmentBuilder } from './Attachment.js';
|
|
37
|
+
import { MessageReferenceBuilder } from './MessageReference.js';
|
|
38
|
+
import { EmbedBuilder } from './embed/Embed.js';
|
|
39
|
+
import { PollBuilder } from './poll/Poll.js';
|
|
40
|
+
|
|
41
|
+
export interface MessageBuilderData extends Partial<
|
|
42
|
+
Omit<
|
|
43
|
+
RESTPostAPIChannelMessageJSONBody,
|
|
44
|
+
'allowed_mentions' | 'attachments' | 'components' | 'embeds' | 'message_reference' | 'poll'
|
|
45
|
+
>
|
|
46
|
+
> {
|
|
47
|
+
allowed_mentions?: AllowedMentionsBuilder;
|
|
48
|
+
attachments: AttachmentBuilder[];
|
|
49
|
+
components: MessageTopLevelComponentBuilder[];
|
|
50
|
+
embeds: EmbedBuilder[];
|
|
51
|
+
message_reference?: MessageReferenceBuilder;
|
|
52
|
+
poll?: PollBuilder;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A builder that creates API-compatible JSON data for messages.
|
|
57
|
+
*/
|
|
58
|
+
export class MessageBuilder
|
|
59
|
+
implements JSONEncodable<RESTPostAPIChannelMessageJSONBody>, FileBodyEncodable<RESTPostAPIChannelMessageJSONBody>
|
|
60
|
+
{
|
|
61
|
+
/**
|
|
62
|
+
* The API data associated with this message.
|
|
63
|
+
*/
|
|
64
|
+
private readonly data: MessageBuilderData;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Gets the attachments of this message.
|
|
68
|
+
*/
|
|
69
|
+
public get attachments(): readonly AttachmentBuilder[] {
|
|
70
|
+
return this.data.attachments;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Gets the components of this message.
|
|
75
|
+
*/
|
|
76
|
+
public get components(): readonly MessageTopLevelComponentBuilder[] {
|
|
77
|
+
return this.data.components;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Gets the embeds of this message.
|
|
82
|
+
*/
|
|
83
|
+
public get embeds(): readonly EmbedBuilder[] {
|
|
84
|
+
return this.data.embeds;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Creates a new message builder.
|
|
89
|
+
*
|
|
90
|
+
* @param data - The API data to create this message with
|
|
91
|
+
*/
|
|
92
|
+
public constructor(data: Partial<RESTPostAPIChannelMessageJSONBody> = {}) {
|
|
93
|
+
const { attachments = [], embeds = [], components = [], message_reference, poll, allowed_mentions, ...rest } = data;
|
|
94
|
+
|
|
95
|
+
this.data = {
|
|
96
|
+
...structuredClone(rest),
|
|
97
|
+
allowed_mentions: allowed_mentions && new AllowedMentionsBuilder(allowed_mentions),
|
|
98
|
+
attachments: attachments.map((attachment) => new AttachmentBuilder(attachment)),
|
|
99
|
+
embeds: embeds.map((embed) => new EmbedBuilder(embed)),
|
|
100
|
+
poll: poll && new PollBuilder(poll),
|
|
101
|
+
components: components.map((component) => createComponentBuilder(component)),
|
|
102
|
+
message_reference: message_reference && new MessageReferenceBuilder(message_reference),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Sets the content of the message.
|
|
108
|
+
*
|
|
109
|
+
* @param content - The content to set
|
|
110
|
+
*/
|
|
111
|
+
public setContent(content: string): this {
|
|
112
|
+
this.data.content = content;
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Clears the content of the message.
|
|
118
|
+
*/
|
|
119
|
+
public clearContent(): this {
|
|
120
|
+
this.data.content = undefined;
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Sets the nonce of the message.
|
|
126
|
+
*
|
|
127
|
+
* @param nonce - The nonce to set
|
|
128
|
+
*/
|
|
129
|
+
public setNonce(nonce: number | string): this {
|
|
130
|
+
this.data.nonce = nonce;
|
|
131
|
+
return this;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Clears the nonce of the message.
|
|
136
|
+
*/
|
|
137
|
+
public clearNonce(): this {
|
|
138
|
+
this.data.nonce = undefined;
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Sets whether the message is TTS.
|
|
144
|
+
*
|
|
145
|
+
* @param tts - Whether the message is TTS
|
|
146
|
+
*/
|
|
147
|
+
public setTTS(tts = true): this {
|
|
148
|
+
this.data.tts = tts;
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Appends embeds to this message.
|
|
154
|
+
*
|
|
155
|
+
* @remarks
|
|
156
|
+
* The maximum amount of embeds that can be added is 10.
|
|
157
|
+
* @example
|
|
158
|
+
* Using an array:
|
|
159
|
+
* ```ts
|
|
160
|
+
* const embeds: APIEmbed[] = ...;
|
|
161
|
+
* const message = new MessageBuilder()
|
|
162
|
+
* .addEmbeds(embeds);
|
|
163
|
+
* ```
|
|
164
|
+
* @example
|
|
165
|
+
* Using rest parameters (variadic):
|
|
166
|
+
* ```ts
|
|
167
|
+
* const message = new MessageBuilder()
|
|
168
|
+
* .addEmbeds(
|
|
169
|
+
* { title: 'Embed 1' },
|
|
170
|
+
* { title: 'Embed 2' },
|
|
171
|
+
* );
|
|
172
|
+
* ```
|
|
173
|
+
* @param embeds - The embeds to add
|
|
174
|
+
*/
|
|
175
|
+
public addEmbeds(...embeds: RestOrArray<APIEmbed | EmbedBuilder | ((builder: EmbedBuilder) => EmbedBuilder)>): this {
|
|
176
|
+
this.data.embeds ??= [];
|
|
177
|
+
|
|
178
|
+
const resolved = normalizeArray(embeds).map((embed) => resolveBuilder(embed, EmbedBuilder));
|
|
179
|
+
this.data.embeds.push(...resolved);
|
|
180
|
+
|
|
181
|
+
return this;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Removes, replaces, or inserts embeds for this message.
|
|
186
|
+
*
|
|
187
|
+
* @remarks
|
|
188
|
+
* This method behaves similarly
|
|
189
|
+
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
|
|
190
|
+
*
|
|
191
|
+
* It's useful for modifying and adjusting order of the already-existing embeds of a message.
|
|
192
|
+
* @example
|
|
193
|
+
* Remove the first embed:
|
|
194
|
+
* ```ts
|
|
195
|
+
* message.spliceEmbeds(0, 1);
|
|
196
|
+
* ```
|
|
197
|
+
* @example
|
|
198
|
+
* Remove the first n embeds:
|
|
199
|
+
* ```ts
|
|
200
|
+
* const n = 4;
|
|
201
|
+
* message.spliceEmbeds(0, n);
|
|
202
|
+
* ```
|
|
203
|
+
* @example
|
|
204
|
+
* Remove the last embed:
|
|
205
|
+
* ```ts
|
|
206
|
+
* message.spliceEmbeds(-1, 1);
|
|
207
|
+
* ```
|
|
208
|
+
* @param start - The index to start at
|
|
209
|
+
* @param deleteCount - The amount of embeds to remove
|
|
210
|
+
* @param embeds - The embeds to insert
|
|
211
|
+
*/
|
|
212
|
+
public spliceEmbeds(
|
|
213
|
+
start: number,
|
|
214
|
+
deleteCount: number,
|
|
215
|
+
...embeds: RestOrArray<APIEmbed | EmbedBuilder | ((builder: EmbedBuilder) => EmbedBuilder)>
|
|
216
|
+
): this {
|
|
217
|
+
this.data.embeds ??= [];
|
|
218
|
+
const resolved = normalizeArray(embeds).map((embed) => resolveBuilder(embed, EmbedBuilder));
|
|
219
|
+
|
|
220
|
+
this.data.embeds.splice(start, deleteCount, ...resolved);
|
|
221
|
+
return this;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Sets the embeds for this message.
|
|
226
|
+
*
|
|
227
|
+
* @param embeds - The embeds to set
|
|
228
|
+
*/
|
|
229
|
+
public setEmbeds(...embeds: RestOrArray<APIEmbed | EmbedBuilder | ((builder: EmbedBuilder) => EmbedBuilder)>): this {
|
|
230
|
+
return this.spliceEmbeds(0, this.embeds.length, ...normalizeArray(embeds));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Sets the allowed mentions for this message.
|
|
235
|
+
*
|
|
236
|
+
* @param allowedMentions - The allowed mentions to set
|
|
237
|
+
*/
|
|
238
|
+
public setAllowedMentions(
|
|
239
|
+
allowedMentions:
|
|
240
|
+
| AllowedMentionsBuilder
|
|
241
|
+
| APIAllowedMentions
|
|
242
|
+
| ((builder: AllowedMentionsBuilder) => AllowedMentionsBuilder) = new AllowedMentionsBuilder(),
|
|
243
|
+
): this {
|
|
244
|
+
this.data.allowed_mentions = resolveBuilder(allowedMentions, AllowedMentionsBuilder);
|
|
245
|
+
return this;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Updates the allowed mentions for this message (and creates it if it doesn't exist)
|
|
250
|
+
*
|
|
251
|
+
* @param updater - The function to update the allowed mentions with
|
|
252
|
+
*/
|
|
253
|
+
public updateAllowedMentions(updater: (builder: AllowedMentionsBuilder) => void): this {
|
|
254
|
+
updater((this.data.allowed_mentions ??= new AllowedMentionsBuilder()));
|
|
255
|
+
return this;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Clears the allowed mentions for this message.
|
|
260
|
+
*/
|
|
261
|
+
public clearAllowedMentions(): this {
|
|
262
|
+
this.data.allowed_mentions = undefined;
|
|
263
|
+
return this;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Sets the message reference for this message.
|
|
268
|
+
*
|
|
269
|
+
* @param reference - The reference to set
|
|
270
|
+
*/
|
|
271
|
+
public setMessageReference(
|
|
272
|
+
reference:
|
|
273
|
+
| APIMessageReference
|
|
274
|
+
| MessageReferenceBuilder
|
|
275
|
+
| ((builder: MessageReferenceBuilder) => MessageReferenceBuilder),
|
|
276
|
+
): this {
|
|
277
|
+
this.data.message_reference = resolveBuilder(reference, MessageReferenceBuilder);
|
|
278
|
+
return this;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Updates the message reference for this message (and creates it if it doesn't exist)
|
|
283
|
+
*
|
|
284
|
+
* @param updater - The function to update the message reference with
|
|
285
|
+
*/
|
|
286
|
+
public updateMessageReference(updater: (builder: MessageReferenceBuilder) => void): this {
|
|
287
|
+
updater((this.data.message_reference ??= new MessageReferenceBuilder()));
|
|
288
|
+
return this;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Clears the message reference for this message.
|
|
293
|
+
*/
|
|
294
|
+
public clearMessageReference(): this {
|
|
295
|
+
this.data.message_reference = undefined;
|
|
296
|
+
return this;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Adds action row components to this message.
|
|
301
|
+
*
|
|
302
|
+
* @param components - The action row components to add
|
|
303
|
+
*/
|
|
304
|
+
public addActionRowComponents(
|
|
305
|
+
...components: RestOrArray<
|
|
306
|
+
| ActionRowBuilder
|
|
307
|
+
| APIActionRowComponent<APIComponentInMessageActionRow>
|
|
308
|
+
| ((builder: ActionRowBuilder) => ActionRowBuilder)
|
|
309
|
+
>
|
|
310
|
+
): this {
|
|
311
|
+
this.data.components ??= [];
|
|
312
|
+
|
|
313
|
+
const resolved = normalizeArray(components).map((component) => resolveBuilder(component, ActionRowBuilder));
|
|
314
|
+
this.data.components.push(...resolved);
|
|
315
|
+
|
|
316
|
+
return this;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Adds container components to this message.
|
|
321
|
+
*
|
|
322
|
+
* @param components - The container components to add
|
|
323
|
+
*/
|
|
324
|
+
public addContainerComponents(
|
|
325
|
+
...components: RestOrArray<
|
|
326
|
+
APIContainerComponent | ContainerBuilder | ((builder: ContainerBuilder) => ContainerBuilder)
|
|
327
|
+
>
|
|
328
|
+
): this {
|
|
329
|
+
this.data.components ??= [];
|
|
330
|
+
|
|
331
|
+
const resolved = normalizeArray(components).map((component) => resolveBuilder(component, ContainerBuilder));
|
|
332
|
+
this.data.components.push(...resolved);
|
|
333
|
+
|
|
334
|
+
return this;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Adds file components to this message.
|
|
339
|
+
*
|
|
340
|
+
* @param components - The file components to add
|
|
341
|
+
*/
|
|
342
|
+
public addFileComponents(
|
|
343
|
+
...components: RestOrArray<APIFileComponent | FileBuilder | ((builder: FileBuilder) => FileBuilder)>
|
|
344
|
+
): this {
|
|
345
|
+
this.data.components ??= [];
|
|
346
|
+
|
|
347
|
+
const resolved = normalizeArray(components).map((component) => resolveBuilder(component, FileBuilder));
|
|
348
|
+
this.data.components.push(...resolved);
|
|
349
|
+
|
|
350
|
+
return this;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Adds media gallery components to this message.
|
|
355
|
+
*
|
|
356
|
+
* @param components - The media gallery components to add
|
|
357
|
+
*/
|
|
358
|
+
public addMediaGalleryComponents(
|
|
359
|
+
...components: RestOrArray<
|
|
360
|
+
APIMediaGalleryComponent | MediaGalleryBuilder | ((builder: MediaGalleryBuilder) => MediaGalleryBuilder)
|
|
361
|
+
>
|
|
362
|
+
): this {
|
|
363
|
+
this.data.components ??= [];
|
|
364
|
+
|
|
365
|
+
const resolved = normalizeArray(components).map((component) => resolveBuilder(component, MediaGalleryBuilder));
|
|
366
|
+
this.data.components.push(...resolved);
|
|
367
|
+
|
|
368
|
+
return this;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Adds section components to this message.
|
|
373
|
+
*
|
|
374
|
+
* @param components - The section components to add
|
|
375
|
+
*/
|
|
376
|
+
public addSectionComponents(
|
|
377
|
+
...components: RestOrArray<APISectionComponent | SectionBuilder | ((builder: SectionBuilder) => SectionBuilder)>
|
|
378
|
+
): this {
|
|
379
|
+
this.data.components ??= [];
|
|
380
|
+
|
|
381
|
+
const resolved = normalizeArray(components).map((component) => resolveBuilder(component, SectionBuilder));
|
|
382
|
+
this.data.components.push(...resolved);
|
|
383
|
+
|
|
384
|
+
return this;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Adds separator components to this message.
|
|
389
|
+
*
|
|
390
|
+
* @param components - The separator components to add
|
|
391
|
+
*/
|
|
392
|
+
public addSeparatorComponents(
|
|
393
|
+
...components: RestOrArray<
|
|
394
|
+
APISeparatorComponent | SeparatorBuilder | ((builder: SeparatorBuilder) => SeparatorBuilder)
|
|
395
|
+
>
|
|
396
|
+
): this {
|
|
397
|
+
this.data.components ??= [];
|
|
398
|
+
|
|
399
|
+
const resolved = normalizeArray(components).map((component) => resolveBuilder(component, SeparatorBuilder));
|
|
400
|
+
this.data.components.push(...resolved);
|
|
401
|
+
|
|
402
|
+
return this;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Adds text display components to this message.
|
|
407
|
+
*
|
|
408
|
+
* @param components - The text display components to add
|
|
409
|
+
*/
|
|
410
|
+
public addTextDisplayComponents(
|
|
411
|
+
...components: RestOrArray<
|
|
412
|
+
APITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)
|
|
413
|
+
>
|
|
414
|
+
): this {
|
|
415
|
+
this.data.components ??= [];
|
|
416
|
+
|
|
417
|
+
const resolved = normalizeArray(components).map((component) => resolveBuilder(component, TextDisplayBuilder));
|
|
418
|
+
this.data.components.push(...resolved);
|
|
419
|
+
|
|
420
|
+
return this;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Removes, replaces, or inserts components for this message.
|
|
425
|
+
*
|
|
426
|
+
* @remarks
|
|
427
|
+
* This method behaves similarly
|
|
428
|
+
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
|
|
429
|
+
*
|
|
430
|
+
* It's useful for modifying and adjusting order of the already-existing components of a message.
|
|
431
|
+
* @example
|
|
432
|
+
* Remove the first component:
|
|
433
|
+
* ```ts
|
|
434
|
+
* message.spliceComponents(0, 1);
|
|
435
|
+
* ```
|
|
436
|
+
* @example
|
|
437
|
+
* Remove the first n components:
|
|
438
|
+
* ```ts
|
|
439
|
+
* const n = 4;
|
|
440
|
+
* message.spliceComponents(0, n);
|
|
441
|
+
* ```
|
|
442
|
+
* @example
|
|
443
|
+
* Remove the last component:
|
|
444
|
+
* ```ts
|
|
445
|
+
* message.spliceComponents(-1, 1);
|
|
446
|
+
* ```
|
|
447
|
+
* @param start - The index to start at
|
|
448
|
+
* @param deleteCount - The amount of components to remove
|
|
449
|
+
* @param components - The components to insert
|
|
450
|
+
*/
|
|
451
|
+
public spliceComponents(
|
|
452
|
+
start: number,
|
|
453
|
+
deleteCount: number,
|
|
454
|
+
...components: RestOrArray<APIMessageTopLevelComponent | MessageTopLevelComponentBuilder>
|
|
455
|
+
): this {
|
|
456
|
+
this.data.components ??= [];
|
|
457
|
+
const resolved = normalizeArray(components).map((component) =>
|
|
458
|
+
component instanceof ComponentBuilder ? component : createComponentBuilder(component),
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
this.data.components.splice(start, deleteCount, ...resolved);
|
|
462
|
+
return this;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Sets the sticker ids of this message.
|
|
467
|
+
*
|
|
468
|
+
* @param stickerIds - The ids of the stickers to set
|
|
469
|
+
*/
|
|
470
|
+
public setStickerIds(...stickerIds: RestOrArray<Snowflake>): this {
|
|
471
|
+
return this.spliceStickerIds(0, this.data.sticker_ids?.length ?? 0, ...normalizeArray(stickerIds));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Adds sticker ids to this message.
|
|
476
|
+
*
|
|
477
|
+
* @param stickerIds - The ids of the stickers to add
|
|
478
|
+
*/
|
|
479
|
+
public addStickerIds(...stickerIds: RestOrArray<Snowflake>): this {
|
|
480
|
+
this.data.sticker_ids ??= [] as unknown as MessageBuilderData['sticker_ids'];
|
|
481
|
+
this.data.sticker_ids!.push(...normalizeArray(stickerIds));
|
|
482
|
+
return this;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Removes, replaces, or inserts sticker ids for this message.
|
|
487
|
+
*
|
|
488
|
+
* @remarks
|
|
489
|
+
* This method behaves similarly
|
|
490
|
+
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
|
|
491
|
+
*
|
|
492
|
+
* It's useful for modifying and adjusting order of the already-existing sticker ids of a message.
|
|
493
|
+
* @example
|
|
494
|
+
* Remove the first sticker id:
|
|
495
|
+
* ```ts
|
|
496
|
+
* message.spliceStickerIds(0, 1);
|
|
497
|
+
* ```
|
|
498
|
+
* @example
|
|
499
|
+
* Remove the first n sticker ids:
|
|
500
|
+
* ```ts
|
|
501
|
+
* const n = 4;
|
|
502
|
+
* message.spliceStickerIds(0, n);
|
|
503
|
+
* ```
|
|
504
|
+
* @example
|
|
505
|
+
* Remove the last sticker id:
|
|
506
|
+
* ```ts
|
|
507
|
+
* message.spliceStickerIds(-1, 1);
|
|
508
|
+
* ```
|
|
509
|
+
* @param index - The index to start at
|
|
510
|
+
* @param deleteCount - The amount of sticker ids to remove
|
|
511
|
+
* @param stickerIds - The sticker ids to insert
|
|
512
|
+
*/
|
|
513
|
+
public spliceStickerIds(index: number, deleteCount: number, ...stickerIds: RestOrArray<Snowflake>): this {
|
|
514
|
+
this.data.sticker_ids ??= [] as unknown as MessageBuilderData['sticker_ids'];
|
|
515
|
+
this.data.sticker_ids!.splice(index, deleteCount, ...normalizeArray(stickerIds));
|
|
516
|
+
return this;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Sets attachments for this message.
|
|
521
|
+
*
|
|
522
|
+
* @param attachments - The attachments to set
|
|
523
|
+
*/
|
|
524
|
+
public setAttachments(
|
|
525
|
+
...attachments: RestOrArray<APIAttachment | AttachmentBuilder | ((builder: AttachmentBuilder) => AttachmentBuilder)>
|
|
526
|
+
): this {
|
|
527
|
+
return this.spliceAttachments(0, this.data.attachments.length, ...normalizeArray(attachments));
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Adds attachments to this message.
|
|
532
|
+
*
|
|
533
|
+
* @param attachments - The attachments to add
|
|
534
|
+
*/
|
|
535
|
+
public addAttachments(
|
|
536
|
+
...attachments: RestOrArray<APIAttachment | AttachmentBuilder | ((builder: AttachmentBuilder) => AttachmentBuilder)>
|
|
537
|
+
): this {
|
|
538
|
+
const resolved = normalizeArray(attachments).map((attachment) => resolveBuilder(attachment, AttachmentBuilder));
|
|
539
|
+
this.data.attachments.push(...resolved);
|
|
540
|
+
|
|
541
|
+
return this;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Removes, replaces, or inserts attachments for this message.
|
|
546
|
+
*
|
|
547
|
+
* @remarks
|
|
548
|
+
* This method behaves similarly
|
|
549
|
+
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
|
|
550
|
+
*
|
|
551
|
+
* It's useful for modifying and adjusting order of the already-existing attachments of a message.
|
|
552
|
+
* @example
|
|
553
|
+
* Remove the first attachment:
|
|
554
|
+
* ```ts
|
|
555
|
+
* message.spliceAttachments(0, 1);
|
|
556
|
+
* ```
|
|
557
|
+
* @example
|
|
558
|
+
* Remove the first n attachments:
|
|
559
|
+
* ```ts
|
|
560
|
+
* const n = 4;
|
|
561
|
+
* message.spliceAttachments(0, n);
|
|
562
|
+
* ```
|
|
563
|
+
* @example
|
|
564
|
+
* Remove the last attachment:
|
|
565
|
+
* ```ts
|
|
566
|
+
* message.spliceAttachments(-1, 1);
|
|
567
|
+
* ```
|
|
568
|
+
* @param start - The index to start at
|
|
569
|
+
* @param deleteCount - The amount of attachments to remove
|
|
570
|
+
* @param attachments - The attachments to insert
|
|
571
|
+
*/
|
|
572
|
+
public spliceAttachments(
|
|
573
|
+
start: number,
|
|
574
|
+
deleteCount: number,
|
|
575
|
+
...attachments: RestOrArray<APIAttachment | AttachmentBuilder | ((builder: AttachmentBuilder) => AttachmentBuilder)>
|
|
576
|
+
): this {
|
|
577
|
+
const resolved = normalizeArray(attachments).map((attachment) => resolveBuilder(attachment, AttachmentBuilder));
|
|
578
|
+
this.data.attachments.splice(start, deleteCount, ...resolved);
|
|
579
|
+
|
|
580
|
+
return this;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Sets the flags for this message.
|
|
585
|
+
*
|
|
586
|
+
* @param flags - The flags to set
|
|
587
|
+
*/
|
|
588
|
+
public setFlags(flags: MessageFlags): this {
|
|
589
|
+
this.data.flags = flags;
|
|
590
|
+
return this;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Clears the flags for this message.
|
|
595
|
+
*/
|
|
596
|
+
public clearFlags(): this {
|
|
597
|
+
this.data.flags = undefined;
|
|
598
|
+
return this;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Sets whether to enforce recent uniqueness of the nonce of this message.
|
|
603
|
+
*
|
|
604
|
+
* @param enforceNonce - Whether to enforce recent uniqueness of the nonce of this message
|
|
605
|
+
*/
|
|
606
|
+
public setEnforceNonce(enforceNonce = true): this {
|
|
607
|
+
this.data.enforce_nonce = enforceNonce;
|
|
608
|
+
return this;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Sets the poll for this message.
|
|
613
|
+
*
|
|
614
|
+
* @param poll - The poll to set
|
|
615
|
+
*/
|
|
616
|
+
public setPoll(poll: APIPoll | PollBuilder | ((builder: PollBuilder) => PollBuilder)): this {
|
|
617
|
+
this.data.poll = resolveBuilder(poll, PollBuilder);
|
|
618
|
+
return this;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Updates the poll for this message (and creates it if it doesn't exist)
|
|
623
|
+
*
|
|
624
|
+
* @param updater - The function to update the poll with
|
|
625
|
+
*/
|
|
626
|
+
public updatePoll(updater: (builder: PollBuilder) => void): this {
|
|
627
|
+
updater((this.data.poll ??= new PollBuilder()));
|
|
628
|
+
return this;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Clears the poll for this message.
|
|
633
|
+
*/
|
|
634
|
+
public clearPoll(): this {
|
|
635
|
+
this.data.poll = undefined;
|
|
636
|
+
return this;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Serializes this builder to API-compatible JSON data.
|
|
641
|
+
*
|
|
642
|
+
* Note that by disabling validation, there is no guarantee that the resulting object will be valid.
|
|
643
|
+
*
|
|
644
|
+
* @param validationOverride - Force validation to run/not run regardless of your global preference
|
|
645
|
+
*/
|
|
646
|
+
public toJSON(validationOverride?: boolean): RESTPostAPIChannelMessageJSONBody {
|
|
647
|
+
const { poll, allowed_mentions, attachments, embeds, components, message_reference, ...rest } = this.data;
|
|
648
|
+
|
|
649
|
+
const data = {
|
|
650
|
+
...structuredClone(rest),
|
|
651
|
+
// Wherever we pass false, it's covered by the messagePredicate already
|
|
652
|
+
poll: poll?.toJSON(false),
|
|
653
|
+
allowed_mentions: allowed_mentions?.toJSON(false),
|
|
654
|
+
attachments: attachments.map((attachment) => attachment.toJSON(false)),
|
|
655
|
+
embeds: embeds.map((embed) => embed.toJSON(false)),
|
|
656
|
+
// Here, the messagePredicate does specific constraints rather than using the componentPredicate
|
|
657
|
+
components: components.map((component) => component.toJSON(validationOverride)),
|
|
658
|
+
message_reference: message_reference?.toJSON(false),
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
validate(messagePredicate, data, validationOverride);
|
|
662
|
+
|
|
663
|
+
return data as RESTPostAPIChannelMessageJSONBody;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Serializes this builder to both JSON body and file data for multipart/form-data requests.
|
|
668
|
+
*
|
|
669
|
+
* @param validationOverride - Force validation to run/not run regardless of your global preference
|
|
670
|
+
* @remarks
|
|
671
|
+
* This method extracts file data from attachments that have files set via {@link AttachmentBuilder.setFileData}.
|
|
672
|
+
* The returned body includes attachment metadata, while files contains the binary data for upload.
|
|
673
|
+
*/
|
|
674
|
+
public toFileBody(validationOverride?: boolean): FileBodyEncodableResult<RESTPostAPIChannelMessageJSONBody> {
|
|
675
|
+
const body = this.toJSON(false);
|
|
676
|
+
|
|
677
|
+
const files: RawFile[] = [];
|
|
678
|
+
for (const attachment of this.data.attachments) {
|
|
679
|
+
const rawFile = attachment.getRawFile();
|
|
680
|
+
// Only if data or content type are set, since that implies the intent is to send a new file.
|
|
681
|
+
// In case it's contentType but not data, a validation error will be thrown right after.
|
|
682
|
+
if (rawFile?.data || rawFile?.contentType) {
|
|
683
|
+
files.push(rawFile as RawFile);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const combined = { body, files };
|
|
688
|
+
validate(fileBodyMessagePredicate, combined, validationOverride);
|
|
689
|
+
|
|
690
|
+
return combined as FileBodyEncodableResult<RESTPostAPIChannelMessageJSONBody>;
|
|
691
|
+
}
|
|
692
|
+
}
|