@ovencord/builders 1.12.7 → 1.12.9

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 (49) hide show
  1. package/package.json +5 -3
  2. package/src/components/ActionRow.ts +14 -13
  3. package/src/components/Assertions.ts +38 -27
  4. package/src/components/Component.ts +3 -3
  5. package/src/components/Components.ts +35 -27
  6. package/src/components/button/Button.ts +1 -1
  7. package/src/components/button/ButtonBuilder.ts +7 -6
  8. package/src/components/button/CustomIdButton.ts +4 -2
  9. package/src/components/button/LinkButton.ts +3 -2
  10. package/src/components/button/mixins/EmojiOrLabelButtonMixin.ts +3 -5
  11. package/src/components/label/Label.ts +4 -1
  12. package/src/components/selectMenu/ChannelSelectMenu.ts +2 -2
  13. package/src/components/selectMenu/MentionableSelectMenu.ts +2 -2
  14. package/src/components/selectMenu/RoleSelectMenu.ts +2 -2
  15. package/src/components/selectMenu/StringSelectMenu.ts +1 -1
  16. package/src/components/selectMenu/UserSelectMenu.ts +2 -2
  17. package/src/components/textInput/TextInput.ts +1 -1
  18. package/src/components/v2/Assertions.ts +11 -6
  19. package/src/components/v2/Container.ts +12 -7
  20. package/src/components/v2/File.ts +1 -1
  21. package/src/components/v2/MediaGallery.ts +1 -1
  22. package/src/components/v2/Section.ts +7 -20
  23. package/src/components/v2/Separator.ts +1 -1
  24. package/src/components/v2/TextDisplay.ts +2 -2
  25. package/src/components/v2/Thumbnail.ts +8 -8
  26. package/src/index.ts +29 -42
  27. package/src/interactions/commands/Command.ts +11 -7
  28. package/src/interactions/commands/SharedName.ts +2 -3
  29. package/src/interactions/commands/SharedNameAndDescription.ts +2 -1
  30. package/src/interactions/commands/chatInput/Assertions.ts +17 -5
  31. package/src/interactions/commands/chatInput/ChatInputCommandSubcommands.ts +5 -4
  32. package/src/interactions/commands/chatInput/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.ts +3 -5
  33. package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionChannelTypesMixin.ts +4 -6
  34. package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionWithAutocompleteMixin.ts +1 -1
  35. package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionWithChoicesMixin.ts +1 -1
  36. package/src/interactions/commands/chatInput/mixins/SharedChatInputCommandOptions.ts +34 -11
  37. package/src/interactions/commands/chatInput/mixins/SharedSubcommands.ts +2 -2
  38. package/src/interactions/commands/chatInput/options/ApplicationCommandOptionBase.ts +1 -1
  39. package/src/interactions/commands/chatInput/options/string.ts +3 -3
  40. package/src/interactions/modals/Modal.ts +3 -9
  41. package/src/messages/Assertions.ts +6 -3
  42. package/src/messages/Attachment.ts +1 -1
  43. package/src/messages/Message.ts +30 -21
  44. package/src/messages/embed/Assertions.ts +16 -3
  45. package/src/messages/embed/Embed.ts +4 -2
  46. package/src/messages/poll/Poll.ts +1 -1
  47. package/src/util/componentUtil.ts +4 -4
  48. package/src/util/resolveBuilder.ts +5 -2
  49. package/src/util/validation.ts +4 -2
package/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@ovencord/builders",
4
- "version": "1.12.7",
4
+ "version": "1.12.9",
5
5
  "description": "A set of builders that you can use when creating your bot",
6
6
  "scripts": {
7
7
  "test": "bun test",
8
8
  "typecheck": "tsc --noEmit",
9
- "lint": "eslint src"
9
+ "lint": "biome check .",
10
+ "format": "biome format --write .",
11
+ "check": "biome check --write ."
10
12
  },
11
13
  "exports": "./src/index.ts",
12
14
  "main": "./src/index.ts",
@@ -43,7 +45,7 @@
43
45
  "ts-mixer": "^6.0.4",
44
46
 
45
47
  "zod": "^4.3.6",
46
- "@ovencord/util": "^1.1.5"
48
+ "@ovencord/util": "^1.1.8"
47
49
  },
48
50
  "devDependencies": {},
