mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
Fix conversion between database and Lysand types
This commit is contained in:
parent
6d0a8a6478
commit
8563c97403
2
build.ts
2
build.ts
|
|
@ -36,7 +36,7 @@ await $`sed -i 's|import("node_modules/|import("./node_modules/|g' dist/*.js`;
|
||||||
// Copy generated Prisma client to dist
|
// Copy generated Prisma client to dist
|
||||||
await $`mkdir -p dist/node_modules/@prisma`;
|
await $`mkdir -p dist/node_modules/@prisma`;
|
||||||
await $`cp -r ${process.cwd()}/node_modules/@prisma dist/node_modules/`;
|
await $`cp -r ${process.cwd()}/node_modules/@prisma dist/node_modules/`;
|
||||||
await $`cp -r ${process.cwd()}/node_modules/.prisma dist/node_modules`;
|
//await $`cp -r ${process.cwd()}/node_modules/.prisma dist/node_modules`;
|
||||||
await $`mkdir -p dist/node_modules/.bin`;
|
await $`mkdir -p dist/node_modules/.bin`;
|
||||||
await $`cp -r ${process.cwd()}/node_modules/.bin/prisma dist/node_modules/.bin`;
|
await $`cp -r ${process.cwd()}/node_modules/.bin/prisma dist/node_modules/.bin`;
|
||||||
await $`cp -r ${process.cwd()}/node_modules/prisma dist/node_modules/`;
|
await $`cp -r ${process.cwd()}/node_modules/prisma dist/node_modules/`;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import type { Config } from "config-manager";
|
||||||
import { MediaBackendType } from "media-manager";
|
import { MediaBackendType } from "media-manager";
|
||||||
import type { APIAsyncAttachment } from "~types/entities/async_attachment";
|
import type { APIAsyncAttachment } from "~types/entities/async_attachment";
|
||||||
import type { APIAttachment } from "~types/entities/attachment";
|
import type { APIAttachment } from "~types/entities/attachment";
|
||||||
|
import type * as Lysand from "lysand-types";
|
||||||
|
|
||||||
export const attachmentToAPI = (
|
export const attachmentToAPI = (
|
||||||
attachment: Attachment,
|
attachment: Attachment,
|
||||||
|
|
@ -57,6 +58,28 @@ export const attachmentToAPI = (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const attachmentToLysand = (
|
||||||
|
attachment: Attachment,
|
||||||
|
): Lysand.ContentFormat => {
|
||||||
|
return {
|
||||||
|
[attachment.mime_type]: {
|
||||||
|
content: attachment.url,
|
||||||
|
blurhash: attachment.blurhash ?? undefined,
|
||||||
|
description: attachment.description ?? undefined,
|
||||||
|
duration: attachment.duration ?? undefined,
|
||||||
|
fps: attachment.fps ?? undefined,
|
||||||
|
height: attachment.height ?? undefined,
|
||||||
|
size: attachment.size ?? undefined,
|
||||||
|
hash: attachment.sha256
|
||||||
|
? {
|
||||||
|
sha256: attachment.sha256,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
width: attachment.width ?? undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const getUrl = (name: string, config: Config) => {
|
export const getUrl = (name: string, config: Config) => {
|
||||||
if (config.media.backend === MediaBackendType.LOCAL) {
|
if (config.media.backend === MediaBackendType.LOCAL) {
|
||||||
return new URL(`/media/${name}`, config.http.base_url).toString();
|
return new URL(`/media/${name}`, config.http.base_url).toString();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Emoji } from "@prisma/client";
|
import type { Emoji } from "@prisma/client";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
import type { APIEmoji } from "~types/entities/emoji";
|
import type { APIEmoji } from "~types/entities/emoji";
|
||||||
import type { Emoji as LysandEmoji } from "~types/lysand/extensions/org.lysand/custom_emojis";
|
import type * as Lysand from "lysand-types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an emoji entity in the database.
|
* Represents an emoji entity in the database.
|
||||||
|
|
@ -29,7 +29,7 @@ export const parseEmojis = async (text: string): Promise<Emoji[]> => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addEmojiIfNotExists = async (emoji: LysandEmoji) => {
|
export const addEmojiIfNotExists = async (emoji: Lysand.Emoji) => {
|
||||||
const existingEmoji = await client.emoji.findFirst({
|
const existingEmoji = await client.emoji.findFirst({
|
||||||
where: {
|
where: {
|
||||||
shortcode: emoji.name,
|
shortcode: emoji.name,
|
||||||
|
|
@ -43,8 +43,8 @@ export const addEmojiIfNotExists = async (emoji: LysandEmoji) => {
|
||||||
data: {
|
data: {
|
||||||
shortcode: emoji.name,
|
shortcode: emoji.name,
|
||||||
url: emoji.url[0].content,
|
url: emoji.url[0].content,
|
||||||
alt: emoji.alt || null,
|
alt: emoji.alt || emoji.url[0].description || undefined,
|
||||||
content_type: emoji.url[0].content_type,
|
content_type: Object.keys(emoji.url)[0],
|
||||||
visible_in_picker: true,
|
visible_in_picker: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -64,34 +64,15 @@ export const emojiToAPI = (emoji: Emoji): APIEmoji => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const emojiToLysand = (emoji: Emoji): LysandEmoji => {
|
export const emojiToLysand = (emoji: Emoji): Lysand.Emoji => {
|
||||||
return {
|
return {
|
||||||
name: emoji.shortcode,
|
name: emoji.shortcode,
|
||||||
url: [
|
url: {
|
||||||
{
|
[emoji.content_type]: {
|
||||||
content: emoji.url,
|
content: emoji.url,
|
||||||
content_type: emoji.content_type,
|
description: emoji.alt || undefined,
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
alt: emoji.alt || undefined,
|
alt: emoji.alt || undefined,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the emoji to an ActivityPub object.
|
|
||||||
* @returns The ActivityPub object.
|
|
||||||
*/
|
|
||||||
export const emojiToActivityPub = (emoji: Emoji): object => {
|
|
||||||
// replace any with your ActivityPub Emoji type
|
|
||||||
return {
|
|
||||||
type: "Emoji",
|
|
||||||
name: `:${emoji.shortcode}:`,
|
|
||||||
updated: new Date().toISOString(),
|
|
||||||
icon: {
|
|
||||||
type: "Image",
|
|
||||||
url: emoji.url,
|
|
||||||
mediaType: emoji.content_type,
|
|
||||||
alt: emoji.alt || undefined,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import type { Like } from "@prisma/client";
|
import type { Like } from "@prisma/client";
|
||||||
import { config } from "config-manager";
|
import { config } from "config-manager";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
import type { Like as LysandLike } from "~types/lysand/Object";
|
|
||||||
import type { StatusWithRelations } from "./Status";
|
import type { StatusWithRelations } from "./Status";
|
||||||
import type { UserWithRelations } from "./User";
|
import type { UserWithRelations } from "./User";
|
||||||
|
import type * as Lysand from "lysand-types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a Like entity in the database.
|
* Represents a Like entity in the database.
|
||||||
*/
|
*/
|
||||||
export const toLysand = (like: Like): LysandLike => {
|
export const toLysand = (like: Like): Lysand.Like => {
|
||||||
return {
|
return {
|
||||||
id: like.id,
|
id: like.id,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: to be rewritten
|
// biome-ignore lint/suspicious/noExplicitAny: to be rewritten
|
||||||
|
|
@ -17,7 +17,10 @@ export const toLysand = (like: Like): LysandLike => {
|
||||||
created_at: new Date(like.createdAt).toISOString(),
|
created_at: new Date(like.createdAt).toISOString(),
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: to be rewritten
|
// biome-ignore lint/suspicious/noExplicitAny: to be rewritten
|
||||||
object: (like as any).liked?.uri,
|
object: (like as any).liked?.uri,
|
||||||
uri: new URL(`/actions/${like.id}`, config.http.base_url).toString(),
|
uri: new URL(
|
||||||
|
`/objects/like/${like.id}`,
|
||||||
|
config.http.base_url,
|
||||||
|
).toString(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ import { client } from "~database/datasource";
|
||||||
import type { APIAttachment } from "~types/entities/attachment";
|
import type { APIAttachment } from "~types/entities/attachment";
|
||||||
import type { APIStatus } from "~types/entities/status";
|
import type { APIStatus } from "~types/entities/status";
|
||||||
import type { LysandPublication, Note } from "~types/lysand/Object";
|
import type { LysandPublication, Note } from "~types/lysand/Object";
|
||||||
|
import type * as Lysand from "lysand-types";
|
||||||
import { applicationToAPI } from "./Application";
|
import { applicationToAPI } from "./Application";
|
||||||
import { attachmentToAPI } from "./Attachment";
|
import { attachmentToAPI, attachmentToLysand } from "./Attachment";
|
||||||
import { emojiToAPI, emojiToLysand, parseEmojis } from "./Emoji";
|
import { emojiToAPI, emojiToLysand, parseEmojis } from "./Emoji";
|
||||||
import type { UserWithRelations } from "./User";
|
import type { UserWithRelations } from "./User";
|
||||||
import { fetchRemoteUser, parseMentionsUris, userToAPI } from "./User";
|
import { fetchRemoteUser, parseMentionsUris, userToAPI } from "./User";
|
||||||
|
|
@ -533,78 +534,33 @@ export const statusToAPI = async (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* export const statusToActivityPub = async (
|
export const statusToLysand = (status: StatusWithRelations): Lysand.Note => {
|
||||||
status: StatusWithRelations
|
|
||||||
// user?: UserWithRelations
|
|
||||||
): Promise<any> => {
|
|
||||||
// replace any with your ActivityPub type
|
|
||||||
return {
|
|
||||||
"@context": [
|
|
||||||
"https://www.w3.org/ns/activitystreams",
|
|
||||||
"https://mastodon.social/schemas/litepub-0.1.jsonld",
|
|
||||||
],
|
|
||||||
id: `${config.http.base_url}/users/${status.authorId}/statuses/${status.id}`,
|
|
||||||
type: "Note",
|
|
||||||
summary: status.spoilerText,
|
|
||||||
content: status.content,
|
|
||||||
published: new Date(status.createdAt).toISOString(),
|
|
||||||
url: `${config.http.base_url}/users/${status.authorId}/statuses/${status.id}`,
|
|
||||||
attributedTo: `${config.http.base_url}/users/${status.authorId}`,
|
|
||||||
to: ["https://www.w3.org/ns/activitystreams#Public"],
|
|
||||||
cc: [], // add recipients here
|
|
||||||
sensitive: status.sensitive,
|
|
||||||
attachment: (status.attachments ?? []).map(
|
|
||||||
a => attachmentToActivityPub(a) as ActivityPubAttachment // replace with your function
|
|
||||||
),
|
|
||||||
tag: [], // add tags here
|
|
||||||
replies: {
|
|
||||||
id: `${config.http.base_url}/users/${status.authorId}/statuses/${status.id}/replies`,
|
|
||||||
type: "Collection",
|
|
||||||
totalItems: status._count.replies,
|
|
||||||
},
|
|
||||||
likes: {
|
|
||||||
id: `${config.http.base_url}/users/${status.authorId}/statuses/${status.id}/likes`,
|
|
||||||
type: "Collection",
|
|
||||||
totalItems: status._count.likes,
|
|
||||||
},
|
|
||||||
shares: {
|
|
||||||
id: `${config.http.base_url}/users/${status.authorId}/statuses/${status.id}/shares`,
|
|
||||||
type: "Collection",
|
|
||||||
totalItems: status._count.reblogs,
|
|
||||||
},
|
|
||||||
inReplyTo: status.inReplyToPostId
|
|
||||||
? `${config.http.base_url}/users/${status.inReplyToPost?.authorId}/statuses/${status.inReplyToPostId}`
|
|
||||||
: null,
|
|
||||||
visibility: "public", // adjust as needed
|
|
||||||
// add more fields as needed
|
|
||||||
};
|
|
||||||
}; */
|
|
||||||
|
|
||||||
export const statusToLysand = (status: StatusWithRelations): Note => {
|
|
||||||
return {
|
return {
|
||||||
type: "Note",
|
type: "Note",
|
||||||
created_at: new Date(status.createdAt).toISOString(),
|
created_at: new Date(status.createdAt).toISOString(),
|
||||||
id: status.id,
|
id: status.id,
|
||||||
author: status.authorId,
|
author: status.authorId,
|
||||||
uri: new URL(`/statuses/${status.id}`, config.http.base_url).toString(),
|
uri: new URL(
|
||||||
contents: [
|
`/objects/note/${status.id}`,
|
||||||
{
|
config.http.base_url,
|
||||||
|
).toString(),
|
||||||
|
content: {
|
||||||
|
"text/html": {
|
||||||
content: status.content,
|
content: status.content,
|
||||||
content_type: "text/html",
|
|
||||||
},
|
},
|
||||||
{
|
"text/plain": {
|
||||||
// Content converted to plaintext
|
|
||||||
content: htmlToText(status.content),
|
content: htmlToText(status.content),
|
||||||
content_type: "text/plain",
|
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
// TODO: Add attachments
|
attachments: status.attachments.map((attachment) =>
|
||||||
attachments: [],
|
attachmentToLysand(attachment),
|
||||||
|
),
|
||||||
is_sensitive: status.sensitive,
|
is_sensitive: status.sensitive,
|
||||||
mentions: status.mentions.map((mention) => mention.uri || ""),
|
mentions: status.mentions.map((mention) => mention.uri || ""),
|
||||||
quotes: status.quotingPost ? [status.quotingPost.uri || ""] : [],
|
quotes: status.quotingPost?.uri ?? undefined,
|
||||||
replies_to: status.inReplyToPostId ? [status.inReplyToPostId] : [],
|
replies_to: status.inReplyToPost?.uri ?? undefined,
|
||||||
subject: status.spoilerText,
|
subject: status.spoilerText,
|
||||||
|
visibility: status.visibility as Lysand.Visibility,
|
||||||
extensions: {
|
extensions: {
|
||||||
"org.lysand:custom_emojis": {
|
"org.lysand:custom_emojis": {
|
||||||
emojis: status.emojis.map((emoji) => emojiToLysand(emoji)),
|
emojis: status.emojis.map((emoji) => emojiToLysand(emoji)),
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,10 @@ import { htmlToText } from "html-to-text";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
import type { APIAccount } from "~types/entities/account";
|
import type { APIAccount } from "~types/entities/account";
|
||||||
import type { APISource } from "~types/entities/source";
|
import type { APISource } from "~types/entities/source";
|
||||||
import type { LysandUser } from "~types/lysand/Object";
|
import type * as Lysand from "lysand-types";
|
||||||
import { addEmojiIfNotExists, emojiToAPI, emojiToLysand } from "./Emoji";
|
import { addEmojiIfNotExists, emojiToAPI, emojiToLysand } from "./Emoji";
|
||||||
import { addInstanceIfNotExists } from "./Instance";
|
import { addInstanceIfNotExists } from "./Instance";
|
||||||
import { userRelations } from "./relations";
|
import { userRelations } from "./relations";
|
||||||
import { getUrl } from "./Attachment";
|
|
||||||
import { createNewRelationship } from "./Relationship";
|
import { createNewRelationship } from "./Relationship";
|
||||||
|
|
||||||
export interface AuthData {
|
export interface AuthData {
|
||||||
|
|
@ -147,7 +146,7 @@ export const fetchRemoteUser = async (uri: string) => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = (await response.json()) as Partial<LysandUser>;
|
const data = (await response.json()) as Partial<Lysand.User>;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!(
|
!(
|
||||||
|
|
@ -155,9 +154,9 @@ export const fetchRemoteUser = async (uri: string) => {
|
||||||
data.username &&
|
data.username &&
|
||||||
data.uri &&
|
data.uri &&
|
||||||
data.created_at &&
|
data.created_at &&
|
||||||
data.disliked &&
|
data.dislikes &&
|
||||||
data.featured &&
|
data.featured &&
|
||||||
data.liked &&
|
data.likes &&
|
||||||
data.followers &&
|
data.followers &&
|
||||||
data.following &&
|
data.following &&
|
||||||
data.inbox &&
|
data.inbox &&
|
||||||
|
|
@ -178,9 +177,9 @@ export const fetchRemoteUser = async (uri: string) => {
|
||||||
uri: data.uri,
|
uri: data.uri,
|
||||||
createdAt: new Date(data.created_at),
|
createdAt: new Date(data.created_at),
|
||||||
endpoints: {
|
endpoints: {
|
||||||
disliked: data.disliked,
|
dislikes: data.dislikes,
|
||||||
featured: data.featured,
|
featured: data.featured,
|
||||||
liked: data.liked,
|
likes: data.likes,
|
||||||
followers: data.followers,
|
followers: data.followers,
|
||||||
following: data.following,
|
following: data.following,
|
||||||
inbox: data.inbox,
|
inbox: data.inbox,
|
||||||
|
|
@ -444,7 +443,7 @@ export const userToAPI = (
|
||||||
/**
|
/**
|
||||||
* Should only return local users
|
* Should only return local users
|
||||||
*/
|
*/
|
||||||
export const userToLysand = (user: UserWithRelations): LysandUser => {
|
export const userToLysand = (user: UserWithRelations): Lysand.User => {
|
||||||
if (user.instanceId !== null) {
|
if (user.instanceId !== null) {
|
||||||
throw new Error("Cannot convert remote user to Lysand format");
|
throw new Error("Cannot convert remote user to Lysand format");
|
||||||
}
|
}
|
||||||
|
|
@ -452,29 +451,28 @@ export const userToLysand = (user: UserWithRelations): LysandUser => {
|
||||||
return {
|
return {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
type: "User",
|
type: "User",
|
||||||
uri: user.uri || "",
|
uri:
|
||||||
bio: [
|
user.uri ||
|
||||||
{
|
new URL(`/users/${user.id}`, config.http.base_url).toString(),
|
||||||
|
bio: {
|
||||||
|
"text/html": {
|
||||||
content: user.note,
|
content: user.note,
|
||||||
content_type: "text/html",
|
|
||||||
},
|
},
|
||||||
{
|
"text/plain": {
|
||||||
content: htmlToText(user.note),
|
content: htmlToText(user.note),
|
||||||
content_type: "text/plain",
|
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
created_at: new Date(user.createdAt).toISOString(),
|
created_at: new Date(user.createdAt).toISOString(),
|
||||||
|
dislikes: new URL(
|
||||||
disliked: new URL(
|
`/users/${user.id}/dislikes`,
|
||||||
`/users/${user.id}/disliked`,
|
|
||||||
config.http.base_url,
|
config.http.base_url,
|
||||||
).toString(),
|
).toString(),
|
||||||
featured: new URL(
|
featured: new URL(
|
||||||
`/users/${user.id}/featured`,
|
`/users/${user.id}/featured`,
|
||||||
config.http.base_url,
|
config.http.base_url,
|
||||||
).toString(),
|
).toString(),
|
||||||
liked: new URL(
|
likes: new URL(
|
||||||
`/users/${user.id}/liked`,
|
`/users/${user.id}/likes`,
|
||||||
config.http.base_url,
|
config.http.base_url,
|
||||||
).toString(),
|
).toString(),
|
||||||
followers: new URL(
|
followers: new URL(
|
||||||
|
|
@ -495,40 +493,35 @@ export const userToLysand = (user: UserWithRelations): LysandUser => {
|
||||||
).toString(),
|
).toString(),
|
||||||
indexable: false,
|
indexable: false,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
avatar: [
|
avatar: {
|
||||||
{
|
[user.avatar.split(".")[1]]: {
|
||||||
content: getAvatarUrl(user, config) || "",
|
content: getAvatarUrl(user, config),
|
||||||
content_type: `image/${user.avatar.split(".")[1]}`,
|
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
header: [
|
header: {
|
||||||
{
|
[user.header.split(".")[1]]: {
|
||||||
content: getHeaderUrl(user, config) || "",
|
content: getHeaderUrl(user, config),
|
||||||
content_type: `image/${user.header.split(".")[1]}`,
|
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
display_name: user.displayName,
|
display_name: user.displayName,
|
||||||
|
|
||||||
fields: (user.source as APISource).fields.map((field) => ({
|
fields: (user.source as APISource).fields.map((field) => ({
|
||||||
key: [
|
key: {
|
||||||
{
|
"text/html": {
|
||||||
content: field.name,
|
content: field.name,
|
||||||
content_type: "text/html",
|
|
||||||
},
|
},
|
||||||
{
|
"text/plain": {
|
||||||
content: htmlToText(field.name),
|
content: htmlToText(field.name),
|
||||||
content_type: "text/plain",
|
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
value: [
|
value: {
|
||||||
{
|
"text/html": {
|
||||||
content: field.value,
|
content: field.value,
|
||||||
content_type: "text/html",
|
|
||||||
},
|
},
|
||||||
{
|
"text/plain": {
|
||||||
content: htmlToText(field.value),
|
content: htmlToText(field.value),
|
||||||
content_type: "text/plain",
|
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
})),
|
})),
|
||||||
public_key: {
|
public_key: {
|
||||||
actor: new URL(
|
actor: new URL(
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,19 @@ export interface Entity {
|
||||||
created_at: string;
|
created_at: string;
|
||||||
uri: string;
|
uri: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
extensions?: {
|
||||||
|
"org.lysand:custom_emojis"?: {
|
||||||
|
emojis: Emoji[];
|
||||||
|
};
|
||||||
|
[key: string]: object | undefined;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Publication {
|
export interface InlineCustomEmojis {
|
||||||
|
[key: string]: Emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Publication extends Entity {
|
||||||
type: "Note" | "Patch";
|
type: "Note" | "Patch";
|
||||||
author: string;
|
author: string;
|
||||||
content?: ContentFormat;
|
content?: ContentFormat;
|
||||||
|
|
@ -57,6 +67,19 @@ export interface Publication {
|
||||||
subject?: string;
|
subject?: string;
|
||||||
is_sensitive?: boolean;
|
is_sensitive?: boolean;
|
||||||
visibility: Visibility;
|
visibility: Visibility;
|
||||||
|
extensions?: Entity["extensions"] & {
|
||||||
|
"org.lysand:reactions"?: {
|
||||||
|
reactions: string;
|
||||||
|
};
|
||||||
|
"org.lysand:polls"?: {
|
||||||
|
poll: {
|
||||||
|
options: ContentFormat[];
|
||||||
|
votes: number[];
|
||||||
|
multiple_choice?: boolean;
|
||||||
|
expires_at: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Visibility {
|
export enum Visibility {
|
||||||
|
|
@ -96,6 +119,9 @@ export interface User extends Entity {
|
||||||
dislikes: string;
|
dislikes: string;
|
||||||
inbox: string;
|
inbox: string;
|
||||||
outbox: string;
|
outbox: string;
|
||||||
|
extensions?: Entity["extensions"] & {
|
||||||
|
"org.lysand:vanity"?: VanityExtension;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Field {
|
export interface Field {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue