mirror of
https://github.com/versia-pub/server.git
synced 2026-04-28 05:09:16 +02:00
refactor: ⬆️ Upgrade to Zod v4 and hono-openapi 0.5.0
This commit is contained in:
parent
add2429606
commit
24d4150da4
209 changed files with 1331 additions and 1622 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
import { Account } from "./account.ts";
|
||||
import { Attachment } from "./attachment.ts";
|
||||
import { PreviewCard } from "./card.ts";
|
||||
|
|
@ -11,28 +11,28 @@ import { NoteReaction } from "./versia.ts";
|
|||
|
||||
export const Mention = z
|
||||
.object({
|
||||
id: Account.shape.id.openapi({
|
||||
id: Account.shape.id.meta({
|
||||
description: "The account ID of the mentioned user.",
|
||||
example: "b9dcb548-bd4d-42af-8b48-3693e6d298e6",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#Mention-id",
|
||||
},
|
||||
}),
|
||||
username: Account.shape.username.openapi({
|
||||
username: Account.shape.username.meta({
|
||||
description: "The username of the mentioned user.",
|
||||
example: "lexi",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#Mention-username",
|
||||
},
|
||||
}),
|
||||
url: Account.shape.url.openapi({
|
||||
url: Account.shape.url.meta({
|
||||
description: "The location of the mentioned user’s profile.",
|
||||
example: "https://beta.versia.social/@lexi",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#Mention-url",
|
||||
},
|
||||
}),
|
||||
acct: Account.shape.acct.openapi({
|
||||
acct: Account.shape.acct.meta({
|
||||
description:
|
||||
"The webfinger acct: URI of the mentioned user. Equivalent to username for local users, or username@domain for remote users.",
|
||||
example: "lexi@beta.versia.social",
|
||||
|
|
@ -41,64 +41,59 @@ export const Mention = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.meta({
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#Mention",
|
||||
},
|
||||
ref: "Mention",
|
||||
id: "Mention",
|
||||
});
|
||||
|
||||
export const StatusSource = z
|
||||
.object({
|
||||
id: Id.openapi({
|
||||
id: Id.meta({
|
||||
description: "ID of the status in the database.",
|
||||
example: "c7db92a4-e472-4e94-a115-7411ee934ba1",
|
||||
}),
|
||||
text: z.string().trim().openapi({
|
||||
text: z.string().trim().meta({
|
||||
description: "The plain text used to compose the status.",
|
||||
example: "this is a status that will be edited",
|
||||
}),
|
||||
// min(0) because some masto-fe clients send empty spoiler_text
|
||||
// when they don't want to set it.
|
||||
spoiler_text: z.string().trim().min(0).max(1024).openapi({
|
||||
spoiler_text: z.string().trim().min(0).max(1024).meta({
|
||||
description:
|
||||
"The plain text used to compose the status’s subject or content warning.",
|
||||
example: "",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.meta({
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/StatusSource",
|
||||
},
|
||||
ref: "StatusSource",
|
||||
id: "StatusSource",
|
||||
});
|
||||
|
||||
// Because Status has some recursive references, we need to define it like this
|
||||
const BaseStatus = z
|
||||
export const Status = z
|
||||
.object({
|
||||
id: Id.openapi({
|
||||
id: Id.meta({
|
||||
description: "ID of the status in the database.",
|
||||
example: "2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#id",
|
||||
},
|
||||
}),
|
||||
uri: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description: "URI of the status used for federation.",
|
||||
example:
|
||||
"https://beta.versia.social/@lexi/2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#uri",
|
||||
},
|
||||
}),
|
||||
uri: z.url().meta({
|
||||
description: "URI of the status used for federation.",
|
||||
example:
|
||||
"https://beta.versia.social/@lexi/2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#uri",
|
||||
},
|
||||
}),
|
||||
url: z
|
||||
.string()
|
||||
.url()
|
||||
.nullable()
|
||||
.openapi({
|
||||
.meta({
|
||||
description: "A link to the status’s HTML representation.",
|
||||
example:
|
||||
"https://beta.versia.social/@lexi/2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
|
|
@ -106,20 +101,20 @@ const BaseStatus = z
|
|||
url: "https://docs.joinmastodon.org/entities/Status/#url",
|
||||
},
|
||||
}),
|
||||
account: Account.openapi({
|
||||
account: Account.meta({
|
||||
description: "The account that authored this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#account",
|
||||
},
|
||||
}),
|
||||
in_reply_to_id: Id.nullable().openapi({
|
||||
in_reply_to_id: Id.nullable().meta({
|
||||
description: "ID of the status being replied to.",
|
||||
example: "c41c9fe9-919a-4d35-a921-d3e79a5c95f8",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#in_reply_to_id",
|
||||
},
|
||||
}),
|
||||
in_reply_to_account_id: Account.shape.id.nullable().openapi({
|
||||
in_reply_to_account_id: Account.shape.id.nullable().meta({
|
||||
description:
|
||||
"ID of the account that authored the status being replied to.",
|
||||
example: "7b9b3ec6-1013-4cc6-8902-94ad00cf2ccc",
|
||||
|
|
@ -128,35 +123,31 @@ const BaseStatus = z
|
|||
},
|
||||
}),
|
||||
|
||||
content: z.string().openapi({
|
||||
content: z.string().meta({
|
||||
description: "HTML-encoded status content.",
|
||||
example: "<p>hello world</p>",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#content",
|
||||
},
|
||||
}),
|
||||
created_at: z
|
||||
.string()
|
||||
.datetime()
|
||||
.openapi({
|
||||
description: "The date when this status was created.",
|
||||
example: "2025-01-07T14:11:00.000Z",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#created_at",
|
||||
},
|
||||
}),
|
||||
edited_at: z
|
||||
.string()
|
||||
created_at: z.iso.datetime().meta({
|
||||
description: "The date when this status was created.",
|
||||
example: "2025-01-07T14:11:00.000Z",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#created_at",
|
||||
},
|
||||
}),
|
||||
edited_at: z.iso
|
||||
.datetime()
|
||||
.nullable()
|
||||
.openapi({
|
||||
.meta({
|
||||
description: "Timestamp of when the status was last edited.",
|
||||
example: "2025-01-07T14:11:00.000Z",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#edited_at",
|
||||
},
|
||||
}),
|
||||
emojis: z.array(CustomEmoji).openapi({
|
||||
emojis: z.array(CustomEmoji).meta({
|
||||
description:
|
||||
"Custom emoji to be used when rendering status content.",
|
||||
externalDocs: {
|
||||
|
|
@ -167,7 +158,7 @@ const BaseStatus = z
|
|||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
.meta({
|
||||
description: "How many replies this status has received.",
|
||||
example: 1,
|
||||
externalDocs: {
|
||||
|
|
@ -178,7 +169,7 @@ const BaseStatus = z
|
|||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
.meta({
|
||||
description: "How many boosts this status has received.",
|
||||
example: 6,
|
||||
externalDocs: {
|
||||
|
|
@ -189,14 +180,14 @@ const BaseStatus = z
|
|||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
.meta({
|
||||
description: "How many favourites this status has received.",
|
||||
example: 11,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#favourites_count",
|
||||
},
|
||||
}),
|
||||
reblogged: zBoolean.optional().openapi({
|
||||
reblogged: zBoolean.optional().meta({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you boosted this status?",
|
||||
example: false,
|
||||
|
|
@ -204,7 +195,7 @@ const BaseStatus = z
|
|||
url: "https://docs.joinmastodon.org/entities/Status/#reblogged",
|
||||
},
|
||||
}),
|
||||
favourited: zBoolean.optional().openapi({
|
||||
favourited: zBoolean.optional().meta({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you favourited this status?",
|
||||
example: true,
|
||||
|
|
@ -212,7 +203,7 @@ const BaseStatus = z
|
|||
url: "https://docs.joinmastodon.org/entities/Status/#favourited",
|
||||
},
|
||||
}),
|
||||
muted: zBoolean.optional().openapi({
|
||||
muted: zBoolean.optional().meta({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you muted notifications for this status’s conversation?",
|
||||
example: false,
|
||||
|
|
@ -220,14 +211,14 @@ const BaseStatus = z
|
|||
url: "https://docs.joinmastodon.org/entities/Status/#muted",
|
||||
},
|
||||
}),
|
||||
sensitive: zBoolean.openapi({
|
||||
sensitive: zBoolean.meta({
|
||||
description: "Is this status marked as sensitive content?",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#sensitive",
|
||||
},
|
||||
}),
|
||||
spoiler_text: z.string().openapi({
|
||||
spoiler_text: z.string().meta({
|
||||
description:
|
||||
"Subject or summary line, below which status content is collapsed until expanded.",
|
||||
example: "lewd text",
|
||||
|
|
@ -235,41 +226,39 @@ const BaseStatus = z
|
|||
url: "https://docs.joinmastodon.org/entities/Status/#spoiler_text",
|
||||
},
|
||||
}),
|
||||
visibility: z
|
||||
.enum(["public", "unlisted", "private", "direct"])
|
||||
.openapi({
|
||||
description: "Visibility of this status.",
|
||||
example: "public",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#visibility",
|
||||
},
|
||||
}),
|
||||
media_attachments: z.array(Attachment).openapi({
|
||||
visibility: z.enum(["public", "unlisted", "private", "direct"]).meta({
|
||||
description: "Visibility of this status.",
|
||||
example: "public",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#visibility",
|
||||
},
|
||||
}),
|
||||
media_attachments: z.array(Attachment).meta({
|
||||
description: "Media that is attached to this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#media_attachments",
|
||||
},
|
||||
}),
|
||||
mentions: z.array(Mention).openapi({
|
||||
mentions: z.array(Mention).meta({
|
||||
description: "Mentions of users within the status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#mentions",
|
||||
},
|
||||
}),
|
||||
tags: z.array(Tag).openapi({
|
||||
tags: z.array(Tag).meta({
|
||||
description: "Hashtags used within the status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#tags",
|
||||
},
|
||||
}),
|
||||
card: PreviewCard.nullable().openapi({
|
||||
card: PreviewCard.nullable().meta({
|
||||
description:
|
||||
"Preview card for links included within status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#card",
|
||||
},
|
||||
}),
|
||||
poll: Poll.nullable().openapi({
|
||||
poll: Poll.nullable().meta({
|
||||
description: "The poll attached to the status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#poll",
|
||||
|
|
@ -277,7 +266,7 @@ const BaseStatus = z
|
|||
}),
|
||||
application: z
|
||||
.object({
|
||||
name: z.string().openapi({
|
||||
name: z.string().meta({
|
||||
description:
|
||||
"The name of the application that posted this status.",
|
||||
externalDocs: {
|
||||
|
|
@ -285,10 +274,9 @@ const BaseStatus = z
|
|||
},
|
||||
}),
|
||||
website: z
|
||||
.string()
|
||||
.url()
|
||||
.nullable()
|
||||
.openapi({
|
||||
.meta({
|
||||
description:
|
||||
"The website associated with the application that posted this status.",
|
||||
externalDocs: {
|
||||
|
|
@ -297,30 +285,41 @@ const BaseStatus = z
|
|||
}),
|
||||
})
|
||||
.optional()
|
||||
.openapi({
|
||||
.meta({
|
||||
description: "The application used to post this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#application",
|
||||
},
|
||||
}),
|
||||
language: iso631.nullable().openapi({
|
||||
language: iso631.nullable().meta({
|
||||
description: "Primary language of this status.",
|
||||
example: "en",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#language",
|
||||
},
|
||||
}),
|
||||
get reblog() {
|
||||
return Status.nullable().meta({
|
||||
description: "The status being reblogged.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#reblog",
|
||||
},
|
||||
});
|
||||
},
|
||||
get quote() {
|
||||
return Status.nullable();
|
||||
},
|
||||
text: z
|
||||
.string()
|
||||
.nullable()
|
||||
.openapi({
|
||||
.meta({
|
||||
description:
|
||||
"Plain-text source of a status. Returned instead of content when status is deleted, so the user may redraft from the source text without the client having to reverse-engineer the original text from the HTML content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#text",
|
||||
},
|
||||
}),
|
||||
pinned: zBoolean.optional().openapi({
|
||||
pinned: zBoolean.optional().meta({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you pinned this status? Only appears if the status is pinnable.",
|
||||
example: true,
|
||||
|
|
@ -328,8 +327,8 @@ const BaseStatus = z
|
|||
url: "https://docs.joinmastodon.org/entities/Status/#pinned",
|
||||
},
|
||||
}),
|
||||
reactions: z.array(NoteReaction).openapi({}),
|
||||
bookmarked: zBoolean.optional().openapi({
|
||||
reactions: z.array(NoteReaction).meta({}),
|
||||
bookmarked: zBoolean.optional().meta({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you bookmarked this status?",
|
||||
example: false,
|
||||
|
|
@ -340,7 +339,7 @@ const BaseStatus = z
|
|||
filtered: z
|
||||
.array(FilterResult)
|
||||
.optional()
|
||||
.openapi({
|
||||
.meta({
|
||||
description:
|
||||
"If the current token has an authorized user: The filter and keywords that matched this status.",
|
||||
externalDocs: {
|
||||
|
|
@ -348,35 +347,23 @@ const BaseStatus = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
ref: "BaseStatus",
|
||||
.meta({
|
||||
id: "Status",
|
||||
});
|
||||
|
||||
export const Status = BaseStatus.extend({
|
||||
reblog: BaseStatus.nullable().openapi({
|
||||
description: "The status being reblogged.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#reblog",
|
||||
},
|
||||
}),
|
||||
quote: BaseStatus.nullable(),
|
||||
}).openapi({
|
||||
ref: "Status",
|
||||
});
|
||||
|
||||
export const ScheduledStatus = z
|
||||
.object({
|
||||
id: Id.openapi({
|
||||
id: Id.meta({
|
||||
description: "ID of the scheduled status in the database.",
|
||||
example: "2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
}),
|
||||
scheduled_at: z.string().datetime().openapi({
|
||||
scheduled_at: z.iso.datetime().meta({
|
||||
description: "When the status will be scheduled.",
|
||||
example: "2025-01-07T14:11:00.000Z",
|
||||
}),
|
||||
media_attachments: Status.shape.media_attachments,
|
||||
params: z.object({
|
||||
text: z.string().openapi({
|
||||
text: z.string().meta({
|
||||
description: "Text to be used as status content.",
|
||||
example: "Hello, world!",
|
||||
}),
|
||||
|
|
@ -384,7 +371,7 @@ export const ScheduledStatus = z
|
|||
media_ids: z
|
||||
.array(Id)
|
||||
.nullable()
|
||||
.openapi({
|
||||
.meta({
|
||||
description:
|
||||
"IDs of the MediaAttachments that will be attached to the status.",
|
||||
example: ["1234567890", "1234567891"],
|
||||
|
|
@ -394,22 +381,22 @@ export const ScheduledStatus = z
|
|||
visibility: Status.shape.visibility,
|
||||
in_reply_to_id: Status.shape.in_reply_to_id,
|
||||
/** Versia Server API Extension */
|
||||
quote_id: z.string().openapi({
|
||||
quote_id: z.string().meta({
|
||||
description: "ID of the status being quoted.",
|
||||
example: "c5d62a13-f340-4e7d-8942-7fd14be688dc",
|
||||
}),
|
||||
language: Status.shape.language,
|
||||
scheduled_at: z.null().openapi({
|
||||
scheduled_at: z.null().meta({
|
||||
description:
|
||||
"When the status will be scheduled. This will be null because the status is only scheduled once.",
|
||||
example: null,
|
||||
}),
|
||||
idempotency: z.string().nullable().openapi({
|
||||
idempotency: z.string().nullable().meta({
|
||||
description: "Idempotency key to prevent duplicate statuses.",
|
||||
example: "1234567890",
|
||||
}),
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
ref: "ScheduledStatus",
|
||||
.meta({
|
||||
id: "ScheduledStatus",
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue