@ovencord/builders 1.11.7 → 1.11.8

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@ovencord/builders",
4
- "version": "1.11.7",
4
+ "version": "1.11.8",
5
5
  "description": "A set of builders that you can use when creating your bot",
6
6
  "scripts": {
7
7
  "test": "bun test",
@@ -1,7 +1,7 @@
1
1
  import { ComponentType, SeparatorSpacingSize } from 'discord-api-types/v10';
2
2
  import { z } from 'zod';
3
3
  import { idPredicate } from '../../Assertions.js';
4
- import { actionRowPredicate } from '../Assertions.js';
4
+ import { actionRowPredicate, buttonPredicate } from '../Assertions.js';
5
5
 
6
6
  const unfurledMediaItemPredicate = z.object({
7
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' }),
@@ -57,8 +57,8 @@ export const sectionPredicate = z.object({
57
57
  id: idPredicate,
58
58
  components: z.array(textDisplayPredicate).min(1).max(3),
59
59
  accessory: z.union([
60
- z.object({ type: z.literal(ComponentType.Button) }),
61
- z.object({ type: z.literal(ComponentType.Thumbnail) }),
60
+ buttonPredicate,
61
+ thumbnailPredicate,
62
62
  ]),
63
63
  });
64
64
 
@@ -8,6 +8,7 @@ import {
8
8
  type APIComponentInContainer,
9
9
  type APIMediaGalleryComponent,
10
10
  type APISectionComponent,
11
+ type APIComponentInActionRow,
11
12
  ComponentType,
12
13
  } from 'discord-api-types/v10';
13
14
  import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
@@ -19,7 +20,7 @@ import { createComponentBuilder } from '../Components';
19
20
  import { containerPredicate } from './Assertions';
20
21
  import { FileBuilder } from './File.js';
21
22
  import { MediaGalleryBuilder } from './MediaGallery';
22
- import { SectionBuilder } from './Section';
23
+ import { SectionBuilder } from './Section.js';
23
24
  import { SeparatorBuilder } from './Separator.js';
24
25
  import { TextDisplayBuilder } from './TextDisplay';
25
26
 
@@ -109,7 +110,7 @@ export class ContainerBuilder extends ComponentBuilder<APIContainerComponent> {
109
110
  >
110
111
  ): this {
111
112
  const normalized = normalizeArray(input);
112
- const resolved = normalized.map((component) => resolveBuilder(component, ActionRowBuilder));
113
+ const resolved = normalized.map((component) => resolveBuilder<ActionRowBuilder, Partial<APIActionRowComponent<APIComponentInActionRow>>>(component, ActionRowBuilder));
113
114
 
114
115
  this.data.components.push(...resolved);
115
116
  return this;
@@ -94,6 +94,7 @@ export class SectionBuilder extends ComponentBuilder<APISectionComponent> {
94
94
  public constructor(data: Partial<APISectionComponent> = {}) {
95
95
  super();
96
96
 
97
+
97
98
  const { components = [], accessory, ...rest } = data;
98
99
 
99
100
  this.data = {
@@ -255,23 +256,33 @@ export class SectionBuilder extends ComponentBuilder<APISectionComponent> {
255
256
  return this;
256
257
  }
257
258
 
259
+ /**
260
+ * {@inheritDoc ComponentBuilder.toJSON}
261
+ */
258
262
  /**
259
263
  * {@inheritDoc ComponentBuilder.toJSON}
260
264
  */
261
265
  public override toJSON(validationOverride?: boolean): APISectionComponent {
262
266
  const { components, accessory, ...rest } = this.data;
263
267
 
268
+ // Resolve accessory if it exists
269
+ const accessoryData = accessory
270
+ ? (accessory as any).toJSON
271
+ ? (accessory as any).toJSON(validationOverride)
272
+ : accessory
273
+ : undefined;
274
+
264
275
  const data = {
265
276
  ...structuredClone(rest),
266
- components: components.map((component) => component.toJSON(false)),
267
- accessory: accessory?.toJSON(validationOverride),
268
- };
277
+ type: ComponentType.Section,
278
+ components: components.map((component) => component.toJSON(validationOverride)),
279
+ accessory: accessoryData,
280
+ } as APISectionComponent;
281
+
282
+
269
283
 
270
284
  validate(sectionPredicate, data, validationOverride);
271
-
272
- // DEBUG LOGGING
273
- console.log('[SectionBuilder] toJSON Payload:', JSON.stringify(data, null, 2));
274
285
 
275
- return data as APISectionComponent;
286
+ return data;
276
287
  }
277
288
  }
@@ -56,8 +56,15 @@ export class TextDisplayBuilder extends ComponentBuilder<APITextDisplayComponent
56
56
  */
57
57
  public override toJSON(validationOverride?: boolean): APITextDisplayComponent {
58
58
  const clone = structuredClone(this.data);
59
- validate(textDisplayPredicate, clone, validationOverride);
59
+
60
+ // Enforce only type and content are present
61
+ const data: APITextDisplayComponent = {
62
+ type: ComponentType.TextDisplay,
63
+ content: clone.content!,
64
+ };
65
+
66
+ validate(textDisplayPredicate, data, validationOverride);
60
67
 
61
- return clone as APITextDisplayComponent;
68
+ return data;
62
69
  }
63
70
  }
@@ -93,8 +93,18 @@ export class ThumbnailBuilder extends ComponentBuilder<APIThumbnailComponent> {
93
93
  */
94
94
  public override toJSON(validationOverride?: boolean): APIThumbnailComponent {
95
95
  const clone = structuredClone(this.data);
96
- validate(thumbnailPredicate, clone, validationOverride);
97
96
 
98
- return clone as APIThumbnailComponent;
97
+ // Enforce Type 11 structure: { type: 11, media: { url: ... } }
98
+ // We ignore description and spoiler for now as per V2 accessory specs
99
+ const data: APIThumbnailComponent = {
100
+ type: ComponentType.Thumbnail,
101
+ media: {
102
+ url: clone.media!.url,
103
+ },
104
+ };
105
+
106
+ validate(thumbnailPredicate, data, validationOverride);
107
+
108
+ return data;
99
109
  }
100
110
  }
@@ -17,6 +17,7 @@ import type {
17
17
  APISeparatorComponent,
18
18
  APITextDisplayComponent,
19
19
  APIMessageTopLevelComponent,
20
+ APIComponentInActionRow,
20
21
  } from 'discord-api-types/v10';
21
22
  import { ActionRowBuilder } from '../components/ActionRow.js';
22
23
  import { ComponentBuilder } from '../components/Component.js';
@@ -310,7 +311,7 @@ export class MessageBuilder
310
311
  ): this {
311
312
  this.data.components ??= [];
312
313
 
313
- const resolved = normalizeArray(components).map((component) => resolveBuilder(component, ActionRowBuilder));
314
+ const resolved = normalizeArray(components).map((component) => resolveBuilder<ActionRowBuilder, Partial<APIActionRowComponent<APIComponentInActionRow>>>(component, ActionRowBuilder));
314
315
  this.data.components.push(...resolved);
315
316
 
316
317
  return this;
@@ -36,5 +36,9 @@ export function resolveBuilder<Builder extends JSONEncodable<any>, BuilderData e
36
36
  return builder(new Constructor());
37
37
  }
38
38
 
39
- return new Constructor(builder);
39
+ if (typeof builder === 'object' && builder !== null && 'toJSON' in builder) {
40
+ return new Constructor((builder as unknown as JSONEncodable<BuilderData>).toJSON());
41
+ }
42
+
43
+ return new Constructor(builder as BuilderData);
40
44
  }