feat: Port code from Lysand Server and improve it

This commit is contained in:
Jesse Wierzbinski 2024-05-13 21:00:05 -10:00
parent ef76ee4a5c
commit bf8898acee
No known key found for this signature in database
18 changed files with 733 additions and 89 deletions

View file

@ -0,0 +1,50 @@
/**
* Custom emojis extension.
* @module federation/schemas/extensions/custom_emojis
* @see module:federation/schemas/base
* @see https://lysand.org/extensions/custom-emojis
*/
import { z } from "zod";
import { ContentFormat } from "../content_format";
import { emojiRegex } from "../regex";
/**
* @description Used to validate the properties the extension's custom field
* @see https://lysand.org/extensions/custom-emojis
* @example
* {
* // ...
* "extensions": {
* "org.lysand:custom_emojis": {
* "emojis": [
* {
* "name": "happy_face",
* "url": {
* "image/png": {
* "content": "https://cdn.example.com/emojis/happy_face.png",
* "content_type": "image/png"
* }
* }
* },
* // ...
* ]
* }
* }
* // ...
* }
*/
export const CustomEmojiExtension = z.object({
emojis: z.array(
z.object({
name: z
.string()
.min(1)
.max(256)
.regex(
emojiRegex,
"Emoji name must be alphanumeric, underscores, or dashes.",
),
url: ContentFormat,
}),
),
});

View file

@ -0,0 +1,92 @@
/**
* Polls extension
* @module federation/schemas/extensions/polls
* @see module:federation/schemas/base
* @see https://lysand.org/extensions/polls
*/
import { z } from "zod";
import { Extension } from "../base";
import { ContentFormat } from "../content_format";
/**
* @description Poll extension entity
* @see https://lysand.org/extensions/polls
* @example
* {
* "type": "Extension",
* "id": "d6eb84ea-cd13-43f9-9c54-01244da8e5e3",
* "extension_type": "org.lysand:polls/Poll",
* "uri": "https://example.com/polls/d6eb84ea-cd13-43f9-9c54-01244da8e5e3",
* "options": [
* {
* "text/plain": {
* "content": "Red"
* }
* },
* {
* "text/plain": {
* "content": "Blue"
* }
* },
* {
* "text/plain": {
* "content": "Green"
* }
* }
* ],
* "votes": [
* 9,
* 5,
* 0
* ],
* "multiple_choice": false,
* "expires_at": "2021-01-04T00:00:00.000Z"
* }
*/
export const Poll = Extension.extend({
extension_type: z.literal("org.lysand:polls/Poll"),
options: z.array(ContentFormat),
votes: z.array(z.number().int().nonnegative()),
multiple_choice: z.boolean().optional(),
expires_at: z.string(),
});
/**
* @description Vote extension entity
* @see https://lysand.org/extensions/polls
* @example
* {
* "type": "Extension",
* "id": "31c4de70-e266-4f61-b0f7-3767d3ccf565",
* "created_at": "2021-01-01T00:00:00.000Z",
* "uri": "https://example.com/votes/31c4de70-e266-4f61-b0f7-3767d3ccf565",
* "extension_type": "org.lysand:polls/Vote",
* "poll": "https://example.com/polls/31c4de70-e266-4f61-b0f7-3767d3ccf565",
* "option": 1
* }
*/
export const Vote = Extension.extend({
extension_type: z.literal("org.lysand:polls/Vote"),
poll: z.string().url(),
option: z.number(),
});
/**
* @description Vote result extension entity
* @see https://lysand.org/extensions/polls
* @example
* {
* "type": "Extension",
* "id": "c6d5755b-f42c-418f-ab53-2ee3705d6628",
* "created_at": "2021-01-01T00:00:00.000Z",
* "uri": "https://example.com/polls/c6d5755b-f42c-418f-ab53-2ee3705d6628/result",
* "extension_type": "org.lysand:polls/VoteResult",
* "poll": "https://example.com/polls/c6d5755b-f42c-418f-ab53-2ee3705d6628",
* "votes": [9, 5, 0]
* }
*/
export const VoteResult = Extension.extend({
extension_type: z.literal("org.lysand:polls/VoteResult"),
poll: z.string().url(),
votes: z.array(z.number().int().nonnegative()),
});

View file

@ -0,0 +1,28 @@
/**
* Reactions extension
* @module federation/schemas/extensions/reactions
* @see module:federation/schemas/base
* @see https://lysand.org/extensions/reactions
*/
import { z } from "zod";
import { Extension } from "../base";
/**
* @description Reaction extension entity
* @see https://lysand.org/extensions/reactions
* @example
* {
* "type": "Extension",
* "id": "d6eb84ea-cd13-43f9-9c54-01244da8e5e3",
* "created_at": "2021-01-01T00:00:00.000Z",
* "uri": "https://example.com/reactions/d6eb84ea-cd13-43f9-9c54-01244da8e5e3",
* "extension_type": "org.lysand:reactions/Reaction",
* "object": "https://example.com/posts/d6eb84ea-cd13-43f9-9c54-01244da8e5e3",
* "content": "👍"
* }
*/
export const Reaction = Extension.extend({
extension_type: z.literal("org.lysand:reactions/Reaction"),
object: z.string().url(),
content: z.string(),
});

View file

@ -0,0 +1,93 @@
/**
* Vanity extension schema.
* @module federation/schemas/extensions/vanity
* @see module:federation/schemas/base
* @see https://lysand.org/extensions/vanity
*/
import { z } from "zod";
import { ContentFormat } from "../content_format";
/**
* @description Vanity extension entity
* @see https://lysand.org/extensions/vanity
* @example
* {
* // ...
* "type": "User",
* // ...
* "extensions": {
* "org.lysand:vanity": {
* "avatar_overlay": {
* "image/png": {
* "content": "https://cdn.example.com/ab5081cf-b11f-408f-92c2-7c246f290593/cat_ears.png",
* "content_type": "image/png"
* }
* },
* "avatar_mask": {
* "image/png": {
* "content": "https://cdn.example.com/d8c42be1-d0f7-43ef-b4ab-5f614e1beba4/rounded_square.jpeg",
* "content_type": "image/jpeg"
* }
* },
* "background": {
* "image/png": {
* "content": "https://cdn.example.com/6492ddcd-311e-4921-9567-41b497762b09/untitled-file-0019822.png",
* "content_type": "image/png"
* }
* },
* "audio": {
* "audio/mpeg": {
* "content": "https://cdn.example.com/4da2f0d4-4728-4819-83e4-d614e4c5bebc/michael-jackson-thriller.mp3",
* "content_type": "audio/mpeg"
* }
* },
* "pronouns": {
* "en-us": [
* "he/him",
* {
* "subject": "they",
* "object": "them",
* "dependent_possessive": "their",
* "independent_possessive": "theirs",
* "reflexive": "themself"
* },
* ]
* },
* "birthday": "1998-04-12",
* "location": "+40.6894-074.0447/",
* "activitypub": [
* "@erikuden@mastodon.de"
* ],
* "aliases": [
* "https://burger.social/accounts/349ee237-c672-41c1-aadc-677e185f795a",
* "https://social.lysand.org/users/f565ef02-035d-4974-ba5e-f62a8558331d"
* ]
* }
* }
* }
*/
export 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(),
});