diff --git a/api/api/v1/accounts/update_credentials/index.ts b/api/api/v1/accounts/update_credentials/index.ts index 34ab21c0..496c0ae9 100644 --- a/api/api/v1/accounts/update_credentials/index.ts +++ b/api/api/v1/accounts/update_credentials/index.ts @@ -5,7 +5,6 @@ import { Account as AccountSchema, zBoolean } from "@versia/client/schemas"; import { RolePermission } from "@versia/client/schemas"; import { Emoji, Media, User } from "@versia/kit/db"; import { Users } from "@versia/kit/tables"; -import * as VersiaEntities from "@versia/sdk/entities"; import { and, eq, isNull } from "drizzle-orm"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; @@ -14,6 +13,7 @@ import { ApiError } from "~/classes/errors/api-error"; import { contentToHtml } from "~/classes/functions/status"; import { config } from "~/config.ts"; import { rateLimit } from "~/middlewares/rate-limit"; +import * as VersiaEntities from "~/packages/sdk/entities"; export default apiRoute((app) => app.patch( diff --git a/api/api/v1/statuses/[id]/index.ts b/api/api/v1/statuses/[id]/index.ts index 229a1b2c..52d65441 100644 --- a/api/api/v1/statuses/[id]/index.ts +++ b/api/api/v1/statuses/[id]/index.ts @@ -15,13 +15,13 @@ import { } from "@versia/client/schemas"; import { RolePermission } from "@versia/client/schemas"; import { Emoji, Media } from "@versia/kit/db"; -import * as VersiaEntities from "@versia/sdk/entities"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; import { z } from "zod"; import { ApiError } from "~/classes/errors/api-error"; import { contentToHtml, parseTextMentions } from "~/classes/functions/status"; import { config } from "~/config.ts"; +import * as VersiaEntities from "~/packages/sdk/entities"; const schema = z .object({ diff --git a/api/api/v1/statuses/index.ts b/api/api/v1/statuses/index.ts index 8669df4a..0c6c0dc5 100644 --- a/api/api/v1/statuses/index.ts +++ b/api/api/v1/statuses/index.ts @@ -9,7 +9,6 @@ import { } from "@versia/client/schemas"; import { RolePermission } from "@versia/client/schemas"; import { Emoji, Media, Note } from "@versia/kit/db"; -import * as VersiaEntities from "@versia/sdk/entities"; import { randomUUIDv7 } from "bun"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; @@ -17,6 +16,7 @@ import { z } from "zod"; import { ApiError } from "~/classes/errors/api-error"; import { contentToHtml, parseTextMentions } from "~/classes/functions/status"; import { config } from "~/config.ts"; +import * as VersiaEntities from "~/packages/sdk/entities"; const schema = z .object({ diff --git a/api/likes/[uuid]/index.ts b/api/likes/[uuid]/index.ts index 2527f6bf..82871d25 100644 --- a/api/likes/[uuid]/index.ts +++ b/api/likes/[uuid]/index.ts @@ -2,13 +2,13 @@ import { apiRoute, handleZodError } from "@/api"; import { Status as StatusSchema } from "@versia/client/schemas"; import { Like, User } from "@versia/kit/db"; import { Likes } from "@versia/kit/tables"; -import { LikeSchema } from "@versia/sdk/schemas"; import { and, eq, sql } from "drizzle-orm"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; import { z } from "zod"; import { ApiError } from "~/classes/errors/api-error"; import { config } from "~/config.ts"; +import { LikeSchema } from "~/packages/sdk/schemas"; export default apiRoute((app) => app.get( diff --git a/api/notes/[uuid]/index.ts b/api/notes/[uuid]/index.ts index c680fc70..2057abda 100644 --- a/api/notes/[uuid]/index.ts +++ b/api/notes/[uuid]/index.ts @@ -2,13 +2,13 @@ import { apiRoute, handleZodError } from "@/api"; import { Status as StatusSchema } from "@versia/client/schemas"; import { Note } from "@versia/kit/db"; import { Notes } from "@versia/kit/tables"; -import { NoteSchema } from "@versia/sdk/schemas"; import { and, eq, inArray } from "drizzle-orm"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; import { z } from "zod"; import { ApiError } from "~/classes/errors/api-error"; import { config } from "~/config.ts"; +import { NoteSchema } from "~/packages/sdk/schemas"; export default apiRoute((app) => app.get( diff --git a/api/notes/[uuid]/quotes.ts b/api/notes/[uuid]/quotes.ts index cd896e51..b9de0f7c 100644 --- a/api/notes/[uuid]/quotes.ts +++ b/api/notes/[uuid]/quotes.ts @@ -2,14 +2,14 @@ import { apiRoute, handleZodError } from "@/api"; import { Status as StatusSchema } from "@versia/client/schemas"; import { Note, db } from "@versia/kit/db"; import { Notes } from "@versia/kit/tables"; -import * as VersiaEntities from "@versia/sdk/entities"; -import { URICollectionSchema } from "@versia/sdk/schemas"; import { and, eq, inArray } from "drizzle-orm"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; import { z } from "zod"; import { ApiError } from "~/classes/errors/api-error"; import { config } from "~/config.ts"; +import * as VersiaEntities from "~/packages/sdk/entities"; +import { URICollectionSchema } from "~/packages/sdk/schemas"; export default apiRoute((app) => app.get( @@ -94,7 +94,9 @@ export default apiRoute((app) => last: replyCount > limit ? new URL( - `/notes/${note.id}/quotes?offset=${replyCount - limit}`, + `/notes/${note.id}/quotes?offset=${ + replyCount - limit + }`, config.http.base_url, ) : new URL( @@ -104,14 +106,18 @@ export default apiRoute((app) => next: offset + limit < replyCount ? new URL( - `/notes/${note.id}/quotes?offset=${offset + limit}`, + `/notes/${note.id}/quotes?offset=${ + offset + limit + }`, config.http.base_url, ) : null, previous: offset - limit >= 0 ? new URL( - `/notes/${note.id}/quotes?offset=${offset - limit}`, + `/notes/${note.id}/quotes?offset=${ + offset - limit + }`, config.http.base_url, ) : null, diff --git a/api/notes/[uuid]/replies.ts b/api/notes/[uuid]/replies.ts index f2243ed5..2bdd377e 100644 --- a/api/notes/[uuid]/replies.ts +++ b/api/notes/[uuid]/replies.ts @@ -2,14 +2,14 @@ import { apiRoute, handleZodError } from "@/api"; import { Status as StatusSchema } from "@versia/client/schemas"; import { Note, db } from "@versia/kit/db"; import { Notes } from "@versia/kit/tables"; -import * as VersiaEntities from "@versia/sdk/entities"; -import { URICollectionSchema } from "@versia/sdk/schemas"; import { and, eq, inArray } from "drizzle-orm"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; import { z } from "zod"; import { ApiError } from "~/classes/errors/api-error"; import { config } from "~/config.ts"; +import * as VersiaEntities from "~/packages/sdk/entities"; +import { URICollectionSchema } from "~/packages/sdk/schemas"; export default apiRoute((app) => app.get( @@ -92,7 +92,9 @@ export default apiRoute((app) => last: replyCount > limit ? new URL( - `/notes/${note.id}/replies?offset=${replyCount - limit}`, + `/notes/${note.id}/replies?offset=${ + replyCount - limit + }`, config.http.base_url, ) : new URL( @@ -102,14 +104,18 @@ export default apiRoute((app) => next: offset + limit < replyCount ? new URL( - `/notes/${note.id}/replies?offset=${offset + limit}`, + `/notes/${note.id}/replies?offset=${ + offset + limit + }`, config.http.base_url, ) : null, previous: offset - limit >= 0 ? new URL( - `/notes/${note.id}/replies?offset=${offset - limit}`, + `/notes/${note.id}/replies?offset=${ + offset - limit + }`, config.http.base_url, ) : null, diff --git a/api/users/[uuid]/inbox/index.ts b/api/users/[uuid]/inbox/index.ts index ba1583ad..4becb342 100644 --- a/api/users/[uuid]/inbox/index.ts +++ b/api/users/[uuid]/inbox/index.ts @@ -4,7 +4,7 @@ import { resolver, validator } from "hono-openapi/zod"; import { z } from "zod"; import { ApiError } from "~/classes/errors/api-error"; import { InboxJobType, inboxQueue } from "~/classes/queues/inbox"; -import type { JSONObject } from "~/packages/federation/types"; +import type { JSONObject } from "~/packages/sdk/types"; export default apiRoute((app) => app.post( diff --git a/api/users/[uuid]/index.ts b/api/users/[uuid]/index.ts index 63182daf..a03d9eb4 100644 --- a/api/users/[uuid]/index.ts +++ b/api/users/[uuid]/index.ts @@ -1,10 +1,10 @@ import { apiRoute, handleZodError } from "@/api"; import { User } from "@versia/kit/db"; -import { UserSchema } from "@versia/sdk/schemas"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; import { z } from "zod"; import { ApiError } from "~/classes/errors/api-error"; +import { UserSchema } from "~/packages/sdk/schemas"; export default apiRoute((app) => app.get( diff --git a/api/users/[uuid]/outbox/index.ts b/api/users/[uuid]/outbox/index.ts index a72e31ca..1eb452dd 100644 --- a/api/users/[uuid]/outbox/index.ts +++ b/api/users/[uuid]/outbox/index.ts @@ -1,14 +1,14 @@ import { apiRoute, handleZodError } from "@/api"; import { Note, User, db } from "@versia/kit/db"; import { Notes } from "@versia/kit/tables"; -import * as VersiaEntities from "@versia/sdk/entities"; -import { CollectionSchema, NoteSchema } from "@versia/sdk/schemas"; import { and, eq, inArray } from "drizzle-orm"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; import { z } from "zod"; import { ApiError } from "~/classes/errors/api-error"; import { config } from "~/config.ts"; +import * as VersiaEntities from "~/packages/sdk/entities"; +import { CollectionSchema, NoteSchema } from "~/packages/sdk/schemas"; const NOTES_PER_PAGE = 20; diff --git a/api/well-known/versia.ts b/api/well-known/versia.ts index a325b486..a36cd128 100644 --- a/api/well-known/versia.ts +++ b/api/well-known/versia.ts @@ -2,12 +2,12 @@ import { apiRoute } from "@/api"; import { urlToContentFormat } from "@/content_types"; import { User } from "@versia/kit/db"; import { Users } from "@versia/kit/tables"; -import { InstanceMetadataSchema } from "@versia/sdk/schemas"; import { asc } from "drizzle-orm"; import { describeRoute } from "hono-openapi"; import { resolver } from "hono-openapi/zod"; import { config } from "~/config.ts"; import pkg from "~/package.json"; +import { InstanceMetadataSchema } from "~/packages/sdk/schemas"; export default apiRoute((app) => app.get( diff --git a/api/well-known/webfinger/index.ts b/api/well-known/webfinger/index.ts index c788c83f..60da40a4 100644 --- a/api/well-known/webfinger/index.ts +++ b/api/well-known/webfinger/index.ts @@ -8,13 +8,13 @@ import { import { getLogger } from "@logtape/logtape"; import { User } from "@versia/kit/db"; import { Users } from "@versia/kit/tables"; -import { WebFingerSchema } from "@versia/sdk/schemas"; import { and, eq, isNull } from "drizzle-orm"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; import { z } from "zod"; import { ApiError } from "~/classes/errors/api-error"; import { config } from "~/config.ts"; +import { WebFingerSchema } from "~/packages/sdk/schemas"; export default apiRoute((app) => app.get( @@ -101,7 +101,9 @@ export default apiRoute((app) => return context.json( { - subject: `acct:${isUuid ? user.id : user.data.username}@${host}`, + subject: `acct:${ + isUuid ? user.id : user.data.username + }@${host}`, links: [ // Keep the ActivityPub link first, because Misskey only searches diff --git a/classes/database/emoji.ts b/classes/database/emoji.ts index 5267f37c..b7e2c857 100644 --- a/classes/database/emoji.ts +++ b/classes/database/emoji.ts @@ -2,8 +2,6 @@ import { emojiValidatorWithColons, emojiValidatorWithIdentifiers } from "@/api"; import type { CustomEmoji } from "@versia/client/schemas"; import { type Instance, Media, db } from "@versia/kit/db"; import { Emojis, type Instances, type Medias } from "@versia/kit/tables"; -import * as VersiaEntities from "@versia/sdk/entities"; -import type { ImageContentFormatSchema } from "@versia/sdk/schemas"; import { randomUUIDv7 } from "bun"; import { type InferInsertModel, @@ -16,6 +14,8 @@ import { isNull, } from "drizzle-orm"; import type { z } from "zod"; +import * as VersiaEntities from "~/packages/sdk/entities/index.ts"; +import type { ImageContentFormatSchema } from "~/packages/sdk/schemas/index.ts"; import { BaseInterface } from "./base.ts"; type EmojiType = InferSelectModel & { diff --git a/classes/database/instance.ts b/classes/database/instance.ts index eaf8987b..1cd26abe 100644 --- a/classes/database/instance.ts +++ b/classes/database/instance.ts @@ -1,7 +1,6 @@ import { getLogger } from "@logtape/logtape"; import { db } from "@versia/kit/db"; import { Instances } from "@versia/kit/tables"; -import * as VersiaEntities from "@versia/sdk/entities"; import { randomUUIDv7 } from "bun"; import chalk from "chalk"; import { @@ -13,6 +12,7 @@ import { inArray, } from "drizzle-orm"; import { config } from "~/config.ts"; +import * as VersiaEntities from "~/packages/sdk/entities/index.ts"; import { ApiError } from "../errors/api-error.ts"; import { BaseInterface } from "./base.ts"; import { User } from "./user.ts"; @@ -319,7 +319,9 @@ export class Instance extends BaseInterface { ); if (!output) { - logger.error`Failed to update instance ${chalk.bold(this.data.baseUrl)}`; + logger.error`Failed to update instance ${chalk.bold( + this.data.baseUrl, + )}`; throw new Error("Failed to update instance"); } diff --git a/classes/database/like.ts b/classes/database/like.ts index dc0808c3..e681eb61 100644 --- a/classes/database/like.ts +++ b/classes/database/like.ts @@ -5,7 +5,6 @@ import { Notifications, type Users, } from "@versia/kit/tables"; -import * as VersiaEntities from "@versia/sdk/entities"; import { type InferInsertModel, type InferSelectModel, @@ -16,6 +15,7 @@ import { inArray, } from "drizzle-orm"; import { config } from "~/config.ts"; +import * as VersiaEntities from "~/packages/sdk/entities/index.ts"; import { BaseInterface } from "./base.ts"; import { User } from "./user.ts"; diff --git a/classes/database/media.ts b/classes/database/media.ts index c28258b4..9bce13f9 100644 --- a/classes/database/media.ts +++ b/classes/database/media.ts @@ -3,11 +3,6 @@ import { mimeLookup } from "@/content_types.ts"; import type { Attachment as AttachmentSchema } from "@versia/client/schemas"; import { db } from "@versia/kit/db"; import { Medias } from "@versia/kit/tables"; -import * as VersiaEntities from "@versia/sdk/entities"; -import type { - ContentFormatSchema, - ImageContentFormatSchema, -} from "@versia/sdk/schemas"; import { S3Client, SHA256, randomUUIDv7, write } from "bun"; import { type InferInsertModel, @@ -21,6 +16,11 @@ import sharp from "sharp"; import type { z } from "zod"; import { MediaBackendType } from "~/classes/config/schema.ts"; import { config } from "~/config.ts"; +import * as VersiaEntities from "~/packages/sdk/entities/index.ts"; +import type { + ContentFormatSchema, + ImageContentFormatSchema, +} from "~/packages/sdk/schemas/index.ts"; import { ApiError } from "../errors/api-error.ts"; import { getMediaHash } from "../media/media-hasher.ts"; import { ProxiableUrl } from "../media/url.ts"; @@ -278,7 +278,9 @@ export class Media extends BaseInterface { throw new ApiError( 415, `File type ${file.type} is not allowed`, - `Allowed types: ${config.validation.media.allowed_mime_types.join(", ")}`, + `Allowed types: ${config.validation.media.allowed_mime_types.join( + ", ", + )}`, ); } } diff --git a/classes/database/note.ts b/classes/database/note.ts index 1aff1277..402df3f0 100644 --- a/classes/database/note.ts +++ b/classes/database/note.ts @@ -10,7 +10,6 @@ import { Notes, Users, } from "@versia/kit/tables"; -import * as VersiaEntities from "@versia/sdk/entities"; import { randomUUIDv7 } from "bun"; import { type InferInsertModel, @@ -28,7 +27,8 @@ import { createRegExp, exactly, global } from "magic-regexp"; import type { z } from "zod"; import { contentToHtml, findManyNotes } from "~/classes/functions/status"; import { config } from "~/config.ts"; -import type { NonTextContentFormatSchema } from "~/packages/federation/schemas/contentformat.ts"; +import * as VersiaEntities from "~/packages/sdk/entities/index.ts"; +import type { NonTextContentFormatSchema } from "~/packages/sdk/schemas/contentformat.ts"; import { DeliveryJobType, deliveryQueue } from "../queues/delivery.ts"; import { Application } from "./application.ts"; import { BaseInterface } from "./base.ts"; diff --git a/classes/database/reaction.ts b/classes/database/reaction.ts index 87f01529..491cc3b7 100644 --- a/classes/database/reaction.ts +++ b/classes/database/reaction.ts @@ -1,6 +1,5 @@ import { Emoji, Instance, type Note, User, db } from "@versia/kit/db"; import { type Notes, Reactions, type Users } from "@versia/kit/tables"; -import * as VersiaEntities from "@versia/sdk/entities"; import { randomUUIDv7 } from "bun"; import { type InferInsertModel, @@ -11,6 +10,7 @@ import { inArray, } from "drizzle-orm"; import { config } from "~/config.ts"; +import * as VersiaEntities from "~/packages/sdk/entities/index.ts"; import { BaseInterface } from "./base.ts"; type ReactionType = InferSelectModel & { diff --git a/classes/database/user.ts b/classes/database/user.ts index 0268e3d3..4458936c 100644 --- a/classes/database/user.ts +++ b/classes/database/user.ts @@ -19,10 +19,6 @@ import { UserToPinnedNotes, Users, } from "@versia/kit/tables"; -import { sign } from "@versia/sdk/crypto"; -import * as VersiaEntities from "@versia/sdk/entities"; -import { FederationRequester } from "@versia/sdk/http"; -import type { ImageContentFormatSchema } from "@versia/sdk/schemas"; import { randomUUIDv7 } from "bun"; import { password as bunPassword } from "bun"; import chalk from "chalk"; @@ -45,6 +41,10 @@ import type { z } from "zod"; import { findManyUsers } from "~/classes/functions/user"; import { searchManager } from "~/classes/search/search-manager"; import { config } from "~/config.ts"; +import { sign } from "~/packages/sdk/crypto.ts"; +import * as VersiaEntities from "~/packages/sdk/entities/index.ts"; +import { FederationRequester } from "~/packages/sdk/http.ts"; +import type { ImageContentFormatSchema } from "~/packages/sdk/schemas/index.ts"; import type { HttpVerb, KnownEntity } from "~/types/api.ts"; import { ProxiableUrl } from "../media/url.ts"; import { DeliveryJobType, deliveryQueue } from "../queues/delivery.ts"; @@ -1023,8 +1023,9 @@ export class User extends BaseInterface { entity, ); } catch (e) { - getLogger(["federation", "delivery"]) - .error`Federating ${chalk.gray(entity.data.type)} to ${user.uri} ${chalk.bold.red("failed")}`; + getLogger(["federation", "delivery"]).error`Federating ${chalk.gray( + entity.data.type, + )} to ${user.uri} ${chalk.bold.red("failed")}`; getLogger(["federation", "delivery"]).error`${e}`; sentry?.captureException(e); diff --git a/classes/functions/status.ts b/classes/functions/status.ts index 97eba1e7..3992df86 100644 --- a/classes/functions/status.ts +++ b/classes/functions/status.ts @@ -3,7 +3,6 @@ import { sanitizeHtml, sanitizeHtmlInline } from "@/sanitization"; import markdownItTaskLists from "@hackmd/markdown-it-task-lists"; import { type Note, User, db } from "@versia/kit/db"; import { Instances, Users } from "@versia/kit/tables"; -import type * as VersiaEntities from "@versia/sdk/entities"; import { and, eq, inArray, isNull, or, sql } from "drizzle-orm"; import linkifyHtml from "linkify-html"; import { @@ -19,6 +18,7 @@ import MarkdownIt from "markdown-it"; import markdownItContainer from "markdown-it-container"; import markdownItTocDoneRight from "markdown-it-toc-done-right"; import { config } from "~/config.ts"; +import type * as VersiaEntities from "~/packages/sdk/entities/index.ts"; import { transformOutputToUserWithRelations, userExtrasTemplate, diff --git a/classes/inbox/processor.ts b/classes/inbox/processor.ts index 7f74da3c..44bfb815 100644 --- a/classes/inbox/processor.ts +++ b/classes/inbox/processor.ts @@ -2,9 +2,6 @@ import { sentry } from "@/sentry"; import { type Logger, getLogger } from "@logtape/logtape"; import { type Instance, Like, Note, Relationship, User } from "@versia/kit/db"; import { Likes, Notes } from "@versia/kit/tables"; -import { EntitySorter } from "@versia/sdk"; -import { verify } from "@versia/sdk/crypto"; -import * as VersiaEntities from "@versia/sdk/entities"; import type { SocketAddress } from "bun"; import { Glob } from "bun"; import chalk from "chalk"; @@ -12,7 +9,10 @@ import { eq } from "drizzle-orm"; import { matches } from "ip-matching"; import { isValidationError } from "zod-validation-error"; import { config } from "~/config.ts"; -import type { JSONObject } from "~/packages/federation/types.ts"; +import { verify } from "~/packages/sdk/crypto.ts"; +import * as VersiaEntities from "~/packages/sdk/entities/index.ts"; +import { EntitySorter } from "~/packages/sdk/inbox-processor.ts"; +import type { JSONObject } from "~/packages/sdk/types.ts"; import { ApiError } from "../errors/api-error.ts"; /** diff --git a/classes/queues/delivery.ts b/classes/queues/delivery.ts index e8cbc6b0..d8605649 100644 --- a/classes/queues/delivery.ts +++ b/classes/queues/delivery.ts @@ -1,10 +1,10 @@ import { User } from "@versia/kit/db"; -import * as VersiaEntities from "@versia/sdk/entities"; import { Queue } from "bullmq"; import { Worker } from "bullmq"; import chalk from "chalk"; import { config } from "~/config.ts"; -import type { JSONObject } from "~/packages/federation/types"; +import * as VersiaEntities from "~/packages/sdk/entities"; +import type { JSONObject } from "~/packages/sdk/types"; import { connection } from "~/utils/redis.ts"; export enum DeliveryJobType { @@ -40,7 +40,9 @@ export const getDeliveryWorker = (): Worker< if (!sender) { throw new Error( - `Could not resolve sender ID ${chalk.gray(senderId)}`, + `Could not resolve sender ID ${chalk.gray( + senderId, + )}`, ); } @@ -48,12 +50,16 @@ export const getDeliveryWorker = (): Worker< if (!recipient) { throw new Error( - `Could not resolve recipient ID ${chalk.gray(recipientId)}`, + `Could not resolve recipient ID ${chalk.gray( + recipientId, + )}`, ); } await job.log( - `Federating entity [${entity.id}] from @${sender.getAcct()} to @${recipient.getAcct()}`, + `Federating entity [${ + entity.id + }] from @${sender.getAcct()} to @${recipient.getAcct()}`, ); const type = entity.type; diff --git a/classes/queues/inbox.ts b/classes/queues/inbox.ts index 2062bb52..31be17ae 100644 --- a/classes/queues/inbox.ts +++ b/classes/queues/inbox.ts @@ -4,7 +4,7 @@ import { Queue } from "bullmq"; import { Worker } from "bullmq"; import type { SocketAddress } from "bun"; import { config } from "~/config.ts"; -import type { JSONObject } from "~/packages/federation/types.ts"; +import type { JSONObject } from "~/packages/sdk/types.ts"; import { connection } from "~/utils/redis.ts"; import { ApiError } from "../errors/api-error.ts"; import { InboxProcessor } from "../inbox/processor.ts"; @@ -182,7 +182,9 @@ export const getInboxWorker = (): Worker => ); await remoteInstance.sendMessage( - `Failed processing entity [${data.uri}] delivered to inbox. Returned error:\n\n${JSON.stringify( + `Failed processing entity [${ + data.uri + }] delivered to inbox. Returned error:\n\n${JSON.stringify( e.message, null, 4, diff --git a/drizzle/schema.ts b/drizzle/schema.ts index 7f2e5174..350fc851 100644 --- a/drizzle/schema.ts +++ b/drizzle/schema.ts @@ -4,13 +4,6 @@ import type { Status as StatusSchema, } from "@versia/client/schemas"; import type { RolePermission } from "@versia/client/schemas"; -import type { - ContentFormatSchema, - ImageContentFormatSchema, - InstanceMetadataSchema, - NonTextContentFormatSchema, - TextContentFormatSchema, -} from "@versia/sdk/schemas"; import type { Challenge } from "altcha-lib/types"; import { relations, sql } from "drizzle-orm"; import { @@ -26,6 +19,13 @@ import { uuid, } from "drizzle-orm/pg-core"; import type { z } from "zod"; +import type { + ContentFormatSchema, + ImageContentFormatSchema, + InstanceMetadataSchema, + NonTextContentFormatSchema, + TextContentFormatSchema, +} from "~/packages/sdk/schemas"; // biome-ignore lint/nursery/useExplicitType: Type is too complex const createdAt = () => diff --git a/packages/sdk/README.md b/packages/sdk/README.md new file mode 100644 index 00000000..2b863508 --- /dev/null +++ b/packages/sdk/README.md @@ -0,0 +1,220 @@ +

+ Versia Logo +

+ +

@versia/sdk

+ +Federation types, validators and cryptography for Versia server implementations. + +## Usage + +## Entities + +The `@versia/sdk/entities` module provides TypeScript classes for working with Versia entities. These classes provide type-safe access to entity properties and methods for serialization/deserialization. + +```ts +import { Note, User } from "@versia/sdk/entities"; + +const note = new Note({ + id: "00000000-0000-0000-0000-000000000000", + type: "Note", +}); + +// You can also parse from JSON, which will apply the schema validation +const invalidJson = { + id: "00000000-0000-0000-0000-000000000000", + invalid: "property", +}; + +// Will throw an error +const invalidNote = await Note.fromJSON(invalidJson); + +const validJson = { + id: "00000000-0000-0000-0000-000000000000", + type: "Note", +}; + +const validNote = await Note.fromJSON(validJson); +``` + +Some entities like `Note` have additional properties, like `content` or `attachments`, which are automatically calculated from the relevant properties. + +```ts +import { TextContentFormat, Note } from "@versia/sdk/entities"; + +const note = new Note({ + id: "00000000-0000-0000-0000-000000000000", + type: "Note", + content: { + "text/plain": { + content: "Hello, world!", + remote: false, + }, + }, +}); + +const content = note.content; +// Is equivalent to +const content = new TextContentFormat(note.data.content); +``` + +## Schemas + +Additionally, the [**Zod**](https://zod.dev) schemas used for validation are available in the `@versia/sdk/schemas` module. You can use these to directly validate incoming data, without using the entity classes. + +```ts +import { NoteSchema, UserSchema } from "@versia/sdk/schemas"; + +const response = await fetch("https://example.com/notes/123"); +const json = await response.json(); + +const noteSchema = NoteSchema.parse(json); +``` + +## Sorter + +The `@versia/sdk/sorter` module provides a class for inbox request handling. It allows you to automatically sort and process incoming entities based on their type. + +```ts +import { EntitySorter } from "@versia/sdk"; +import { Note, User } from "@versia/sdk/entities"; + +app.post("/inbox", async (req, res) => { + const json = await req.json(); + + const sorter = new EntitySorter(json); + + await sorter + .on(Note, (note) => { + console.log(note); + }) + .on(User, (user) => { + console.log(user); + }) + .sort(); +}); +``` + +## Cryptography + +The `@versia/sdk/crypto` module provides functions for signing and verifying requests using the [**Ed25519**](https://en.wikipedia.org/wiki/EdDSA) algorithm. + +```ts +import { sign, verify } from "@versia/sdk/crypto"; + +const keys = await crypto.subtle.generateKey("Ed25519", true, [ + "sign", + "verify", +]); + +// URI of the User that is signing the request +const authorUrl = new URL("https://example.com"); + +const req = new Request("https://example.com/notes/123", { + method: "POST", + body: JSON.stringify({ + id: "00000000-0000-0000-0000-000000000000", + type: "Note", + }), +}); + +const signedReq = await sign(keys.privateKey, authorUrl, req); + +const verified = await verify(keys.publicKey, signedReq); +``` + +### Prerequisites + +#### For Usage + +See the [**Compatibility**](#compatibility) section for the supported environments. Any package manager can be used to install the packages. + +#### For Development + +- [**Bun**](https://bun.sh) version `1.1.8` or higher. +- Either the [**Linux**](https://www.linux.org) or [**macOS**](https://www.apple.com/macos) operating systems. ([**Windows**](https://www.microsoft.com/windows) will work, but is not officially supported.) + +### Compatibility + +This library is built for JavaScript runtimes with the support for: + +- [**ES Modules**](https://nodejs.org/api/esm.html) +- [**ECMAScript 2020**](https://www.ecma-international.org/ecma-262/11.0/index.html) +- (only required for cryptography) [**Ed25519**](https://en.wikipedia.org/wiki/EdDSA) cryptography in the [**WebCrypto API**](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) + +#### Runtimes + +- **Node.js**: 14.0+ is the minimum (18.0+ for cryptography), but only Node.js 20.0+ (LTS) is officially supported. +- **Deno**: Support is unknown. 1.0+ is expected to work. +- **Bun**: Bun 1.1.8 is the minimum-supported version. As Bun is rapidly evolving, this may change. Previous versions may also work. + +#### Browsers + +Consequently, this library is compatible without any bundling in the following browser versions: + +- **Chrome**: 80+ +- **Edge**: 80+ +- **Firefox**: 74+ +- **Safari**: 13.1+ +- **Opera**: 67+ +- **Internet Explorer**: None + +Cryptography functions are supported in the following browsers: + +- **Safari**: 17.0+ +- **Firefox**: 129.0+ +- **Chrome**: 113.0+ with `#enable-experimental-web-platform-features` enabled + +If you are targeting older browsers, please don't, you are doing yourself a disservice. + +Transpilation to non-ES Module environments is not officially supported, but should be simple with the use of a bundler like [**Parcel**](https://parceljs.org) or [**Rollup**](https://rollupjs.org). + +### Installation + +Package is distributed as a scoped package on the NPM registry and [JSR](https://jsr.io). + +We strongly recommend using JSR over NPM for all your packages that are available on it. + +```bash +# NPM version +deno add npm:@versia/sdk # For Deno +npm install @versia/sdk # For NPM +yarn add @versia/sdk # For Yarn +pnpm add @versia/sdk # For PNPM +bun add @versia/sdk # For Bun + +# JSR version +deno add @versia/sdk # For Deno +npx jsr add @versia/sdk # For JSR +yarn dlx jsr add @versia/sdk # For Yarn +pnpm dlx jsr add @versia/sdk # For PNPM +bunx jsr add @versia/sdk # For Bun +``` + +#### From Source + +If you want to install from source, you can clone [this repository](https://github.com/versia-pub/api) and run the following commands: + +```bash +bun install # Install dependencies + +bun run build # Build the packages +``` + +The built package will be in the `sdk/dist` folder. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## Acknowledgments + +### Projects + +- [**Bun**](https://bun.sh): Thanks to the Bun team for creating an amazing JavaScript runtime. +- [**TypeScript**](https://www.typescriptlang.org): TypeScript is the backbone of this project. +- [**Node.js**](https://nodejs.org): Node.js created the idea of JavaScript on the server. + +### People + +- [**April John**](https://github.com/cutestnekoaqua): Creator and maintainer of the Versia Server ActivityPub bridge. diff --git a/packages/federation/crypto.ts b/packages/sdk/crypto.ts similarity index 71% rename from packages/federation/crypto.ts rename to packages/sdk/crypto.ts index f207af03..541cc4fd 100644 --- a/packages/federation/crypto.ts +++ b/packages/sdk/crypto.ts @@ -9,6 +9,16 @@ const stringToBase64Hash = async (str: string): Promise => { const base64ToArrayBuffer = (base64: string): ArrayBuffer => Uint8Array.fromBase64(base64).buffer as ArrayBuffer; +/** + * Signs a request using the Ed25519 algorithm, according to the [**Versia**](https://versia.pub/signatures) specification. + * + * @see https://versia.pub/signatures + * @param privateKey - Private key of the User that is signing the request. + * @param authorUrl - URL of the User that is signing the request. + * @param req - Request to sign. + * @param timestamp - (optional) Timestamp of the request. + * @returns The signed request. + */ export const sign = async ( privateKey: CryptoKey, authorUrl: URL, @@ -45,6 +55,14 @@ export const sign = async ( return newReq; }; +/** + * Verifies a signed request using the Ed25519 algorithm, according to the [**Versia**](https://versia.pub/signatures) specification. + * + * @see https://versia.pub/signatures + * @param publicKey - Public key of the User that is verifying the request. + * @param req - Request to verify. + * @returns Whether the request signature is valid or not. + */ export const verify = async ( publicKey: CryptoKey, req: Request, @@ -62,7 +80,9 @@ export const verify = async ( const digest = await stringToBase64Hash(body); - const expectedSignedString = `${req.method.toLowerCase()} ${encodeURI(url.pathname)} ${signedAt} ${digest}`; + const expectedSignedString = `${req.method.toLowerCase()} ${encodeURI( + url.pathname, + )} ${signedAt} ${digest}`; // Check if this matches the signature return crypto.subtle.verify( diff --git a/packages/federation/entities/collection.ts b/packages/sdk/entities/collection.ts similarity index 100% rename from packages/federation/entities/collection.ts rename to packages/sdk/entities/collection.ts diff --git a/packages/federation/entities/contentformat.ts b/packages/sdk/entities/contentformat.ts similarity index 100% rename from packages/federation/entities/contentformat.ts rename to packages/sdk/entities/contentformat.ts diff --git a/packages/federation/entities/delete.ts b/packages/sdk/entities/delete.ts similarity index 100% rename from packages/federation/entities/delete.ts rename to packages/sdk/entities/delete.ts diff --git a/packages/federation/entities/entity.ts b/packages/sdk/entities/entity.ts similarity index 100% rename from packages/federation/entities/entity.ts rename to packages/sdk/entities/entity.ts diff --git a/packages/federation/entities/extensions/likes.ts b/packages/sdk/entities/extensions/likes.ts similarity index 100% rename from packages/federation/entities/extensions/likes.ts rename to packages/sdk/entities/extensions/likes.ts diff --git a/packages/federation/entities/extensions/polls.ts b/packages/sdk/entities/extensions/polls.ts similarity index 100% rename from packages/federation/entities/extensions/polls.ts rename to packages/sdk/entities/extensions/polls.ts diff --git a/packages/federation/entities/extensions/reactions.ts b/packages/sdk/entities/extensions/reactions.ts similarity index 100% rename from packages/federation/entities/extensions/reactions.ts rename to packages/sdk/entities/extensions/reactions.ts diff --git a/packages/federation/entities/extensions/reports.ts b/packages/sdk/entities/extensions/reports.ts similarity index 100% rename from packages/federation/entities/extensions/reports.ts rename to packages/sdk/entities/extensions/reports.ts diff --git a/packages/federation/entities/extensions/share.ts b/packages/sdk/entities/extensions/share.ts similarity index 100% rename from packages/federation/entities/extensions/share.ts rename to packages/sdk/entities/extensions/share.ts diff --git a/packages/federation/entities/follow.ts b/packages/sdk/entities/follow.ts similarity index 100% rename from packages/federation/entities/follow.ts rename to packages/sdk/entities/follow.ts diff --git a/packages/federation/entities/index.ts b/packages/sdk/entities/index.ts similarity index 100% rename from packages/federation/entities/index.ts rename to packages/sdk/entities/index.ts diff --git a/packages/federation/entities/instancemetadata.ts b/packages/sdk/entities/instancemetadata.ts similarity index 100% rename from packages/federation/entities/instancemetadata.ts rename to packages/sdk/entities/instancemetadata.ts diff --git a/packages/federation/entities/note.ts b/packages/sdk/entities/note.ts similarity index 100% rename from packages/federation/entities/note.ts rename to packages/sdk/entities/note.ts diff --git a/packages/federation/entities/user.ts b/packages/sdk/entities/user.ts similarity index 100% rename from packages/federation/entities/user.ts rename to packages/sdk/entities/user.ts diff --git a/packages/federation/http.ts b/packages/sdk/http.ts similarity index 100% rename from packages/federation/http.ts rename to packages/sdk/http.ts diff --git a/packages/federation/inbox-processor.ts b/packages/sdk/inbox-processor.ts similarity index 96% rename from packages/federation/inbox-processor.ts rename to packages/sdk/inbox-processor.ts index 647ce820..6c6e000a 100644 --- a/packages/federation/inbox-processor.ts +++ b/packages/sdk/inbox-processor.ts @@ -10,7 +10,7 @@ type MaybePromise = T | Promise; /** * @example * const jsonData = { ... }; - * const processor = new EntitySorter(jsonData) + * const processor = await new EntitySorter(jsonData) * .on(User, async (user) => { * // Do something with the user * }) diff --git a/packages/federation/package.json b/packages/sdk/package.json similarity index 100% rename from packages/federation/package.json rename to packages/sdk/package.json diff --git a/packages/federation/regex.ts b/packages/sdk/regex.ts similarity index 100% rename from packages/federation/regex.ts rename to packages/sdk/regex.ts diff --git a/packages/federation/schemas/collection.ts b/packages/sdk/schemas/collection.ts similarity index 100% rename from packages/federation/schemas/collection.ts rename to packages/sdk/schemas/collection.ts diff --git a/packages/federation/schemas/common.ts b/packages/sdk/schemas/common.ts similarity index 100% rename from packages/federation/schemas/common.ts rename to packages/sdk/schemas/common.ts diff --git a/packages/federation/schemas/contentformat.ts b/packages/sdk/schemas/contentformat.ts similarity index 100% rename from packages/federation/schemas/contentformat.ts rename to packages/sdk/schemas/contentformat.ts diff --git a/packages/federation/schemas/delete.ts b/packages/sdk/schemas/delete.ts similarity index 100% rename from packages/federation/schemas/delete.ts rename to packages/sdk/schemas/delete.ts diff --git a/packages/federation/schemas/entity.ts b/packages/sdk/schemas/entity.ts similarity index 100% rename from packages/federation/schemas/entity.ts rename to packages/sdk/schemas/entity.ts diff --git a/packages/federation/schemas/extensions/emojis.ts b/packages/sdk/schemas/extensions/emojis.ts similarity index 100% rename from packages/federation/schemas/extensions/emojis.ts rename to packages/sdk/schemas/extensions/emojis.ts diff --git a/packages/federation/schemas/extensions/groups.ts b/packages/sdk/schemas/extensions/groups.ts similarity index 100% rename from packages/federation/schemas/extensions/groups.ts rename to packages/sdk/schemas/extensions/groups.ts diff --git a/packages/federation/schemas/extensions/likes.ts b/packages/sdk/schemas/extensions/likes.ts similarity index 100% rename from packages/federation/schemas/extensions/likes.ts rename to packages/sdk/schemas/extensions/likes.ts diff --git a/packages/federation/schemas/extensions/migration.ts b/packages/sdk/schemas/extensions/migration.ts similarity index 100% rename from packages/federation/schemas/extensions/migration.ts rename to packages/sdk/schemas/extensions/migration.ts diff --git a/packages/federation/schemas/extensions/polls.ts b/packages/sdk/schemas/extensions/polls.ts similarity index 100% rename from packages/federation/schemas/extensions/polls.ts rename to packages/sdk/schemas/extensions/polls.ts diff --git a/packages/federation/schemas/extensions/reactions.ts b/packages/sdk/schemas/extensions/reactions.ts similarity index 100% rename from packages/federation/schemas/extensions/reactions.ts rename to packages/sdk/schemas/extensions/reactions.ts diff --git a/packages/federation/schemas/extensions/reports.ts b/packages/sdk/schemas/extensions/reports.ts similarity index 100% rename from packages/federation/schemas/extensions/reports.ts rename to packages/sdk/schemas/extensions/reports.ts diff --git a/packages/federation/schemas/extensions/share.ts b/packages/sdk/schemas/extensions/share.ts similarity index 100% rename from packages/federation/schemas/extensions/share.ts rename to packages/sdk/schemas/extensions/share.ts diff --git a/packages/federation/schemas/extensions/vanity.ts b/packages/sdk/schemas/extensions/vanity.ts similarity index 100% rename from packages/federation/schemas/extensions/vanity.ts rename to packages/sdk/schemas/extensions/vanity.ts diff --git a/packages/federation/schemas/follow.ts b/packages/sdk/schemas/follow.ts similarity index 100% rename from packages/federation/schemas/follow.ts rename to packages/sdk/schemas/follow.ts diff --git a/packages/federation/schemas/index.ts b/packages/sdk/schemas/index.ts similarity index 100% rename from packages/federation/schemas/index.ts rename to packages/sdk/schemas/index.ts diff --git a/packages/federation/schemas/instance.ts b/packages/sdk/schemas/instance.ts similarity index 100% rename from packages/federation/schemas/instance.ts rename to packages/sdk/schemas/instance.ts diff --git a/packages/federation/schemas/note.ts b/packages/sdk/schemas/note.ts similarity index 100% rename from packages/federation/schemas/note.ts rename to packages/sdk/schemas/note.ts diff --git a/packages/federation/schemas/user.ts b/packages/sdk/schemas/user.ts similarity index 100% rename from packages/federation/schemas/user.ts rename to packages/sdk/schemas/user.ts diff --git a/packages/federation/schemas/webfinger.ts b/packages/sdk/schemas/webfinger.ts similarity index 100% rename from packages/federation/schemas/webfinger.ts rename to packages/sdk/schemas/webfinger.ts diff --git a/packages/federation/types.ts b/packages/sdk/types.ts similarity index 100% rename from packages/federation/types.ts rename to packages/sdk/types.ts diff --git a/types/api.ts b/types/api.ts index 38953d73..444d4b4e 100644 --- a/types/api.ts +++ b/types/api.ts @@ -1,10 +1,10 @@ -import type * as VersiaEntities from "@versia/sdk/entities"; import type { SocketAddress } from "bun"; import type { Hono } from "hono"; import type { RouterRoute } from "hono/types"; import type { z } from "zod"; import type { ConfigSchema } from "~/classes/config/schema"; import type { AuthData } from "~/classes/functions/user"; +import type * as VersiaEntities from "~/packages/sdk/entities"; export type HttpVerb = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS"; diff --git a/utils/content_types.ts b/utils/content_types.ts index eebe7791..f1f0daa1 100644 --- a/utils/content_types.ts +++ b/utils/content_types.ts @@ -1,8 +1,8 @@ -import type { ContentFormatSchema } from "@versia/sdk/schemas"; import { htmlToText as htmlToTextLib } from "html-to-text"; import { lookup } from "mime-types"; import type { z } from "zod"; import { config } from "~/config.ts"; +import type { ContentFormatSchema } from "~/packages/sdk/schemas"; export const getBestContentType = ( content?: z.infer | null,