@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.
Files changed (84) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +92 -0
  3. package/package.json +70 -0
  4. package/src/Assertions.ts +15 -0
  5. package/src/components/ActionRow.ts +346 -0
  6. package/src/components/Assertions.ts +190 -0
  7. package/src/components/Component.ts +47 -0
  8. package/src/components/Components.ts +275 -0
  9. package/src/components/button/Button.ts +34 -0
  10. package/src/components/button/CustomIdButton.ts +74 -0
  11. package/src/components/button/LinkButton.ts +39 -0
  12. package/src/components/button/PremiumButton.ts +26 -0
  13. package/src/components/button/mixins/EmojiOrLabelButtonMixin.ts +52 -0
  14. package/src/components/fileUpload/Assertions.ts +12 -0
  15. package/src/components/fileUpload/FileUpload.ts +109 -0
  16. package/src/components/label/Assertions.ts +28 -0
  17. package/src/components/label/Label.ts +215 -0
  18. package/src/components/selectMenu/BaseSelectMenu.ts +89 -0
  19. package/src/components/selectMenu/ChannelSelectMenu.ts +115 -0
  20. package/src/components/selectMenu/MentionableSelectMenu.ts +126 -0
  21. package/src/components/selectMenu/RoleSelectMenu.ts +89 -0
  22. package/src/components/selectMenu/StringSelectMenu.ts +165 -0
  23. package/src/components/selectMenu/StringSelectMenuOption.ts +113 -0
  24. package/src/components/selectMenu/UserSelectMenu.ts +89 -0
  25. package/src/components/textInput/Assertions.ts +15 -0
  26. package/src/components/textInput/TextInput.ts +154 -0
  27. package/src/components/v2/Assertions.ts +82 -0
  28. package/src/components/v2/Container.ts +254 -0
  29. package/src/components/v2/File.ts +81 -0
  30. package/src/components/v2/MediaGallery.ts +128 -0
  31. package/src/components/v2/MediaGalleryItem.ts +85 -0
  32. package/src/components/v2/Section.ts +266 -0
  33. package/src/components/v2/Separator.ts +82 -0
  34. package/src/components/v2/TextDisplay.ts +63 -0
  35. package/src/components/v2/Thumbnail.ts +100 -0
  36. package/src/index.ts +109 -0
  37. package/src/interactions/commands/Command.ts +87 -0
  38. package/src/interactions/commands/SharedName.ts +68 -0
  39. package/src/interactions/commands/SharedNameAndDescription.ts +69 -0
  40. package/src/interactions/commands/chatInput/Assertions.ts +180 -0
  41. package/src/interactions/commands/chatInput/ChatInputCommand.ts +40 -0
  42. package/src/interactions/commands/chatInput/ChatInputCommandSubcommands.ts +117 -0
  43. package/src/interactions/commands/chatInput/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.ts +52 -0
  44. package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionChannelTypesMixin.ts +57 -0
  45. package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionWithAutocompleteMixin.ts +32 -0
  46. package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionWithChoicesMixin.ts +43 -0
  47. package/src/interactions/commands/chatInput/mixins/SharedChatInputCommandOptions.ts +204 -0
  48. package/src/interactions/commands/chatInput/mixins/SharedSubcommands.ts +61 -0
  49. package/src/interactions/commands/chatInput/options/ApplicationCommandOptionBase.ts +66 -0
  50. package/src/interactions/commands/chatInput/options/attachment.ts +20 -0
  51. package/src/interactions/commands/chatInput/options/boolean.ts +20 -0
  52. package/src/interactions/commands/chatInput/options/channel.ts +28 -0
  53. package/src/interactions/commands/chatInput/options/integer.ts +34 -0
  54. package/src/interactions/commands/chatInput/options/mentionable.ts +20 -0
  55. package/src/interactions/commands/chatInput/options/number.ts +34 -0
  56. package/src/interactions/commands/chatInput/options/role.ts +20 -0
  57. package/src/interactions/commands/chatInput/options/string.ts +71 -0
  58. package/src/interactions/commands/chatInput/options/user.ts +20 -0
  59. package/src/interactions/commands/contextMenu/Assertions.ts +31 -0
  60. package/src/interactions/commands/contextMenu/ContextMenuCommand.ts +42 -0
  61. package/src/interactions/commands/contextMenu/MessageCommand.ts +19 -0
  62. package/src/interactions/commands/contextMenu/UserCommand.ts +19 -0
  63. package/src/interactions/modals/Assertions.ts +27 -0
  64. package/src/interactions/modals/Modal.ts +158 -0
  65. package/src/messages/AllowedMentions.ts +193 -0
  66. package/src/messages/Assertions.ts +148 -0
  67. package/src/messages/Attachment.ts +209 -0
  68. package/src/messages/Message.ts +692 -0
  69. package/src/messages/MessageReference.ts +111 -0
  70. package/src/messages/embed/Assertions.ts +53 -0
  71. package/src/messages/embed/Embed.ts +352 -0
  72. package/src/messages/embed/EmbedAuthor.ts +83 -0
  73. package/src/messages/embed/EmbedField.ts +67 -0
  74. package/src/messages/embed/EmbedFooter.ts +65 -0
  75. package/src/messages/poll/Assertions.ts +20 -0
  76. package/src/messages/poll/Poll.ts +243 -0
  77. package/src/messages/poll/PollAnswer.ts +77 -0
  78. package/src/messages/poll/PollAnswerMedia.ts +38 -0
  79. package/src/messages/poll/PollMedia.ts +41 -0
  80. package/src/messages/poll/PollQuestion.ts +20 -0
  81. package/src/util/ValidationError.ts +21 -0
  82. package/src/util/normalizeArray.ts +19 -0
  83. package/src/util/resolveBuilder.ts +40 -0
  84. package/src/util/validation.ts +58 -0
