@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,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
|
+
}
|