diff --git a/packages/builders/__tests__/messages/embed.test.ts b/packages/builders/__tests__/messages/embed.test.ts index 65097ef23..5b04b51dd 100644 --- a/packages/builders/__tests__/messages/embed.test.ts +++ b/packages/builders/__tests__/messages/embed.test.ts @@ -207,6 +207,12 @@ describe('Embed', () => { expect(embed.toJSON()).toStrictEqual({ ...base, thumbnail: { url: 'https://discord.js.org/static/logo.svg' } }); }); + test('GIVEN an embed using Embed#setThumbnail with attachment protocol THEN returns valid toJSON data', () => { + const embed = new EmbedBuilder(); + embed.setThumbnail('attachment://discordjs.webp'); + expect(embed.toJSON()).toStrictEqual({ ...base, thumbnail: { url: 'attachment://discordjs.webp' } }); + }); + test('GIVEN an embed with a pre-defined thumbnail THEN unset thumbnail THEN return valid toJSON data', () => { const embed = new EmbedBuilder({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' }, ...dummy }); embed.clearThumbnail(); @@ -228,6 +234,12 @@ describe('Embed', () => { expect(embed.toJSON()).toStrictEqual({ ...base, image: { url: 'https://discord.js.org/static/logo.svg' } }); }); + test('GIVEN an embed using Embed#setImage with attachment protocol THEN returns valid toJSON data', () => { + const embed = new EmbedBuilder(); + embed.setImage('attachment://discordjs.webp'); + expect(embed.toJSON()).toStrictEqual({ ...base, image: { url: 'attachment://discordjs.webp' } }); + }); + test('GIVEN an embed using Embed#setImage THEN returns valid toJSON data', () => { const embed = new EmbedBuilder(); embed.setImage('https://discord.js.org/static/logo.svg'); diff --git a/packages/builders/src/messages/embed/Assertions.ts b/packages/builders/src/messages/embed/Assertions.ts index 9f7f06a47..aea6d805f 100644 --- a/packages/builders/src/messages/embed/Assertions.ts +++ b/packages/builders/src/messages/embed/Assertions.ts @@ -4,18 +4,18 @@ import { embedLength } from '../../util/componentUtil.js'; const namePredicate = z.string().max(256); -const iconURLPredicate = z - .string() - .url() - .refine(refineURLPredicate(['http:', 'https:', 'attachment:']), { - message: 'Invalid protocol for icon URL. Must be http:, https:, or attachment:', - }); - const URLPredicate = z .string() .url() .refine(refineURLPredicate(['http:', 'https:']), { message: 'Invalid protocol for URL. Must be http: or https:' }); +const URLWithAttachmentProtocolPredicate = z + .string() + .url() + .refine(refineURLPredicate(['http:', 'https:', 'attachment:']), { + message: 'Invalid protocol for URL. Must be http:, https:, or attachment:', + }); + export const embedFieldPredicate = z.object({ name: namePredicate, value: z.string().max(1_024), @@ -24,13 +24,13 @@ export const embedFieldPredicate = z.object({ export const embedAuthorPredicate = z.object({ name: namePredicate.min(1), - icon_url: iconURLPredicate.optional(), + icon_url: URLWithAttachmentProtocolPredicate.optional(), url: URLPredicate.optional(), }); export const embedFooterPredicate = z.object({ text: z.string().min(1).max(2_048), - icon_url: iconURLPredicate.optional(), + icon_url: URLWithAttachmentProtocolPredicate.optional(), }); export const embedPredicate = z @@ -41,8 +41,8 @@ export const embedPredicate = z timestamp: z.string().optional(), color: z.number().int().min(0).max(0xffffff).optional(), footer: embedFooterPredicate.optional(), - image: z.object({ url: URLPredicate }).optional(), - thumbnail: z.object({ url: URLPredicate }).optional(), + image: z.object({ url: URLWithAttachmentProtocolPredicate }).optional(), + thumbnail: z.object({ url: URLWithAttachmentProtocolPredicate }).optional(), author: embedAuthorPredicate.optional(), fields: z.array(embedFieldPredicate).max(25).optional(), })