@@ -0,0 +1,111 @@
1
+ import type { JSONEncodable } from '@ovencord/util';
2
+ import type { MessageReferenceType, RESTAPIMessageReference, Snowflake } from 'discord-api-types/v10';
3
+ import { validate } from '../util/validation.js';
4
+ import { messageReferencePredicate } from './Assertions.js';
5
+
6
+ /**
7
+ * A builder that creates API-compatible JSON data for message references.
8
+ */
9
+ export class MessageReferenceBuilder implements JSONEncodable<RESTAPIMessageReference> {
10
+ /**
11
+ * The API data associated with this message reference.
12
+ */
13
+ private readonly data: Partial<RESTAPIMessageReference>;
14
+
15
+ /**
16
+ * Creates a new message reference builder.
17
+ *
18
+ * @param data - The API data to create this message reference with
19
+ */
20
+ public constructor(data: Partial<RESTAPIMessageReference> = {}) {
21
+ this.data = structuredClone(data);
22
+ }
23
+
24
+ /**
25
+ * Sets the type of message reference this represents
26
+ *
27
+ * @param type - The type of message reference
28
+ */
29
+ public setType(type: MessageReferenceType): this {
30
+ this.data.type = type;
31
+ return this;
32
+ }
33
+
34
+ /**
35
+ * Clear the type of message reference this represents
36
+ */
37
+ public clearType(): this {
38
+ this.data.type = undefined;
39
+ return this;
40
+ }
41
+
42
+ /**
43
+ * Sets the id of the message being referenced
44
+ *
45
+ * @param messageId - The id of the message being referenced
46
+ */
47
+ public setMessageId(messageId: Snowflake): this {
48
+ this.data.message_id = messageId;
49
+ return this;
50
+ }
51
+
52
+ /**
53
+ * Sets the id of the channel being referenced
54
+ *
55
+ * @param channelId - The id of the channel being referenced
56
+ */
57
+ public setChannelId(channelId: Snowflake): this {
58
+ this.data.channel_id = channelId;
59
+ return this;
60
+ }
61
+
62
+ /**
63
+ * Clear the id of the channel being referenced
64
+ */
65
+ public clearChannelId(): this {
66
+ this.data.channel_id = undefined;
67
+ return this;
68
+ }
69
+
70
+ /**
71
+ * Sets the id of the guild being referenced
72
+ *
73
+ * @param guildId - The id of the guild being referenced
74
+ */
75
+ public setGuildId(guildId: Snowflake): this {
76
+ this.data.guild_id = guildId;
77
+ return this;
78
+ }
79
+
80
+ /**
81
+ * Clear the id of the guild being referenced
82
+ */
83
+ public clearGuildId(): this {
84
+ this.data.guild_id = undefined;
85
+ return this;
86
+ }
87
+
88
+ /**
89
+ * Sets whether to fail the message creation if the referenced message does not exist
90
+ *
91
+ * @param failIfNotExists - Whether to fail the message creation if the referenced message does not exist
92
+ */
93
+ public setFailIfNotExists(failIfNotExists = true): this {
94
+ this.data.fail_if_not_exists = failIfNotExists;
95
+ return this;
96
+ }
97
+
98
+ /**
99
+ * Serializes this builder to API-compatible JSON data.
100
+ *
101
+ * Note that by disabling validation, there is no guarantee that the resulting object will be valid.
102
+ *
103
+ * @param validationOverride - Force validation to run/not run regardless of your global preference
104
+ */
105
+ public toJSON(validationOverride?: boolean): RESTAPIMessageReference {
106
+ const clone = structuredClone(this.data);
107
+ validate(messageReferencePredicate, clone, validationOverride);
108
+
109
+ return clone as RESTAPIMessageReference;
110
+ }
111
+ }
@@ -0,0 +1,53 @@
1
+ import { embedLength } from '@ovencord/util';
2
+ import { z } from 'zod';
3
+
4
+ const namePredicate = z.string().max(256);
5
+
6
+ const URLPredicate = z.string().url().refine((url) => url.startsWith('http:') || url.startsWith('https:'), { message: 'URL must use http or https protocol' });
7
+
8
+ const URLWithAttachmentProtocolPredicate = z.string().url().refine((url) => url.startsWith('http:') || url.startsWith('https:') || url.startsWith('attachment:'), { message: 'URL must use http, https, or attachment protocol' });
9
+
10
+ export const embedFieldPredicate = z.object({
11
+ name: namePredicate,
12
+ value: z.string().max(1_024),
13
+ inline: z.boolean().optional(),
14
+ });
15
+
16
+ export const embedAuthorPredicate = z.object({
17
+ name: namePredicate.min(1),
18
+ icon_url: URLWithAttachmentProtocolPredicate.optional(),
19
+ url: URLPredicate.optional(),
20
+ });
21
+
22
+ export const embedFooterPredicate = z.object({
23
+ text: z.string().min(1).max(2_048),
24
+ icon_url: URLWithAttachmentProtocolPredicate.optional(),
25
+ });
26
+
27
+ export const embedPredicate = z
28
+ .object({
29
+ title: namePredicate.min(1).optional(),
30
+ description: z.string().min(1).max(4_096).optional(),
31
+ url: URLPredicate.optional(),
32
+ timestamp: z.string().optional(),
33
+ color: z.number().int().min(0).max(0xffffff).optional(),
34
+ footer: embedFooterPredicate.optional(),
35
+ image: z.object({ url: URLWithAttachmentProtocolPredicate }).optional(),
36
+ thumbnail: z.object({ url: URLWithAttachmentProtocolPredicate }).optional(),
37
+ author: embedAuthorPredicate.optional(),
38
+ fields: z.array(embedFieldPredicate).max(25).optional(),
39
+ })
40
+ .refine(
41
+ (embed) =>
42
+ embed.title !== undefined ||
43
+ embed.description !== undefined ||
44
+ (embed.fields !== undefined && embed.fields.length > 0) ||
45
+ embed.footer !== undefined ||
46
+ embed.author !== undefined ||
47
+ embed.image !== undefined ||
48
+ embed.thumbnail !== undefined,
49
+ {
50
+ message: 'Embed must have at least a title, description, a field, a footer, an author, an image, OR a thumbnail.',
51
+ },
52
+ )
53
+ .refine((embed) => embedLength(embed as any) <= 6_000, { message: 'Embeds must not exceed 6000 characters in total.' });
@@ -0,0 +1,352 @@
1
+ import type { JSONEncodable } from '@ovencord/util';
2
+ import type { APIEmbed, APIEmbedAuthor, APIEmbedField, APIEmbedFooter } from 'discord-api-types/v10';
3
+ import type { RestOrArray } from '../../util/normalizeArray.js';
4
+ import { normalizeArray } from '../../util/normalizeArray.js';
5
+ import { resolveBuilder } from '../../util/resolveBuilder.js';
6
+ import { validate } from '../../util/validation.js';
7
+ import { embedPredicate } from './Assertions.js';
8
+ import { EmbedAuthorBuilder } from './EmbedAuthor.js';
9
+ import { EmbedFieldBuilder } from './EmbedField.js';
10
+ import { EmbedFooterBuilder } from './EmbedFooter.js';
11
+
12
+ /**
13
+ * Data stored in the process of constructing an embed.
14
+ */
15
+ export interface EmbedBuilderData extends Omit<APIEmbed, 'author' | 'fields' | 'footer'> {
16
+ author?: EmbedAuthorBuilder;
17
+ fields: EmbedFieldBuilder[];
18
+ footer?: EmbedFooterBuilder;
19
+ }
20
+
21
+ /**
22
+ * A builder that creates API-compatible JSON data for embeds.
23
+ */
24
+ export class EmbedBuilder implements JSONEncodable<APIEmbed> {
25
+ /**
26
+ * The API data associated with this embed.
27
+ */
28
+ private readonly data: EmbedBuilderData;
29
+
30
+ /**
31
+ * Gets the fields of this embed.
32
+ */
33
+ public get fields(): readonly EmbedFieldBuilder[] {
34
+ return this.data.fields;
35
+ }
36
+
37
+ /**
38
+ * Creates a new embed.
39
+ *
40
+ * @param data - The API data to create this embed with
41
+ */
42
+ public constructor(data: Partial<APIEmbed> = {}) {
43
+ const { author, fields = [], footer, ...rest } = data;
44
+
45
+ this.data = {
46
+ ...structuredClone(rest),
47
+ author: author && new EmbedAuthorBuilder(author),
48
+ fields: fields.map((field) => new EmbedFieldBuilder(field)),
49
+ footer: footer && new EmbedFooterBuilder(footer),
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Appends fields to the embed.
55
+ *
56
+ * @remarks
57
+ * This method accepts either an array of fields or a variable number of field parameters.
58
+ * The maximum amount of fields that can be added is 25.
59
+ * @example
60
+ * Using an array:
61
+ * ```ts
62
+ * const fields: APIEmbedField[] = ...;
63
+ * const embed = new EmbedBuilder()
64
+ * .addFields(fields);
65
+ * ```
66
+ * @example
67
+ * Using rest parameters (variadic):
68
+ * ```ts
69
+ * const embed = new EmbedBuilder()
70
+ * .addFields(
71
+ * { name: 'Field 1', value: 'Value 1' },
72
+ * { name: 'Field 2', value: 'Value 2' },
73
+ * );
74
+ * ```
75
+ * @param fields - The fields to add
76
+ */
77
+ public addFields(
78
+ ...fields: RestOrArray<APIEmbedField | EmbedFieldBuilder | ((builder: EmbedFieldBuilder) => EmbedFieldBuilder)>
79
+ ): this {
80
+ const normalizedFields = normalizeArray(fields);
81
+ const resolved = normalizedFields.map((field) => resolveBuilder(field, EmbedFieldBuilder));
82
+
83
+ this.data.fields.push(...resolved);
84
+ return this;
85
+ }
86
+
87
+ /**
88
+ * Removes, replaces, or inserts fields for this embed.
89
+ *
90
+ * @remarks
91
+ * This method behaves similarly
92
+ * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
93
+ * The maximum amount of fields that can be added is 25.
94
+ *
95
+ * It's useful for modifying and adjusting order of the already-existing fields of an embed.
96
+ * @example
97
+ * Remove the first field:
98
+ * ```ts
99
+ * embed.spliceFields(0, 1);
100
+ * ```
101
+ * @example
102
+ * Remove the first n fields:
103
+ * ```ts
104
+ * const n = 4;
105
+ * embed.spliceFields(0, n);
106
+ * ```
107
+ * @example
108
+ * Remove the last field:
109
+ * ```ts
110
+ * embed.spliceFields(-1, 1);
111
+ * ```
112
+ * @param index - The index to start at
113
+ * @param deleteCount - The number of fields to remove
114
+ * @param fields - The replacing field objects
115
+ */
116
+ public spliceFields(
117
+ index: number,
118
+ deleteCount: number,
119
+ ...fields: (APIEmbedField | EmbedFieldBuilder | ((builder: EmbedFieldBuilder) => EmbedFieldBuilder))[]
120
+ ): this {
121
+ const resolved = fields.map((field) => resolveBuilder(field, EmbedFieldBuilder));
122
+ this.data.fields.splice(index, deleteCount, ...resolved);
123
+
124
+ return this;
125
+ }
126
+
127
+ /**
128
+ * Sets the fields for this embed.
129
+ *
130
+ * @remarks
131
+ * This method is an alias for {@link EmbedBuilder.spliceFields}. More specifically,
132
+ * it splices the entire array of fields, replacing them with the provided fields.
133
+ *
134
+ * You can set a maximum of 25 fields.
135
+ * @param fields - The fields to set
136
+ */
137
+ public setFields(
138
+ ...fields: RestOrArray<APIEmbedField | EmbedFieldBuilder | ((builder: EmbedFieldBuilder) => EmbedFieldBuilder)>
139
+ ): this {
140
+ this.spliceFields(0, this.data.fields.length, ...normalizeArray(fields));
141
+ return this;
142
+ }
143
+
144
+ /**
145
+ * Sets the author of this embed.
146
+ *
147
+ * @param options - The options to use
148
+ */
149
+ public setAuthor(
150
+ options: APIEmbedAuthor | EmbedAuthorBuilder | ((builder: EmbedAuthorBuilder) => EmbedAuthorBuilder),
151
+ ): this {
152
+ this.data.author = resolveBuilder(options, EmbedAuthorBuilder);
153
+ return this;
154
+ }
155
+
156
+ /**
157
+ * Updates the author of this embed (and creates it if it doesn't exist).
158
+ *
159
+ * @param updater - The function to update the author with
160
+ */
161
+ public updateAuthor(updater: (builder: EmbedAuthorBuilder) => void) {
162
+ updater((this.data.author ??= new EmbedAuthorBuilder()));
163
+ return this;
164
+ }
165
+
166
+ /**
167
+ * Clears the author of this embed.
168
+ */
169
+ public clearAuthor(): this {
170
+ this.data.author = undefined;
171
+ return this;
172
+ }
173
+
174
+ /**
175
+ * Sets the color of this embed.
176
+ *
177
+ * @param color - The color to use
178
+ */
179
+ public setColor(color: number): this {
180
+ this.data.color = color;
181
+ return this;
182
+ }
183
+
184
+ /**
185
+ * Clears the color of this embed.
186
+ */
187
+ public clearColor(): this {
188
+ this.data.color = undefined;
189
+ return this;
190
+ }
191
+
192
+ /**
193
+ * Sets the description of this embed.
194
+ *
195
+ * @param description - The description to use
196
+ */
197
+ public setDescription(description: string): this {
198
+ this.data.description = description;
199
+ return this;
200
+ }
201
+
202
+ /**
203
+ * Clears the description of this embed.
204
+ */
205
+ public clearDescription(): this {
206
+ this.data.description = undefined;
207
+ return this;
208
+ }
209
+
210
+ /**
211
+ * Sets the footer of this embed.
212
+ *
213
+ * @param options - The footer to use
214
+ */
215
+ public setFooter(
216
+ options: APIEmbedFooter | EmbedFooterBuilder | ((builder: EmbedFooterBuilder) => EmbedFooterBuilder),
217
+ ): this {
218
+ this.data.footer = resolveBuilder(options, EmbedFooterBuilder);
219
+ return this;
220
+ }
221
+
222
+ /**
223
+ * Updates the footer of this embed (and creates it if it doesn't exist).
224
+ *
225
+ * @param updater - The function to update the footer with
226
+ */
227
+ public updateFooter(updater: (builder: EmbedFooterBuilder) => void) {
228
+ updater((this.data.footer ??= new EmbedFooterBuilder()));
229
+ return this;
230
+ }
231
+
232
+ /**
233
+ * Clears the footer of this embed.
234
+ */
235
+ public clearFooter(): this {
236
+ this.data.footer = undefined;
237
+ return this;
238
+ }
239
+
240
+ /**
241
+ * Sets the image of this embed.
242
+ *
243
+ * @param url - The image URL to use
244
+ */
245
+ public setImage(url: string): this {
246
+ this.data.image = { url };
247
+ return this;
248
+ }
249
+
250
+ /**
251
+ * Clears the image of this embed.
252
+ */
253
+ public clearImage(): this {
254
+ this.data.image = undefined;
255
+ return this;
256
+ }
257
+
258
+ /**
259
+ * Sets the thumbnail of this embed.
260
+ *
261
+ * @param url - The thumbnail URL to use
262
+ */
263
+ public setThumbnail(url: string): this {
264
+ this.data.thumbnail = { url };
265
+ return this;
266
+ }
267
+
268
+ /**
269
+ * Clears the thumbnail of this embed.
270
+ */
271
+ public clearThumbnail(): this {
272
+ this.data.thumbnail = undefined;
273
+ return this;
274
+ }
275
+
276
+ /**
277
+ * Sets the timestamp of this embed.
278
+ *
279
+ * @param timestamp - The timestamp or date to use
280
+ */
281
+ public setTimestamp(timestamp: Date | number | string = Date.now()): this {
282
+ this.data.timestamp = new Date(timestamp).toISOString();
283
+ return this;
284
+ }
285
+
286
+ /**
287
+ * Clears the timestamp of this embed.
288
+ */
289
+ public clearTimestamp(): this {
290
+ this.data.timestamp = undefined;
291
+ return this;
292
+ }
293
+
294
+ /**
295
+ * Sets the title for this embed.
296
+ *
297
+ * @param title - The title to use
298
+ */
299
+ public setTitle(title: string): this {
300
+ this.data.title = title;
301
+ return this;
302
+ }
303
+
304
+ /**
305
+ * Clears the title of this embed.
306
+ */
307
+ public clearTitle(): this {
308
+ this.data.title = undefined;
309
+ return this;
310
+ }
311
+
312
+ /**
313
+ * Sets the URL of this embed.
314
+ *
315
+ * @param url - The URL to use
316
+ */
317
+ public setURL(url: string): this {
318
+ this.data.url = url;
319
+ return this;
320
+ }
321
+
322
+ /**
323
+ * Clears the URL of this embed.
324
+ */
325
+ public clearURL(): this {
326
+ this.data.url = undefined;
327
+ return this;
328
+ }
329
+
330
+ /**
331
+ * Serializes this builder to API-compatible JSON data.
332
+ *
333
+ * Note that by disabling validation, there is no guarantee that the resulting object will be valid.
334
+ *
335
+ * @param validationOverride - Force validation to run/not run regardless of your global preference
336
+ */
337
+ public toJSON(validationOverride?: boolean): APIEmbed {
338
+ const { author, fields, footer, ...rest } = this.data;
339
+
340
+ const data = {
341
+ ...structuredClone(rest),
342
+ // Disable validation because the embedPredicate below will validate those as well
343
+ author: author?.toJSON(false),
344
+ fields: fields.map((field) => field.toJSON(false)),
345
+ footer: footer?.toJSON(false),
346
+ };
347
+
348
+ validate(embedPredicate, data, validationOverride);
349
+
350
+ return data;
351
+ }
352
+ }
@@ -0,0 +1,83 @@
1
+ import type { JSONEncodable } from '@ovencord/util';
2
+ import type { APIEmbedAuthor } from 'discord-api-types/v10';
3
+ import { validate } from '../../util/validation.js';
4
+ import { embedAuthorPredicate } from './Assertions.js';
5
+
6
+ /**
7
+ * A builder that creates API-compatible JSON data for the embed author.
8
+ */
9
+ export class EmbedAuthorBuilder implements JSONEncodable<APIEmbedAuthor> {
10
+ /**
11
+ * The API data associated with this embed author.
12
+ */
13
+ private readonly data: Partial<APIEmbedAuthor>;
14
+
15
+ /**
16
+ * Creates a new embed author.
17
+ *
18
+ * @param data - The API data to create this embed author with
19
+ */
20
+ public constructor(data: Partial<APIEmbedAuthor> = {}) {
21
+ this.data = structuredClone(data);
22
+ }
23
+
24
+ /**
25
+ * Sets the name for this embed author.
26
+ *
27
+ * @param name - The name to use
28
+ */
29
+ public setName(name: string): this {
30
+ this.data.name = name;
31
+ return this;
32
+ }
33
+
34
+ /**
35
+ * Sets the URL for this embed author.
36
+ *
37
+ * @param url - The url to use
38
+ */
39
+ public setURL(url: string): this {
40
+ this.data.url = url;
41
+ return this;
42
+ }
43
+
44
+ /**
45
+ * Clears the URL for this embed author.
46
+ */
47
+ public clearURL(): this {
48
+ this.data.url = undefined;
49
+ return this;
50
+ }
51
+
52
+ /**
53
+ * Sets the icon URL for this embed author.
54
+ *
55
+ * @param iconURL - The icon URL to use
56
+ */
57
+ public setIconURL(iconURL: string): this {
58
+ this.data.icon_url = iconURL;
59
+ return this;
60
+ }
61
+
62
+ /**
63
+ * Clears the icon URL for this embed author.
64
+ */
65
+ public clearIconURL(): this {
66
+ this.data.icon_url = undefined;
67
+ return this;
68
+ }
69
+
70
+ /**
71
+ * Serializes this builder to API-compatible JSON data.
72
+ *
73
+ * Note that by disabling validation, there is no guarantee that the resulting object will be valid.
74
+ *
75
+ * @param validationOverride - Force validation to run/not run regardless of your global preference
76
+ */
77
+ public toJSON(validationOverride?: boolean): APIEmbedAuthor {
78
+ const clone = structuredClone(this.data);
79
+ validate(embedAuthorPredicate, clone, validationOverride);
80
+
81
+ return clone as APIEmbedAuthor;
82
+ }
83
+ }
@@ -0,0 +1,67 @@
1
+ import type { JSONEncodable } from '@ovencord/util';
2
+ import type { APIEmbedField } from 'discord-api-types/v10';
3
+ import { validate } from '../../util/validation.js';
4
+ import { embedFieldPredicate } from './Assertions.js';
5
+
6
+ /**
7
+ * A builder that creates API-compatible JSON data for embed fields.
8
+ */
9
+ export class EmbedFieldBuilder implements JSONEncodable<APIEmbedField> {
10
+ /**
11
+ * The API data associated with this embed field.
12
+ */
13
+ private readonly data: Partial<APIEmbedField>;
14
+
15
+ /**
16
+ * Creates a new embed field.
17
+ *
18
+ * @param data - The API data to create this embed field with
19
+ */
20
+ public constructor(data: Partial<APIEmbedField> = {}) {
21
+ this.data = structuredClone(data);
22
+ }
23
+
24
+ /**
25
+ * Sets the name for this embed field.
26
+ *
27
+ * @param name - The name to use
28
+ */
29
+ public setName(name: string): this {
30
+ this.data.name = name;
31
+ return this;
32
+ }
33
+
34
+ /**
35
+ * Sets the value for this embed field.
36
+ *
37
+ * @param value - The value to use
38
+ */
39
+ public setValue(value: string): this {
40
+ this.data.value = value;
41
+ return this;
42
+ }
43
+
44
+ /**
45
+ * Sets whether this field should display inline.
46
+ *
47
+ * @param inline - Whether this field should display inline
48
+ */
49
+ public setInline(inline = true): this {
50
+ this.data.inline = inline;
51
+ return this;
52
+ }
53
+
54
+ /**
55
+ * Serializes this builder to API-compatible JSON data.
56
+ *
57
+ * Note that by disabling validation, there is no guarantee that the resulting object will be valid.
58
+ *
59
+ * @param validationOverride - Force validation to run/not run regardless of your global preference
60
+ */
61
+ public toJSON(validationOverride?: boolean): APIEmbedField {
62
+ const clone = structuredClone(this.data);
63
+ validate(embedFieldPredicate, clone, validationOverride);
64
+
65
+ return clone as APIEmbedField;
66
+ }
67
+ }