refactor(schema): simplify validation and OpenAPI generation (#2709)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-11 23:24:26 +02:00
1 parent 4bc5593f9f
commit de1fd95a99
510 files changed
+29494 -36131

No files matched your search

@@ -36,14 +36,12 @@ export const ClientAttachmentRequest = ClientAttachmentBase.extend({
export type ClientAttachmentRequest = z.infer<typeof ClientAttachmentRequest>;
export const ClientUploadedAttachmentRequest = ClientAttachmentBase.extend({
id: coerceNumberFromString(Int32Type).describe('The client-side identifier for this attachment'),
filename: FilenameType.describe('The name of the file being uploaded'),
export const ClientUploadedAttachmentRequest = ClientAttachmentRequest.extend({
upload_filename: createStringType(1, 4096).describe(
'Temporary upload key returned by the attachment upload endpoint',
),
file_size: coerceNumberFromString(NonNegativeSafeIntegerType).describe('Uploaded file size in bytes'),
content_type: createStringType(1, 255).describe('MIME type of the uploaded file'),
content_type: ClientAttachmentRequest.shape.content_type.unwrap().describe('MIME type of the uploaded file'),
});
export type ClientUploadedAttachmentRequest = z.infer<typeof ClientUploadedAttachmentRequest>;
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {ATTACHMENT_UPLOAD_MAX_CHUNKS, MAX_ATTACHMENTS_PER_MESSAGE} from '@fluxer/constants/src/LimitConstants';
import {FilenameType} from '@fluxer/schema/src/primitives/FileValidators';
import {ClientUploadedAttachmentRequest} from '@fluxer/schema/src/domains/message/AttachmentSchemas';
import {
coerceNumberFromString,
createStringType,
@@ -12,10 +12,10 @@ import {URLType} from '@fluxer/schema/src/primitives/UrlValidators';
import {z} from 'zod';
export const PresignedAttachmentUploadRequestItem = z.object({
id: coerceNumberFromString(Int32Type).describe('The client-side identifier for this attachment'),
filename: FilenameType.describe('The name of the file that will be uploaded'),
file_size: coerceNumberFromString(NonNegativeSafeIntegerType).describe('Expected file size in bytes'),
content_type: createStringType(1, 255).describe('MIME type the client will upload'),
id: ClientUploadedAttachmentRequest.shape.id,
filename: ClientUploadedAttachmentRequest.shape.filename.describe('The name of the file that will be uploaded'),
file_size: ClientUploadedAttachmentRequest.shape.file_size.describe('Expected file size in bytes'),
content_type: ClientUploadedAttachmentRequest.shape.content_type.describe('MIME type the client will upload'),
});
export type PresignedAttachmentUploadRequestItem = z.infer<typeof PresignedAttachmentUploadRequestItem>;
@@ -30,12 +30,12 @@ export const PresignedAttachmentUploadRequest = z.object({
export type PresignedAttachmentUploadRequest = z.infer<typeof PresignedAttachmentUploadRequest>;
const PresignedAttachmentUploadBase = z.object({
id: coerceNumberFromString(Int32Type).describe('The client-side identifier for this attachment'),
filename: FilenameType.describe('The original filename for this upload'),
upload_filename: createStringType(1, 4096).describe('Temporary upload key to reference in message send payloads'),
file_size: coerceNumberFromString(NonNegativeSafeIntegerType).describe('Expected file size in bytes'),
content_type: createStringType(1, 255).describe('Expected MIME type for this upload'),
const PresignedAttachmentUploadBase = PresignedAttachmentUploadRequestItem.extend({
filename: PresignedAttachmentUploadRequestItem.shape.filename.describe('The original filename for this upload'),
upload_filename: ClientUploadedAttachmentRequest.shape.upload_filename.describe(
'Temporary upload key to reference in message send payloads',
),
content_type: PresignedAttachmentUploadRequestItem.shape.content_type.describe('Expected MIME type for this upload'),
});
const PresignedAttachmentUploadSinglepart = PresignedAttachmentUploadBase.extend({
upload_mode: z.literal('singlepart'),
@@ -72,7 +72,9 @@ export const PresignedAttachmentUploadResponse = z.object({
export type PresignedAttachmentUploadResponse = z.infer<typeof PresignedAttachmentUploadResponse>;
export const CompleteMultipartAttachmentUploadItem = z.object({
upload_filename: createStringType(1, 4096).describe('The upload_filename returned when the upload was planned'),
upload_filename: ClientUploadedAttachmentRequest.shape.upload_filename.describe(
'The upload_filename returned when the upload was planned',
),
upload_id: createStringType(1, 1024).describe('The upload_id returned when the upload was planned'),
});
@@ -89,7 +91,7 @@ export const CompleteMultipartAttachmentUploadRequest = z.object({
export type CompleteMultipartAttachmentUploadRequest = z.infer<typeof CompleteMultipartAttachmentUploadRequest>;
export const CompleteMultipartAttachmentUploadResult = z.object({
upload_filename: createStringType(1, 4096).describe('Finalized upload key'),
upload_filename: ClientUploadedAttachmentRequest.shape.upload_filename.describe('Finalized upload key'),
});
export type CompleteMultipartAttachmentUploadResult = z.infer<typeof CompleteMultipartAttachmentUploadResult>;
@@ -49,31 +49,6 @@ export const EmbedFieldResponse = z.object({
export type EmbedFieldResponse = z.infer<typeof EmbedFieldResponse>;
interface MessageEmbedChildResponseData {
type: string;
url?: string | null;
title?: string | null;
color?: number | null;
timestamp?: string | null;
description?: string | null;
author?: EmbedAuthorResponse | null;
image?: EmbedMediaResponse | null;
thumbnail?: EmbedMediaResponse | null;
footer?: EmbedFooterResponse | null;
fields?: Array<EmbedFieldResponse> | null;
provider?: EmbedAuthorResponse | null;
video?: EmbedMediaResponse | null;
audio?: EmbedMediaResponse | null;
html?: string | null;
html_width?: number | null;
html_height?: number | null;
nsfw?: boolean | null;
}
interface MessageEmbedResponseData extends MessageEmbedChildResponseData {
children?: Array<MessageEmbedChildResponseData> | null;
}
export const MessageEmbedChildResponse = z.object({
type: z.string().describe('The type of embed (e.g., rich, image, video, gifv, article, link)'),
url: z.url().nullish().describe('The URL of the embed'),
@@ -97,7 +72,7 @@ export const MessageEmbedChildResponse = z.object({
export type MessageEmbedChildResponse = z.infer<typeof MessageEmbedChildResponse>;
export const MessageEmbedResponse: z.ZodType<MessageEmbedResponseData> = MessageEmbedChildResponse.extend({
export const MessageEmbedResponse = MessageEmbedChildResponse.extend({
children: z
.array(MessageEmbedChildResponse)
.max(1)
@@ -134,34 +109,10 @@ export interface EmbedMedia {
readonly nsfw?: boolean;
}
export interface EmbedField {
readonly name: string;
readonly value: string;
readonly inline: boolean;
}
export type EmbedField = Readonly<EmbedFieldResponse>;
export interface MessageEmbed {
readonly id?: string;
readonly type: string;
readonly url?: string;
readonly title?: string;
readonly color?: number;
readonly timestamp?: string;
readonly description?: string;
readonly author?: EmbedAuthor;
readonly image?: EmbedMedia;
readonly thumbnail?: EmbedMedia;
readonly footer?: EmbedFooter;
readonly fields?: ReadonlyArray<EmbedField>;
readonly provider?: EmbedAuthor;
readonly video?: EmbedMedia;
readonly audio?: EmbedMedia;
readonly html?: string;
readonly html_width?: number;
readonly html_height?: number;
export interface MessageEmbed extends MessageEmbedChild {
readonly children?: ReadonlyArray<MessageEmbedChild>;
readonly flags?: number;
readonly nsfw?: boolean;
}
export interface MessageEmbedChild {
@@ -312,7 +312,6 @@ export const MessageNonceRequest = z
.number()
.int()
.nonnegative()
.safe()
.transform((value) => value.toString()),
])
.pipe(createStringType(1, 32))
@@ -464,7 +463,7 @@ export const ChannelPinsQuerySchema = z.object({
.max(50)
.optional()
.describe('Maximum number of pinned messages to return (1-50)'),
before: z.coerce.date().optional().describe('Get pinned messages before this timestamp'),
before: z.string().pipe(z.coerce.date()).optional().describe('Get pinned messages before this timestamp'),
});
export type ChannelPinsQuerySchema = z.infer<typeof ChannelPinsQuerySchema>;
@@ -301,11 +301,7 @@ export interface MessageSnapshot {
readonly timestamp: string;
}
export interface MessageStickerItem {
readonly id: string;
readonly name: string;
readonly animated: boolean;
}
export type MessageStickerItem = Readonly<MessageStickerResponse>;
export interface AllowedMentions {
readonly parse?: ReadonlyArray<'roles' | 'users' | 'everyone'>;
@@ -314,11 +310,7 @@ export interface AllowedMentions {
readonly replied_user?: boolean;
}
export interface ChannelMention {
readonly id: string;
readonly type: number;
readonly name: string;
}
export type ChannelMention = Readonly<MessageChannelMentionResponse>;
export interface MessageMention extends UserPartial {
readonly member?: Omit<GuildMemberData, 'user'>;
@@ -357,3 +349,5 @@ export interface Message {
readonly _allowedMentions?: AllowedMentions;
readonly _favoriteMemeId?: string;
}
export const MessagePurgeResponse = z.object({deleted_count: z.number().int().nonnegative()});
@@ -47,7 +47,7 @@ export const MessageReferenceRequest = z
return true;
},
{
message: 'Forward message reference must include channel_id and message_id',
error: 'Forward message reference must include channel_id and message_id',
},
);