49
51
  "engines": {
@@ -1,24 +1,21 @@
1
1
  import type {
2
- APITextInputComponent,
3
2
  APIActionRowComponent,
4
- APIComponentInActionRow,
3
+ APIButtonComponentWithCustomId,
4
+ APIButtonComponentWithSKUId,
5
+ APIButtonComponentWithURL,
5
6
  APIChannelSelectComponent,
7
+ APIComponentInActionRow,
6
8
  APIMentionableSelectComponent,
7
9
  APIRoleSelectComponent,
8
10
  APIStringSelectComponent,
11
+ APITextInputComponent,
9
12
  APIUserSelectComponent,
10
- APIButtonComponentWithCustomId,
11
- APIButtonComponentWithSKUId,
12
- APIButtonComponentWithURL,
13
13
  } from 'discord-api-types/v10';
14
14
  import { ComponentType } from 'discord-api-types/v10';
15
15
  import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';
16
16
  import { resolveBuilder } from '../util/resolveBuilder.js';
17
17
  import { validate } from '../util/validation.js';
18
18
  import { actionRowPredicate } from './Assertions.js';
19
- import { ComponentBuilder } from './Component.js';
20
- import type { AnyActionRowComponentBuilder } from './Components.js';
21
- import { createComponentBuilder } from './Components.js';
22
19
  import {
23
20
  DangerButtonBuilder,
24
21
  PrimaryButtonBuilder,
@@ -27,6 +24,9 @@ import {
27
24
  } from './button/CustomIdButton.js';
28
25
  import { LinkButtonBuilder } from './button/LinkButton.js';
29
26
  import { PremiumButtonBuilder } from './button/PremiumButton.js';
27
+ import { ComponentBuilder } from './Component.js';
28
+ import type { AnyActionRowComponentBuilder, MessageComponentBuilder } from './Components.js';
29
+ import { createComponentBuilder } from './Components.js';
30
30
  import { ChannelSelectMenuBuilder } from './selectMenu/ChannelSelectMenu.js';
31
31
  import { MentionableSelectMenuBuilder } from './selectMenu/MentionableSelectMenu.js';
32
32
  import { RoleSelectMenuBuilder } from './selectMenu/RoleSelectMenu.js';
@@ -34,16 +34,17 @@ import { StringSelectMenuBuilder } from './selectMenu/StringSelectMenu.js';
34
34
  import { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js';
35
35
  import { TextInputBuilder } from './textInput/TextInput.js';
36
36
 
37
- export interface ActionRowBuilderData<T extends AnyActionRowComponentBuilder = AnyActionRowComponentBuilder> extends Partial<
38
- Omit<APIActionRowComponent<APIComponentInActionRow>, 'components'>
39
- > {
37
+ export interface ActionRowBuilderData<T extends AnyActionRowComponentBuilder = AnyActionRowComponentBuilder>
38
+ extends Partial<Omit<APIActionRowComponent<APIComponentInActionRow>, 'components'>> {
40
39
  components: T[];
41
40
  }
42
41
 
43
42
  /**
44
43
  * A builder that creates API-compatible JSON data for action rows.
45
44
  */
46
- export class ActionRowBuilder<T extends AnyActionRowComponentBuilder = AnyActionRowComponentBuilder> extends ComponentBuilder<APIActionRowComponent<APIComponentInActionRow>> {
45
+ export class ActionRowBuilder<
46
+ T extends AnyActionRowComponentBuilder = AnyActionRowComponentBuilder,
47
+ > extends ComponentBuilder<APIActionRowComponent<APIComponentInActionRow>> {
47
48
  /**
48
49
  * @internal
49
50
  */
@@ -348,7 +349,7 @@ export class ActionRowBuilder<T extends AnyActionRowComponentBuilder = AnyAction
348
349
 
349
350
  const data = {
350
351
  ...structuredClone(rest),
351
- components: components.map((component) => (component as any).toJSON(validationOverride)),
352
+ components: components.map((component) => (component as MessageComponentBuilder).toJSON(validationOverride)),
352
353
  };
353
354
 
354
355
  validate(actionRowPredicate, data, validationOverride);
@@ -1,6 +1,6 @@
1
1
  import { ButtonStyle, ChannelType, ComponentType, SelectMenuDefaultValueType } from 'discord-api-types/v10';
2
2
  import { z } from 'zod';
3
- import { idPredicate, customIdPredicate, snowflakePredicate } from '../Assertions.js';
3
+ import { customIdPredicate, idPredicate, snowflakePredicate } from '../Assertions.js';
4
4
 
5
5
  export const emojiPredicate = z
6
6
  .strictObject({
@@ -19,37 +19,52 @@ const buttonPredicateBase = z.strictObject({
19
19
 
20
20
  const buttonLabelPredicate = z.string().min(1).max(80);
21
21
 
22
- const buttonCustomIdPredicateBase = buttonPredicateBase
23
- .extend({
24
- custom_id: customIdPredicate,
25
- emoji: emojiPredicate.optional(),
26
- label: buttonLabelPredicate.optional(),
27
- });
28
-
29
-
22
+ const buttonCustomIdPredicateBase = buttonPredicateBase.extend({
23
+ custom_id: customIdPredicate,
24
+ emoji: emojiPredicate.optional(),
25
+ label: buttonLabelPredicate.optional(),
26
+ });
30
27
 
31
28
  const buttonPrimaryPredicate = buttonCustomIdPredicateBase.extend({ style: z.literal(ButtonStyle.Primary) });
32
29
  const buttonSecondaryPredicate = buttonCustomIdPredicateBase.extend({ style: z.literal(ButtonStyle.Secondary) });
33
30
  const buttonSuccessPredicate = buttonCustomIdPredicateBase.extend({ style: z.literal(ButtonStyle.Success) });
34
31
  const buttonDangerPredicate = buttonCustomIdPredicateBase.extend({ style: z.literal(ButtonStyle.Danger) });
35
32
 
36
- const buttonPrimaryRefinedPredicate = buttonPrimaryPredicate.refine((data) => data.emoji !== undefined || data.label !== undefined, {
37
- message: 'Buttons with a custom id must have either an emoji or a label.',
38
- });
39
- const buttonSecondaryRefinedPredicate = buttonSecondaryPredicate.refine((data) => data.emoji !== undefined || data.label !== undefined, {
40
- message: 'Buttons with a custom id must have either an emoji or a label.',
41
- });
42
- const buttonSuccessRefinedPredicate = buttonSuccessPredicate.refine((data) => data.emoji !== undefined || data.label !== undefined, {
43
- message: 'Buttons with a custom id must have either an emoji or a label.',
44
- });
45
- const buttonDangerRefinedPredicate = buttonDangerPredicate.refine((data) => data.emoji !== undefined || data.label !== undefined, {
46
- message: 'Buttons with a custom id must have either an emoji or a label.',
47
- });
33
+ const buttonPrimaryRefinedPredicate = buttonPrimaryPredicate.refine(
34
+ (data) => data.emoji !== undefined || data.label !== undefined,
35
+ {
36
+ message: 'Buttons with a custom id must have either an emoji or a label.',
37
+ },
38
+ );
39
+ const buttonSecondaryRefinedPredicate = buttonSecondaryPredicate.refine(
40
+ (data) => data.emoji !== undefined || data.label !== undefined,
41
+ {
42
+ message: 'Buttons with a custom id must have either an emoji or a label.',
43
+ },
44
+ );
45
+ const buttonSuccessRefinedPredicate = buttonSuccessPredicate.refine(
46
+ (data) => data.emoji !== undefined || data.label !== undefined,
47
+ {
48
+ message: 'Buttons with a custom id must have either an emoji or a label.',
49
+ },
50
+ );
51
+ const buttonDangerRefinedPredicate = buttonDangerPredicate.refine(
52
+ (data) => data.emoji !== undefined || data.label !== undefined,
53
+ {
54
+ message: 'Buttons with a custom id must have either an emoji or a label.',
55
+ },
56
+ );
48
57
 
49
58
  const buttonLinkPredicate = buttonPredicateBase
50
59
  .extend({
51
60
  style: z.literal(ButtonStyle.Link),
52
- url: z.string().url().max(512).refine((url) => url.startsWith('http:') || url.startsWith('https:') || url.startsWith('discord:'), { message: 'URL must use http, https, or discord protocol' }),
61
+ url: z
62
+ .string()
63
+ .url()
64
+ .max(512)
65
+ .refine((url) => url.startsWith('http:') || url.startsWith('https:') || url.startsWith('discord:'), {
66
+ message: 'URL must use http, https, or discord protocol',
67
+ }),
53
68
  emoji: emojiPredicate.optional(),
54
69
  label: buttonLabelPredicate.optional(),
55
70
  })
@@ -140,11 +155,7 @@ export const selectMenuStringPredicate = selectMenuBasePredicate
140
155
  addIssue('min_values', value.min_values);
141
156
  }
142
157
 
143
- if (
144
- value.min_values !== undefined &&
145
- value.max_values !== undefined &&
146
- value.min_values > value.max_values
147
- ) {
158
+ if (value.min_values !== undefined && value.max_values !== undefined && value.min_values > value.max_values) {
148
159
  ctx.addIssue({
149
160
  code: z.ZodIssueCode.too_big,
150
161
  message: `The maximum amount of options must be greater than or equal to the minimum amount of options`,
@@ -10,9 +10,9 @@ export interface ComponentBuilderBaseData {
10
10
  *
11
11
  * @typeParam Component - The type of API data that is stored within the builder
12
12
  */
13
- export abstract class ComponentBuilder<
14
- Component extends APIBaseComponent<ComponentType>,
15
- > implements JSONEncodable<Component> {
13
+ export abstract class ComponentBuilder<Component extends APIBaseComponent<ComponentType>>
14
+ implements JSONEncodable<Component>
15
+ {
16
16
  /**
17
17
  * @internal
18
18
  */
@@ -1,21 +1,30 @@
1
1
  import type {
2
+ APIActionRowComponent,
2
3
  APIBaseComponent,
3
4
  APIButtonComponent,
5
+ APIChannelSelectComponent,
6
+ APIComponentInActionRow,
7
+ APIMentionableSelectComponent,
4
8
  APIMessageComponent,
5
9
  APIModalComponent,
10
+ APIRoleSelectComponent,
6
11
  APISectionAccessoryComponent,
12
+ APIStringSelectComponent,
13
+ APITextInputComponent,
14
+ APIUserSelectComponent,
7
15
  } from 'discord-api-types/v10';
8
16
  import { ButtonStyle, ComponentType } from 'discord-api-types/v10';
9
17
  import { ActionRowBuilder } from './ActionRow.js';
10
- import { ComponentBuilder } from './Component.js';
18
+ import { ButtonBuilder } from './button/ButtonBuilder.js';
11
19
  import {
12
20
  DangerButtonBuilder,
13
21
  PrimaryButtonBuilder,
14
22
  SecondaryButtonBuilder,
15
23
  SuccessButtonBuilder,
16
24
  } from './button/CustomIdButton.js';
17
- import { ButtonBuilder } from './button/ButtonBuilder.js';
25
+ import { ComponentBuilder } from './Component.js';
18
26
  export { ButtonBuilder };
27
+
19
28
  import { LinkButtonBuilder } from './button/LinkButton.js';
20
29
  import { PremiumButtonBuilder } from './button/PremiumButton.js';
21
30
  import { FileUploadBuilder } from './fileUpload/FileUpload.js';
@@ -178,7 +187,6 @@ export interface MappedComponentTypes {
178
187
  * @param data - The API data to transform to a component class
179
188
  */
180
189
  export function createComponentBuilder<ComponentType extends keyof MappedComponentTypes>(
181
-
182
190
  data: (APIModalComponent | APIMessageComponent) & { type: ComponentType },
183
191
  ): MappedComponentTypes[ComponentType];
184
192
 
@@ -196,45 +204,45 @@ export function createComponentBuilder(
196
204
  data: APIMessageComponent | APIModalComponent | MessageComponentBuilder,
197
205
  ): ComponentBuilder<APIBaseComponent<ComponentType>> {
198
206
  if (data instanceof ComponentBuilder || (typeof data === 'object' && data !== null && 'toJSON' in data)) {
199
- return data as any;
207
+ return data as unknown as ComponentBuilder<APIBaseComponent<ComponentType>>;
200
208
  }
201
209
 
202
210
  const rawData = data as APIMessageComponent | APIModalComponent;
203
211
  switch (rawData.type) {
204
212
  case ComponentType.ActionRow:
205
- return new ActionRowBuilder(rawData as any);
213
+ return new ActionRowBuilder(rawData as APIActionRowComponent<APIComponentInActionRow>);
206
214
  case ComponentType.Button:
207
- return createButtonBuilder(rawData as any) as any;
215
+ return createButtonBuilder(rawData as APIButtonComponent) as unknown as MessageComponentBuilder;
208
216
  case ComponentType.StringSelect:
209
- return new StringSelectMenuBuilder(rawData as any);
217
+ return new StringSelectMenuBuilder(rawData as APIStringSelectComponent);
210
218
  case ComponentType.TextInput:
211
- return new TextInputBuilder(rawData as any);
219
+ return new TextInputBuilder(rawData as APITextInputComponent);
212
220
  case ComponentType.UserSelect:
213
- return new UserSelectMenuBuilder(rawData as any);
221
+ return new UserSelectMenuBuilder(rawData as APIUserSelectComponent);
214
222
  case ComponentType.RoleSelect:
215
- return new RoleSelectMenuBuilder(rawData as any);
223
+ return new RoleSelectMenuBuilder(rawData as APIRoleSelectComponent);
216
224
  case ComponentType.MentionableSelect:
217
- return new MentionableSelectMenuBuilder(rawData as any);
225
+ return new MentionableSelectMenuBuilder(rawData as APIMentionableSelectComponent);
218
226
  case ComponentType.ChannelSelect:
219
- return new ChannelSelectMenuBuilder(rawData as any);
227
+ return new ChannelSelectMenuBuilder(rawData as APIChannelSelectComponent);
220
228
  case ComponentType.Thumbnail:
221
- return new ThumbnailBuilder(rawData as any);
229
+ return new ThumbnailBuilder(rawData as unknown);
222
230
  case ComponentType.File:
223
- return new FileBuilder(rawData as any);
231
+ return new FileBuilder(rawData as unknown);
224
232
  case ComponentType.Separator:
225
- return new SeparatorBuilder(rawData as any);
233
+ return new SeparatorBuilder(rawData as unknown);
226
234
  case ComponentType.TextDisplay:
227
- return new TextDisplayBuilder(rawData as any);
235
+ return new TextDisplayBuilder(rawData as unknown);
228
236
  case ComponentType.MediaGallery:
229
- return new MediaGalleryBuilder(rawData as any);
237
+ return new MediaGalleryBuilder(rawData as unknown);
230
238
  case ComponentType.Section:
231
- return new SectionBuilder(rawData as any);
239
+ return new SectionBuilder(rawData as unknown);
232
240
  case ComponentType.Container:
233
- return new ContainerBuilder(rawData as any);
241
+ return new ContainerBuilder(rawData as unknown);
234
242
  case ComponentType.Label:
235
- return new LabelBuilder(rawData as any);
243
+ return new LabelBuilder(rawData as unknown);
236
244
  case ComponentType.FileUpload:
237
- return new FileUploadBuilder(rawData as any);
245
+ return new FileUploadBuilder(rawData as unknown);
238
246
  default:
239
247
  // This case can still occur if we get a newer unsupported component type
240
248
  throw new Error(`Cannot properly serialize component type: ${rawData.type}`);
@@ -244,17 +252,17 @@ export function createComponentBuilder(
244
252
  function createButtonBuilder(data: APIButtonComponent): ButtonBuilder {
245
253
  switch (data.style) {
246
254
  case ButtonStyle.Primary:
247
- return new PrimaryButtonBuilder(data) as any;
255
+ return new PrimaryButtonBuilder(data) as unknown as ButtonBuilder;
248
256
  case ButtonStyle.Secondary:
249
- return new SecondaryButtonBuilder(data) as any;
257
+ return new SecondaryButtonBuilder(data) as unknown as ButtonBuilder;
250
258
  case ButtonStyle.Success:
251
- return new SuccessButtonBuilder(data) as any;
259
+ return new SuccessButtonBuilder(data) as unknown as ButtonBuilder;
252
260
  case ButtonStyle.Danger:
253
- return new DangerButtonBuilder(data) as any;
261
+ return new DangerButtonBuilder(data) as unknown as ButtonBuilder;
254
262
  case ButtonStyle.Link:
255
- return new LinkButtonBuilder(data) as any;
263
+ return new LinkButtonBuilder(data) as unknown as ButtonBuilder;
256
264
  case ButtonStyle.Premium:
257
- return new PremiumButtonBuilder(data) as any;
265
+ return new PremiumButtonBuilder(data) as unknown as ButtonBuilder;
258
266
  default:
259
267
  // @ts-expect-error This case can still occur if we get a newer unsupported button style
260
268
  throw new Error(`Cannot properly serialize button with style: ${data.style}`);
@@ -10,7 +10,7 @@ export abstract class BaseButtonBuilder<ButtonData extends APIButtonComponent> e
10
10
  /**
11
11
  * @internal
12
12
  */
13
- declare protected readonly data: Partial<ButtonData>;
13
+ protected declare readonly data: Partial<ButtonData>;
14
14
 
15
15
  /**
16
16
  * Sets whether this button is disabled.
@@ -1,4 +1,4 @@
1
- import { ButtonStyle, ComponentType, type APIButtonComponent } from 'discord-api-types/v10';
1
+ import { type APIButtonComponent, type ButtonStyle, ComponentType } from 'discord-api-types/v10';
2
2
  import { Mixin } from 'ts-mixer';
3
3
  import { BaseButtonBuilder } from './Button.js';
4
4
  import { EmojiOrLabelButtonMixin } from './mixins/EmojiOrLabelButtonMixin.js';
@@ -9,9 +9,10 @@ import { EmojiOrLabelButtonMixin } from './mixins/EmojiOrLabelButtonMixin.js';
9
9
  * @mixes {@link BaseButtonBuilder}\<{@link discord-api-types/v10#(APIButtonComponent:interface)}\>
10
10
  * @mixes {@link EmojiOrLabelButtonMixin}
11
11
  */
12
- // @ts-ignore
12
+ // @ts-expect-error - Structural mismatch from ts-mixer
13
13
  export interface ButtonBuilder extends BaseButtonBuilder<APIButtonComponent>, EmojiOrLabelButtonMixin {}
14
14
 
15
+ // biome-ignore lint/suspicious/noUnsafeDeclarationMerging: Standard event typing pattern
15
16
  export class ButtonBuilder extends Mixin(BaseButtonBuilder<APIButtonComponent>, EmojiOrLabelButtonMixin) {
16
17
  /**
17
18
  * @internal
@@ -34,7 +35,7 @@ export class ButtonBuilder extends Mixin(BaseButtonBuilder<APIButtonComponent>,
34
35
  * @param customId - The custom id to use
35
36
  */
36
37
  public setCustomId(customId: string) {
37
- (this.data as any).custom_id = customId;
38
+ (this.data as Record<string, unknown>).custom_id = customId;
38
39
  return this;
39
40
  }
40
41
 
@@ -44,7 +45,7 @@ export class ButtonBuilder extends Mixin(BaseButtonBuilder<APIButtonComponent>,
44
45
  * @param style - The style to use
45
46
  */
46
47
  public setStyle(style: ButtonStyle) {
47
- (this.data as any).style = style;
48
+ (this.data as Record<string, unknown>).style = style;
48
49
  return this;
49
50
  }
50
51
 
@@ -54,7 +55,7 @@ export class ButtonBuilder extends Mixin(BaseButtonBuilder<APIButtonComponent>,
54
55
  * @param url - The URL to use
55
56
  */
56
57
  public setURL(url: string) {
57
- (this.data as any).url = url;
58
+ (this.data as Record<string, unknown>).url = url;
58
59
  return this;
59
60
  }
60
61
 
@@ -64,7 +65,7 @@ export class ButtonBuilder extends Mixin(BaseButtonBuilder<APIButtonComponent>,
64
65
  * @param skuId - The SKU id to use
65
66
  */
66
67
  public setSKUId(skuId: string) {
67
- (this.data as any).sku_id = skuId;
68
+ (this.data as Record<string, unknown>).sku_id = skuId;
68
69
  return this;
69
70
  }
70
71
  }
@@ -1,4 +1,4 @@
1
- import { ButtonStyle, ComponentType, type APIButtonComponentWithCustomId } from 'discord-api-types/v10';
1
+ import { type APIButtonComponentWithCustomId, ButtonStyle, ComponentType } from 'discord-api-types/v10';
2
2
  import { Mixin } from 'ts-mixer';
3
3
  import { BaseButtonBuilder } from './Button.js';
4
4
  import { EmojiOrLabelButtonMixin } from './mixins/EmojiOrLabelButtonMixin.js';
@@ -11,7 +11,9 @@ export type CustomIdButtonStyle = APIButtonComponentWithCustomId['style'];
11
11
  * @mixes {@link BaseButtonBuilder}\<{@link discord-api-types/v10#(APIButtonComponentWithCustomId:interface)}\>
12
12
  * @mixes {@link EmojiOrLabelButtonMixin}
13
13
  */
14
- export interface CustomIdButtonBuilder extends BaseButtonBuilder<APIButtonComponentWithCustomId>, EmojiOrLabelButtonMixin {}
14
+ export interface CustomIdButtonBuilder
15
+ extends BaseButtonBuilder<APIButtonComponentWithCustomId>,
16
+ EmojiOrLabelButtonMixin {}
15
17
 
16
18
  export abstract class CustomIdButtonBuilder extends Mixin(
17
19
  BaseButtonBuilder<APIButtonComponentWithCustomId>,
@@ -1,8 +1,8 @@
1
1
  import {
2
- ButtonStyle,
3
- ComponentType,
4
2
  type APIButtonComponent,
5
3
  type APIButtonComponentWithURL,
4
+ ButtonStyle,
5
+ ComponentType,
6
6
  } from 'discord-api-types/v10';
7
7
  import { Mixin } from 'ts-mixer';
8
8
  import { BaseButtonBuilder } from './Button.js';
@@ -16,6 +16,7 @@ import { EmojiOrLabelButtonMixin } from './mixins/EmojiOrLabelButtonMixin.js';
16
16
  */
17
17
  export interface LinkButtonBuilder extends BaseButtonBuilder<APIButtonComponentWithURL>, EmojiOrLabelButtonMixin {}
18
18
 
19
+ // biome-ignore lint/suspicious/noUnsafeDeclarationMerging: Standard event typing pattern
19
20
  export class LinkButtonBuilder extends Mixin(BaseButtonBuilder<APIButtonComponentWithURL>, EmojiOrLabelButtonMixin) {
20
21
  protected override readonly data: Partial<APIButtonComponentWithURL>;
21
22
 
@@ -1,10 +1,8 @@
1
1
  import type { APIButtonComponent, APIButtonComponentWithSKUId, APIMessageComponentEmoji } from 'discord-api-types/v10';
2
2
  import { parseEmoji } from '../../../util/componentUtil.js';
3
3
 
4
- export interface EmojiOrLabelButtonData extends Pick<
5
- Exclude<APIButtonComponent, APIButtonComponentWithSKUId>,
6
- 'emoji' | 'label'
7
- > {}
4
+ export interface EmojiOrLabelButtonData
5
+ extends Pick<Exclude<APIButtonComponent, APIButtonComponentWithSKUId>, 'emoji' | 'label'> {}
8
6
 
9
7
  /**
10
8
  * A mixin that adds emoji and label symbols to a button builder.
@@ -13,7 +11,7 @@ export class EmojiOrLabelButtonMixin {
13
11
  /**
14
12
  * @internal
15
13
  */
16
- declare protected readonly data: EmojiOrLabelButtonData;
14
+ protected declare readonly data: EmojiOrLabelButtonData;
17
15
 
18
16
  /**
19
17
  * Sets the emoji to display on this button.
@@ -3,6 +3,7 @@ import type {
3
3
  APIFileUploadComponent,
4
4
  APILabelComponent,
5
5
  APIMentionableSelectComponent,
6
+ APIMessageComponent,
6
7
  APIRoleSelectComponent,
7
8
  APIStringSelectComponent,
8
9
  APITextInputComponent,
@@ -70,7 +71,9 @@ export class LabelBuilder extends ComponentBuilder<APILabelComponent> {
70
71
 
71
72
  this.data = {
72
73
  ...structuredClone(rest),
73
- component: component ? (createComponentBuilder(component as any) as any) : undefined,
74
+ component: component
75
+ ? (createComponentBuilder(component as APIMessageComponent) as LabelBuilderData['component'])
76
+ : undefined,
74
77
  type: ComponentType.Label,
75
78
  };
76
79
  }
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  type APIChannelSelectComponent,
3
3
  type ChannelType,
4
- type Snowflake,
5
4
  ComponentType,
6
5
  SelectMenuDefaultValueType,
6
+ type Snowflake,
7
7
  } from 'discord-api-types/v10';
8
- import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
8
+ import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
9
9
  import { validate } from '../../util/validation.js';
10
10
  import { selectMenuChannelPredicate } from '../Assertions.js';
11
11
  import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  type APIMentionableSelectComponent,
3
3
  type APISelectMenuDefaultValue,
4
- type Snowflake,
5
4
  ComponentType,
6
5
  SelectMenuDefaultValueType,
6
+ type Snowflake,
7
7
  } from 'discord-api-types/v10';
8
- import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
8
+ import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
9
9
  import { validate } from '../../util/validation.js';
10
10
  import { selectMenuMentionablePredicate } from '../Assertions.js';
11
11
  import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  type APIRoleSelectComponent,
3
- type Snowflake,
4
3
  ComponentType,
5
4
  SelectMenuDefaultValueType,
5
+ type Snowflake,
6
6
  } from 'discord-api-types/v10';
7
- import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
7
+ import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
8
8
  import { validate } from '../../util/validation.js';
9
9
  import { selectMenuRolePredicate } from '../Assertions.js';
10
10
  import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
@@ -1,5 +1,5 @@
1
+ import type { APISelectMenuOption, APIStringSelectComponent } from 'discord-api-types/v10';
1
2
  import { ComponentType } from 'discord-api-types/v10';
2
- import type { APIStringSelectComponent, APISelectMenuOption } from 'discord-api-types/v10';
3
3
  import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
4
4
  import { resolveBuilder } from '../../util/resolveBuilder.js';
5
5
  import { validate } from '../../util/validation.js';
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  type APIUserSelectComponent,
3
- type Snowflake,
4
3
  ComponentType,
5
4
  SelectMenuDefaultValueType,
5
+ type Snowflake,
6
6
  } from 'discord-api-types/v10';
7
- import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
7
+ import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
8
8
  import { validate } from '../../util/validation.js';
9
9
  import { selectMenuUserPredicate } from '../Assertions.js';
10
10
  import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
@@ -1,4 +1,4 @@
1
- import { ComponentType, type TextInputStyle, type APITextInputComponent } from 'discord-api-types/v10';
1
+ import { type APITextInputComponent, ComponentType, type TextInputStyle } from 'discord-api-types/v10';
2
2
  import { validate } from '../../util/validation.js';
3
3
  import { ComponentBuilder } from '../Component.js';
4
4
  import { textInputPredicate } from './Assertions.js';
@@ -4,7 +4,12 @@ import { idPredicate } from '../../Assertions.js';
4
4
  import { actionRowPredicate, buttonPredicate } from '../Assertions.js';
5
5
 
6
6
  const unfurledMediaItemPredicate = z.object({
7
- url: z.string().url().refine((url) => url.startsWith('http:') || url.startsWith('https:') || url.startsWith('attachment:'), { message: 'URL must use http, https, or attachment protocol' }),
7
+ url: z
8
+ .string()
9
+ .url()
10
+ .refine((url) => url.startsWith('http:') || url.startsWith('https:') || url.startsWith('attachment:'), {
11
+ message: 'URL must use http, https, or attachment protocol',
12
+ }),
8
13
  });
9
14
 
10
15
  export const thumbnailPredicate = z.object({
@@ -16,7 +21,10 @@ export const thumbnailPredicate = z.object({
16
21
  });
17
22
 
18
23
  const unfurledMediaItemAttachmentOnlyPredicate = z.object({
19
- url: z.string().url().refine((url) => url.startsWith('attachment:'), { message: 'URL must use attachment protocol' }),
24
+ url: z
25
+ .string()
26
+ .url()
27
+ .refine((url) => url.startsWith('attachment:'), { message: 'URL must use attachment protocol' }),
20
28
  });
21
29
 
22
30
  export const filePredicate = z.object({
@@ -56,10 +64,7 @@ export const sectionPredicate = z.object({
56
64
  type: z.literal(ComponentType.Section),
57
65
  id: idPredicate,
58
66
  components: z.array(textDisplayPredicate).min(1).max(3),
59
- accessory: z.union([
60
- buttonPredicate,
61
- thumbnailPredicate,
62
- ]),
67
+ accessory: z.union([buttonPredicate, thumbnailPredicate]),
63
68
  });
64
69
 
65
70
  export const containerPredicate = z.object({
@@ -1,14 +1,14 @@
1
1
  import {
2
- type APIComponentInMessageActionRow,
3
- type APISeparatorComponent,
4
2
  type APIActionRowComponent,
5
- type APIFileComponent,
6
- type APITextDisplayComponent,
7
- type APIContainerComponent,
3
+ type APIComponentInActionRow,
8
4
  type APIComponentInContainer,
5
+ type APIComponentInMessageActionRow,
6
+ type APIContainerComponent,
7
+ type APIFileComponent,
9
8
  type APIMediaGalleryComponent,
10
9
  type APISectionComponent,
11
- type APIComponentInActionRow,
10
+ type APISeparatorComponent,
11
+ type APITextDisplayComponent,
12
12
  ComponentType,
13
13
  } from 'discord-api-types/v10';
14
14
  import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
@@ -110,7 +110,12 @@ export class ContainerBuilder extends ComponentBuilder<APIContainerComponent> {
110
110
  >
111
111
  ): this {
112
112
  const normalized = normalizeArray(input);
113
- const resolved = normalized.map((component) => resolveBuilder<ActionRowBuilder, Partial<APIActionRowComponent<APIComponentInActionRow>>>(component, ActionRowBuilder));
113
+ const resolved = normalized.map((component) =>
114
+ resolveBuilder<ActionRowBuilder, Partial<APIActionRowComponent<APIComponentInActionRow>>>(
115
+ component,
116
+ ActionRowBuilder,
117
+ ),
118
+ );
114
119
 
115
120
  this.data.components.push(...resolved);
116
121
  return this;
@@ -1,4 +1,4 @@
1
- import { ComponentType, type APIFileComponent } from 'discord-api-types/v10';
1
+ import { type APIFileComponent, ComponentType } from 'discord-api-types/v10';
2
2
  import { validate } from '../../util/validation.js';
3
3
  import { ComponentBuilder } from '../Component.js';
4
4
  import { filePredicate } from './Assertions.js';
@@ -1,4 +1,4 @@
1
- import { type APIMediaGalleryItem, type APIMediaGalleryComponent, ComponentType } from 'discord-api-types/v10';
1
+ import { type APIMediaGalleryComponent, type APIMediaGalleryItem, ComponentType } from 'discord-api-types/v10';
2
2
  import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
3
3
  import { resolveBuilder } from '../../util/resolveBuilder.js';
4
4
  import { validate } from '../../util/validation.js';