mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 16:38:19 +01:00
262 lines
6.5 KiB
TypeScript
262 lines
6.5 KiB
TypeScript
|
|
import { z } from "zod";
|
||
|
|
|
||
|
|
const Entity = z.object({
|
||
|
|
id: z.string().uuid(),
|
||
|
|
created_at: z.string(),
|
||
|
|
uri: z.string().url(),
|
||
|
|
type: z.string(),
|
||
|
|
extensions: z.object({
|
||
|
|
"org.lysand:custom_emojis": z.object({
|
||
|
|
emojis: z.array(
|
||
|
|
z.object({
|
||
|
|
shortcode: z.string(),
|
||
|
|
url: z.string(),
|
||
|
|
}),
|
||
|
|
),
|
||
|
|
}),
|
||
|
|
}),
|
||
|
|
});
|
||
|
|
|
||
|
|
const ContentFormat = z.record(
|
||
|
|
z.string(),
|
||
|
|
z.object({
|
||
|
|
content: z.string(),
|
||
|
|
description: z.string().optional(),
|
||
|
|
size: z.number().optional(),
|
||
|
|
hash: z.record(z.string().optional()).optional(),
|
||
|
|
blurhash: z.string().optional(),
|
||
|
|
fps: z.number().optional(),
|
||
|
|
width: z.number().optional(),
|
||
|
|
height: z.number().optional(),
|
||
|
|
duration: z.number().optional(),
|
||
|
|
}),
|
||
|
|
);
|
||
|
|
|
||
|
|
const Visibility = z.enum(["public", "unlisted", "private", "direct"]);
|
||
|
|
|
||
|
|
const Publication = Entity.extend({
|
||
|
|
type: z.union([z.literal("Note"), z.literal("Patch")]),
|
||
|
|
author: z.string().url(),
|
||
|
|
content: ContentFormat.optional(),
|
||
|
|
attachments: z.array(ContentFormat).optional(),
|
||
|
|
replies_to: z.string().url().optional(),
|
||
|
|
quotes: z.string().url().optional(),
|
||
|
|
mentions: z.array(z.string().url()).optional(),
|
||
|
|
subject: z.string().optional(),
|
||
|
|
is_sensitive: z.boolean().optional(),
|
||
|
|
visibility: Visibility,
|
||
|
|
extensions: Entity.shape.extensions.extend({
|
||
|
|
"org.lysand:reactions": z
|
||
|
|
.object({
|
||
|
|
reactions: z.string(),
|
||
|
|
})
|
||
|
|
.optional(),
|
||
|
|
"org.lysand:polls": z
|
||
|
|
.object({
|
||
|
|
poll: z.object({
|
||
|
|
options: z.array(ContentFormat),
|
||
|
|
votes: z.array(z.number()),
|
||
|
|
multiple_choice: z.boolean().optional(),
|
||
|
|
expires_at: z.string(),
|
||
|
|
}),
|
||
|
|
})
|
||
|
|
.optional(),
|
||
|
|
}),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Note = Publication.extend({
|
||
|
|
type: z.literal("Note"),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Patch = Publication.extend({
|
||
|
|
type: z.literal("Patch"),
|
||
|
|
patched_id: z.string().uuid(),
|
||
|
|
patched_at: z.string(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const ActorPublicKeyData = z.object({
|
||
|
|
public_key: z.string(),
|
||
|
|
actor: z.string().url(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const VanityExtension = z.object({
|
||
|
|
avatar_overlay: ContentFormat.optional(),
|
||
|
|
avatar_mask: ContentFormat.optional(),
|
||
|
|
background: ContentFormat.optional(),
|
||
|
|
audio: ContentFormat.optional(),
|
||
|
|
pronouns: z.record(
|
||
|
|
z.string(),
|
||
|
|
z.array(
|
||
|
|
z.union([
|
||
|
|
z.object({
|
||
|
|
subject: z.string(),
|
||
|
|
object: z.string(),
|
||
|
|
dependent_possessive: z.string(),
|
||
|
|
independent_possessive: z.string(),
|
||
|
|
reflexive: z.string(),
|
||
|
|
}),
|
||
|
|
z.string(),
|
||
|
|
]),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
birthday: z.string().optional(),
|
||
|
|
location: z.string().optional(),
|
||
|
|
activitypub: z.string().optional(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const User = Entity.extend({
|
||
|
|
type: z.literal("User"),
|
||
|
|
display_name: z.string().optional(),
|
||
|
|
username: z.string(),
|
||
|
|
avatar: ContentFormat.optional(),
|
||
|
|
header: ContentFormat.optional(),
|
||
|
|
indexable: z.boolean(),
|
||
|
|
public_key: ActorPublicKeyData,
|
||
|
|
bio: ContentFormat.optional(),
|
||
|
|
fields: z
|
||
|
|
.array(
|
||
|
|
z.object({
|
||
|
|
name: ContentFormat,
|
||
|
|
value: ContentFormat,
|
||
|
|
}),
|
||
|
|
)
|
||
|
|
.optional(),
|
||
|
|
featured: z.string().url(),
|
||
|
|
followers: z.string().url(),
|
||
|
|
following: z.string().url(),
|
||
|
|
likes: z.string().url(),
|
||
|
|
dislikes: z.string().url(),
|
||
|
|
inbox: z.string().url(),
|
||
|
|
outbox: z.string().url(),
|
||
|
|
extensions: Entity.shape.extensions.extend({
|
||
|
|
"org.lysand:vanity": VanityExtension.optional(),
|
||
|
|
}),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Action = Entity.extend({
|
||
|
|
type: z.union([
|
||
|
|
z.literal("Like"),
|
||
|
|
z.literal("Dislike"),
|
||
|
|
z.literal("Follow"),
|
||
|
|
z.literal("FollowAccept"),
|
||
|
|
z.literal("FollowReject"),
|
||
|
|
z.literal("Announce"),
|
||
|
|
z.literal("Undo"),
|
||
|
|
]),
|
||
|
|
author: z.string().url(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Like = Action.extend({
|
||
|
|
type: z.literal("Like"),
|
||
|
|
object: z.string().url(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Undo = Action.extend({
|
||
|
|
type: z.literal("Undo"),
|
||
|
|
object: z.string().url(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Dislike = Action.extend({
|
||
|
|
type: z.literal("Dislike"),
|
||
|
|
object: z.string().url(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Follow = Action.extend({
|
||
|
|
type: z.literal("Follow"),
|
||
|
|
followee: z.string().url(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const FollowAccept = Action.extend({
|
||
|
|
type: z.literal("FollowAccept"),
|
||
|
|
follower: z.string().url(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const FollowReject = Action.extend({
|
||
|
|
type: z.literal("FollowReject"),
|
||
|
|
follower: z.string().url(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Announce = Action.extend({
|
||
|
|
type: z.literal("Announce"),
|
||
|
|
object: z.string().url(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Extension = Entity.extend({
|
||
|
|
type: z.literal("Extension"),
|
||
|
|
extension_type: z.string(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Reaction = Extension.extend({
|
||
|
|
extension_type: z.literal("org.lysand:reactions/Reaction"),
|
||
|
|
object: z.string().url(),
|
||
|
|
content: z.string(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Poll = Extension.extend({
|
||
|
|
extension_type: z.literal("org.lysand:polls/Poll"),
|
||
|
|
options: z.array(ContentFormat),
|
||
|
|
votes: z.array(z.number()),
|
||
|
|
multiple_choice: z.boolean().optional(),
|
||
|
|
expires_at: z.string(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Vote = Extension.extend({
|
||
|
|
extension_type: z.literal("org.lysand:polls/Vote"),
|
||
|
|
poll: z.string().url(),
|
||
|
|
option: z.number(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const VoteResult = Extension.extend({
|
||
|
|
extension_type: z.literal("org.lysand:polls/VoteResult"),
|
||
|
|
poll: z.string().url(),
|
||
|
|
votes: z.array(z.number()),
|
||
|
|
});
|
||
|
|
|
||
|
|
const Report = Extension.extend({
|
||
|
|
extension_type: z.literal("org.lysand:reports/Report"),
|
||
|
|
objects: z.array(z.string().url()),
|
||
|
|
reason: z.string(),
|
||
|
|
comment: z.string().optional(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const ServerMetadata = Entity.extend({
|
||
|
|
type: z.literal("ServerMetadata"),
|
||
|
|
name: z.string(),
|
||
|
|
version: z.string(),
|
||
|
|
description: z.string().optional(),
|
||
|
|
website: z.string().optional(),
|
||
|
|
moderators: z.array(z.string()).optional(),
|
||
|
|
admins: z.array(z.string()).optional(),
|
||
|
|
logo: ContentFormat.optional(),
|
||
|
|
banner: ContentFormat.optional(),
|
||
|
|
supported_extensions: z.array(z.string()),
|
||
|
|
extensions: z.record(z.string(), z.any()).optional(),
|
||
|
|
});
|
||
|
|
|
||
|
|
export const schemas = {
|
||
|
|
Entity,
|
||
|
|
ContentFormat,
|
||
|
|
Visibility,
|
||
|
|
Publication,
|
||
|
|
Note,
|
||
|
|
Patch,
|
||
|
|
ActorPublicKeyData,
|
||
|
|
VanityExtension,
|
||
|
|
User,
|
||
|
|
Action,
|
||
|
|
Like,
|
||
|
|
Undo,
|
||
|
|
Dislike,
|
||
|
|
Follow,
|
||
|
|
FollowAccept,
|
||
|
|
FollowReject,
|
||
|
|
Announce,
|
||
|
|
Extension,
|
||
|
|
Reaction,
|
||
|
|
Poll,
|
||
|
|
Vote,
|
||
|
|
VoteResult,
|
||
|
|
Report,
|
||
|
|
ServerMetadata,
|
||
|
|
};
|