Repository: discordjs/discord.js
File: packages/builders/src/messages/Assertions.ts (TypeScript)

Code before:
		.object({
			type: z.literal([
				ComponentType.Button,
				ComponentType.ChannelSelect,
				ComponentType.MentionableSelect,
				ComponentType.RoleSelect,
				ComponentType.StringSelect,
				ComponentType.UserSelect,
			]),
		})
		.array(),
});

const messageNoComponentsV2Predicate = baseMessagePredicate
	.extend({
		content: z.string().max(2_000).optional(),
		embeds: embedPredicate.array().max(10).optional(),
		sticker_ids: z.array(z.string()).max(3).optional(),
		poll: pollPredicate.optional(),
		components: basicActionRowPredicate.array().max(5).optional(),
		flags: z
			.number()
			.optional()
			// If we have flags, ensure we don't have the ComponentsV2 flag
			.refine((flags) => !flags || (flags & MessageFlags.IsComponentsV2) === 0, {
				error: 'ComponentsV2 flag cannot be set on messages without components v2',
			}),
	})
	.refine(
		(data) =>
			data.content !== undefined ||
			(data.embeds !== undefined && data.embeds.length > 0) ||
			data.poll !== undefined ||
			(data.attachments !== undefined && data.attachments.length > 0) ||
			(data.components !== undefined && data.components.length > 0) ||
			(data.sticker_ids !== undefined && data.sticker_ids.length > 0),
		{ error: 'Messages must have content, embeds, a poll, attachments, components or stickers' },
	);

const allTopLevelComponentsPredicate = z
	.union([
		basicActionRowPredicate,
		z.object({
			type: z.literal([
				// Components v2
				ComponentType.Container,
				ComponentType.File,
				ComponentType.MediaGallery,
				ComponentType.Section,
				ComponentType.Separator,
				ComponentType.TextDisplay,

Review comment (suggestion):
This is absolutely not true, you CAN set the flag and not use components v2 (aka send a message with just `components: [actionRowsHere]`)

Code after:
		.object({
			type: z.literal([
				ComponentType.Button,
				ComponentType.ChannelSelect,
				ComponentType.MentionableSelect,
				ComponentType.RoleSelect,
				ComponentType.StringSelect,
				ComponentType.UserSelect,
			]),
		})
		.array(),
});

const messageNoComponentsV2Predicate = baseMessagePredicate
	.extend({
		content: z.string().max(2_000).optional(),
		embeds: embedPredicate.array().max(10).optional(),
		sticker_ids: z.array(z.string()).max(3).optional(),
		poll: pollPredicate.optional(),
		components: basicActionRowPredicate.array().max(5).optional(),
		flags: z
			.int()
			.optional()
			.refine((flags) => !flags || (flags & MessageFlags.IsComponentsV2) === 0, {
				error: 'Cannot set content, embeds, stickers, or poll with IsComponentsV2 flag set',
			}),
	})
	.refine(
		(data) =>
			data.content !== undefined ||
			(data.embeds !== undefined && data.embeds.length > 0) ||
			data.poll !== undefined ||
			(data.attachments !== undefined && data.attachments.length > 0) ||
			(data.components !== undefined && data.components.length > 0) ||
			(data.sticker_ids !== undefined && data.sticker_ids.length > 0),
		{ error: 'Messages must have content, embeds, a poll, attachments, components or stickers' },
	);

const allTopLevelComponentsPredicate = z
	.union([
		basicActionRowPredicate,
		z.object({
			type: z.literal([
				// Components v2
				ComponentType.Container,
				ComponentType.File,
				ComponentType.MediaGallery,
				ComponentType.Section,
				ComponentType.Separator,
				ComponentType.TextDisplay,
				ComponentType.Thumbnail,