From fca30b4dad2175ddd08bacaf577a9c94f6860b01 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Wed, 25 Feb 2026 02:34:27 +0100 Subject: [PATCH 1/3] feat(federation): :sparkles: Port to Versia 0.6 --- cli/user/refetch.ts | 5 +- cli/utils.ts | 2 +- .../routes/api/v1/accounts/[id]/refetch.ts | 5 +- .../routes/api/v1/accounts/lookup/index.ts | 17 +- .../routes/api/v1/accounts/search/index.ts | 19 +- packages/api/routes/api/v2/search/index.ts | 33 +- packages/api/routes/likes/[uuid]/index.ts | 84 ----- packages/api/routes/notes/[uuid]/index.ts | 78 ----- packages/api/routes/notes/[uuid]/quotes.ts | 146 -------- packages/api/routes/notes/[uuid]/replies.ts | 144 -------- packages/api/routes/notes/[uuid]/shares.ts | 150 -------- packages/api/routes/shares/[uuid]/index.ts | 78 ----- .../api/routes/users/[uuid]/inbox/index.ts | 118 ------- packages/api/routes/users/[uuid]/index.ts | 75 ---- .../api/routes/users/[uuid]/outbox/index.ts | 137 -------- .../[id]/collections/[collection_type].ts | 324 ++++++++++++++++++ .../versia/v0.6/[entity_type]/[id]/index.ts | 178 ++++++++++ .../v0.6/inbox.test.ts} | 164 ++++----- .../{inbox/index.ts => versia/v0.6/inbox.ts} | 19 +- packages/api/routes/versia/v0.6/instance.ts | 88 +++++ packages/api/routes/well-known/versia.ts | 73 +--- packages/kit/db/instance.ts | 85 +++-- packages/kit/db/like.ts | 63 ++-- packages/kit/db/media.ts | 4 +- packages/kit/db/note.ts | 279 ++++++++------- packages/kit/db/reaction.ts | 63 ++-- packages/kit/db/user.ts | 323 +++++------------ packages/kit/inbox-processor.ts | 68 ++-- packages/kit/parsers.ts | 10 +- packages/kit/queues/fetch/worker.ts | 4 +- packages/kit/queues/inbox/worker.ts | 43 +-- packages/kit/tables/schema.ts | 24 +- packages/sdk/crypto.ts | 8 +- packages/sdk/entities/delete.ts | 10 +- packages/sdk/entities/entity.ts | 28 ++ packages/sdk/entities/extensions/likes.ts | 18 +- packages/sdk/entities/extensions/polls.ts | 10 +- packages/sdk/entities/extensions/reactions.ts | 10 +- packages/sdk/entities/extensions/reports.ts | 10 +- packages/sdk/entities/extensions/share.ts | 10 +- packages/sdk/entities/follow.ts | 34 +- packages/sdk/entities/index.ts | 2 +- packages/sdk/entities/note.ts | 31 +- packages/sdk/http.ts | 223 ++++++++---- packages/sdk/schemas/collection.ts | 11 +- packages/sdk/schemas/contentformat.ts | 31 +- packages/sdk/schemas/delete.ts | 10 +- packages/sdk/schemas/entity.ts | 19 +- packages/sdk/schemas/extensions/groups.ts | 39 +-- packages/sdk/schemas/extensions/likes.ts | 11 +- packages/sdk/schemas/extensions/migration.ts | 14 +- packages/sdk/schemas/extensions/polls.ts | 10 +- packages/sdk/schemas/extensions/reactions.ts | 7 +- packages/sdk/schemas/extensions/reports.ts | 10 +- packages/sdk/schemas/extensions/share.ts | 7 +- packages/sdk/schemas/extensions/vanity.ts | 23 +- packages/sdk/schemas/follow.ts | 31 +- packages/sdk/schemas/index.ts | 6 +- packages/sdk/schemas/instance.ts | 12 +- packages/sdk/schemas/note.ts | 46 +-- packages/sdk/schemas/user.ts | 37 +- types/api.ts | 1 + 62 files changed, 1614 insertions(+), 2008 deletions(-) delete mode 100644 packages/api/routes/likes/[uuid]/index.ts delete mode 100644 packages/api/routes/notes/[uuid]/index.ts delete mode 100644 packages/api/routes/notes/[uuid]/quotes.ts delete mode 100644 packages/api/routes/notes/[uuid]/replies.ts delete mode 100644 packages/api/routes/notes/[uuid]/shares.ts delete mode 100644 packages/api/routes/shares/[uuid]/index.ts delete mode 100644 packages/api/routes/users/[uuid]/inbox/index.ts delete mode 100644 packages/api/routes/users/[uuid]/index.ts delete mode 100644 packages/api/routes/users/[uuid]/outbox/index.ts create mode 100644 packages/api/routes/versia/v0.6/[entity_type]/[id]/collections/[collection_type].ts create mode 100644 packages/api/routes/versia/v0.6/[entity_type]/[id]/index.ts rename packages/api/routes/{inbox/index.test.ts => versia/v0.6/inbox.test.ts} (69%) rename packages/api/routes/{inbox/index.ts => versia/v0.6/inbox.ts} (78%) create mode 100644 packages/api/routes/versia/v0.6/instance.ts diff --git a/cli/user/refetch.ts b/cli/user/refetch.ts index f805cf4d..376fb9c9 100644 --- a/cli/user/refetch.ts +++ b/cli/user/refetch.ts @@ -28,7 +28,10 @@ export const refetchUserCommand = defineCommand( const spinner = ora("Refetching user").start(); try { - await User.fromVersia(user.uri); + await User.fromVersia( + user.reference, + user.reference.domain as string, + ); } catch (error) { spinner.fail( `Failed to refetch user ${chalk.gray(user.data.username)}`, diff --git a/cli/utils.ts b/cli/utils.ts index b75ffc06..2fc6b494 100644 --- a/cli/utils.ts +++ b/cli/utils.ts @@ -8,7 +8,7 @@ export const retrieveUser = async ( ): Promise => { const { username, domain } = parseUserAddress(usernameOrHandle); - const instance = domain ? await Instance.resolveFromHost(domain) : null; + const instance = domain ? await Instance.resolve(domain) : null; const user = await User.fromSql( and( diff --git a/packages/api/routes/api/v1/accounts/[id]/refetch.ts b/packages/api/routes/api/v1/accounts/[id]/refetch.ts index c817269d..5f3d6577 100644 --- a/packages/api/routes/api/v1/accounts/[id]/refetch.ts +++ b/packages/api/routes/api/v1/accounts/[id]/refetch.ts @@ -50,7 +50,10 @@ export default apiRoute((app) => throw new ApiError(400, "Cannot refetch a local user"); } - const newUser = await User.fromVersia(otherUser.uri); + const newUser = await User.fromVersia( + otherUser.reference, + otherUser.reference.domain as string, + ); return context.json(newUser.toApi(false), 200); }, diff --git a/packages/api/routes/api/v1/accounts/lookup/index.ts b/packages/api/routes/api/v1/accounts/lookup/index.ts index b247d3fd..3122e1b6 100644 --- a/packages/api/routes/api/v1/accounts/lookup/index.ts +++ b/packages/api/routes/api/v1/accounts/lookup/index.ts @@ -2,6 +2,7 @@ import { Account as AccountSchema, RolePermission, } from "@versia/client/schemas"; +import * as VersiaEntities from "@versia/sdk/entities"; import { config } from "@versia-server/config"; import { ApiError } from "@versia-server/kit"; import { apiRoute, auth, handleZodError } from "@versia-server/kit/api"; @@ -73,7 +74,7 @@ export default apiRoute((app) => // User is remote // Try to fetch it from database - const instance = await Instance.resolveFromHost(domain); + const instance = await Instance.resolve(domain); if (!instance) { return context.json( @@ -100,13 +101,17 @@ export default apiRoute((app) => throw ApiError.accountNotFound(); } - const foundAccount = await User.resolve(uri); + const accountData = await Instance.federationRequester.fetchSigned( + uri, + VersiaEntities.User, + ); - if (foundAccount) { - return context.json(foundAccount.toApi(), 200); - } + const foundAccount = await User.fromVersia( + accountData, + instance.data.baseUrl, + ); - throw ApiError.accountNotFound(); + return context.json(foundAccount.toApi(), 200); }, ), ); diff --git a/packages/api/routes/api/v1/accounts/search/index.ts b/packages/api/routes/api/v1/accounts/search/index.ts index 4dbadffa..ee787542 100644 --- a/packages/api/routes/api/v1/accounts/search/index.ts +++ b/packages/api/routes/api/v1/accounts/search/index.ts @@ -3,9 +3,10 @@ import { RolePermission, zBoolean, } from "@versia/client/schemas"; +import * as VersiaEntities from "@versia/sdk/entities"; import { ApiError } from "@versia-server/kit"; import { apiRoute, auth, handleZodError } from "@versia-server/kit/api"; -import { User } from "@versia-server/kit/db"; +import { Instance, User } from "@versia-server/kit/db"; import { parseUserAddress } from "@versia-server/kit/parsers"; import { Users } from "@versia-server/kit/tables"; import { eq, ilike, not, or, sql } from "drizzle-orm"; @@ -88,14 +89,22 @@ export default apiRoute((app) => const accounts: User[] = []; if (resolve && domain) { + const instance = await Instance.resolve(domain); const uri = await User.webFinger(username, domain); if (uri) { - const resolvedUser = await User.resolve(uri); + const accountData = + await Instance.federationRequester.fetchSigned( + uri, + VersiaEntities.User, + ); - if (resolvedUser) { - accounts.push(resolvedUser); - } + const foundAccount = await User.fromVersia( + accountData, + instance.data.baseUrl, + ); + + accounts.push(foundAccount); } } else { accounts.push( diff --git a/packages/api/routes/api/v2/search/index.ts b/packages/api/routes/api/v2/search/index.ts index 47bccfbb..432e3faf 100644 --- a/packages/api/routes/api/v2/search/index.ts +++ b/packages/api/routes/api/v2/search/index.ts @@ -6,10 +6,11 @@ import { userAddressRegex, zBoolean, } from "@versia/client/schemas"; +import * as VersiaEntities from "@versia/sdk/entities"; import { config } from "@versia-server/config"; import { ApiError } from "@versia-server/kit"; import { apiRoute, auth, handleZodError } from "@versia-server/kit/api"; -import { db, Note, User } from "@versia-server/kit/db"; +import { db, Instance, Note, User } from "@versia-server/kit/db"; import { parseUserAddress } from "@versia-server/kit/parsers"; import { searchManager } from "@versia-server/kit/search"; import { Instances, Notes, Users } from "@versia-server/kit/tables"; @@ -187,21 +188,29 @@ export default apiRoute((app) => } if (resolve && domain) { + const instance = await Instance.resolve(domain); const uri = await User.webFinger(username, domain); if (uri) { - const newUser = await User.resolve(uri); - - if (newUser) { - return context.json( - { - accounts: [newUser.toApi()], - statuses: [], - hashtags: [], - }, - 200, + const accountData = + await Instance.federationRequester.fetchSigned( + uri, + VersiaEntities.User, ); - } + + const newUser = await User.fromVersia( + accountData, + instance.data.baseUrl, + ); + + return context.json( + { + accounts: [newUser.toApi()], + statuses: [], + hashtags: [], + }, + 200, + ); } } } diff --git a/packages/api/routes/likes/[uuid]/index.ts b/packages/api/routes/likes/[uuid]/index.ts deleted file mode 100644 index a0d99ba0..00000000 --- a/packages/api/routes/likes/[uuid]/index.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Status as StatusSchema } from "@versia/client/schemas"; -import { LikeSchema } from "@versia/sdk/schemas"; -import { config } from "@versia-server/config"; -import { ApiError } from "@versia-server/kit"; -import { apiRoute, handleZodError } from "@versia-server/kit/api"; -import { Like, User } from "@versia-server/kit/db"; -import { Likes } from "@versia-server/kit/tables"; -import { and, eq, sql } from "drizzle-orm"; -import { describeRoute, resolver, validator } from "hono-openapi"; -import { z } from "zod"; - -export default apiRoute((app) => - app.get( - "/likes/:id", - describeRoute({ - summary: "Retrieve the Versia representation of a like.", - tags: ["Federation"], - responses: { - 200: { - description: "Like", - content: { - "application/json": { - schema: resolver(LikeSchema), - }, - }, - }, - 404: { - description: - "Entity not found, is remote, or the requester is not allowed to view it.", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - }, - }), - validator( - "param", - z.object({ id: StatusSchema.shape.id }), - handleZodError, - ), - async (context) => { - const { id } = context.req.valid("param"); - - // Don't fetch a like of a note that is not public or unlisted - // prevents leaking the existence of a private note - const like = await Like.fromSql( - and( - eq(Likes.id, id), - sql`EXISTS (SELECT 1 FROM "Notes" WHERE "Notes"."id" = ${Likes.likedId} AND "Notes"."visibility" IN ('public', 'unlisted'))`, - ), - ); - - if (!like) { - throw ApiError.likeNotFound(); - } - - const liker = await User.fromId(like.data.likerId); - - if (!liker || liker.remote) { - throw ApiError.accountNotFound(); - } - - // If base_url uses https and request uses http, rewrite request to use https - // This fixes reverse proxy errors - const reqUrl = new URL(context.req.url); - if ( - config.http.base_url.protocol === "https:" && - reqUrl.protocol === "http:" - ) { - reqUrl.protocol = "https:"; - } - - const { headers } = await liker.sign( - like.toVersia(), - reqUrl, - "GET", - ); - - return context.json(like.toVersia(), 200, headers.toJSON()); - }, - ), -); diff --git a/packages/api/routes/notes/[uuid]/index.ts b/packages/api/routes/notes/[uuid]/index.ts deleted file mode 100644 index 4d57f219..00000000 --- a/packages/api/routes/notes/[uuid]/index.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Status as StatusSchema } from "@versia/client/schemas"; -import { NoteSchema } from "@versia/sdk/schemas"; -import { config } from "@versia-server/config"; -import { ApiError } from "@versia-server/kit"; -import { apiRoute, handleZodError } from "@versia-server/kit/api"; -import { Note } from "@versia-server/kit/db"; -import { Notes } from "@versia-server/kit/tables"; -import { and, eq, inArray } from "drizzle-orm"; -import { describeRoute, resolver, validator } from "hono-openapi"; -import { z } from "zod"; - -export default apiRoute((app) => - app.get( - "/notes/:id", - describeRoute({ - summary: "Retrieve the Versia representation of a note.", - tags: ["Federation"], - responses: { - 200: { - description: "Note", - content: { - "application/json": { - schema: resolver(NoteSchema), - }, - }, - }, - 404: { - description: - "Entity not found, is remote, or the requester is not allowed to view it.", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - }, - }), - validator( - "param", - z.object({ - id: StatusSchema.shape.id, - }), - handleZodError, - ), - async (context) => { - const { id } = context.req.valid("param"); - - const note = await Note.fromSql( - and( - eq(Notes.id, id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - ); - - if (!(note && (await note.isViewableByUser(null))) || note.remote) { - throw ApiError.noteNotFound(); - } - - // If base_url uses https and request uses http, rewrite request to use https - // This fixes reverse proxy errors - const reqUrl = new URL(context.req.url); - if ( - config.http.base_url.protocol === "https:" && - reqUrl.protocol === "http:" - ) { - reqUrl.protocol = "https:"; - } - - const { headers } = await note.author.sign( - note.toVersia(), - reqUrl, - "GET", - ); - - return context.json(note.toVersia(), 200, headers.toJSON()); - }, - ), -); diff --git a/packages/api/routes/notes/[uuid]/quotes.ts b/packages/api/routes/notes/[uuid]/quotes.ts deleted file mode 100644 index 6497cc27..00000000 --- a/packages/api/routes/notes/[uuid]/quotes.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { Status as StatusSchema } from "@versia/client/schemas"; -import * as VersiaEntities from "@versia/sdk/entities"; -import { URICollectionSchema } from "@versia/sdk/schemas"; -import { config } from "@versia-server/config"; -import { ApiError } from "@versia-server/kit"; -import { apiRoute, handleZodError } from "@versia-server/kit/api"; -import { db, Note } from "@versia-server/kit/db"; -import { Notes } from "@versia-server/kit/tables"; -import { and, eq, inArray } from "drizzle-orm"; -import { describeRoute, resolver, validator } from "hono-openapi"; -import { z } from "zod"; - -export default apiRoute((app) => - app.get( - "/notes/:id/quotes", - describeRoute({ - summary: "Retrieve all quotes of a Versia Note.", - tags: ["Federation"], - responses: { - 200: { - description: "Note quotes", - content: { - "application/json": { - schema: resolver(URICollectionSchema), - }, - }, - }, - 404: { - description: - "Entity not found, is remote, or the requester is not allowed to view it.", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - }, - }), - validator( - "param", - z.object({ - id: StatusSchema.shape.id, - }), - handleZodError, - ), - validator( - "query", - z.object({ - limit: z.coerce.number().int().min(1).max(100).default(40), - offset: z.coerce.number().int().nonnegative().default(0), - }), - handleZodError, - ), - async (context) => { - const { id } = context.req.valid("param"); - const { limit, offset } = context.req.valid("query"); - - const note = await Note.fromSql( - and( - eq(Notes.id, id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - ); - - if (!(note && (await note.isViewableByUser(null))) || note.remote) { - throw ApiError.noteNotFound(); - } - - const quotes = await Note.manyFromSql( - and( - eq(Notes.quotingId, note.id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - undefined, - limit, - offset, - ); - - const quoteCount = await db.$count( - Notes, - and( - eq(Notes.quotingId, note.id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - ); - - const uriCollection = new VersiaEntities.URICollection({ - author: note.author.uri.href, - first: new URL( - `/notes/${note.id}/quotes?offset=0`, - config.http.base_url, - ).href, - last: - quoteCount > limit - ? new URL( - `/notes/${note.id}/quotes?offset=${ - quoteCount - limit - }`, - config.http.base_url, - ).href - : new URL( - `/notes/${note.id}/quotes`, - config.http.base_url, - ).href, - next: - offset + limit < quoteCount - ? new URL( - `/notes/${note.id}/quotes?offset=${ - offset + limit - }`, - config.http.base_url, - ).href - : null, - previous: - offset - limit >= 0 - ? new URL( - `/notes/${note.id}/quotes?offset=${ - offset - limit - }`, - config.http.base_url, - ).href - : null, - total: quoteCount, - items: quotes.map((reply) => reply.getUri().href), - }); - - // If base_url uses https and request uses http, rewrite request to use https - // This fixes reverse proxy errors - const reqUrl = new URL(context.req.url); - if ( - config.http.base_url.protocol === "https:" && - reqUrl.protocol === "http:" - ) { - reqUrl.protocol = "https:"; - } - - const { headers } = await note.author.sign( - uriCollection, - reqUrl, - "GET", - ); - - return context.json(uriCollection, 200, headers.toJSON()); - }, - ), -); diff --git a/packages/api/routes/notes/[uuid]/replies.ts b/packages/api/routes/notes/[uuid]/replies.ts deleted file mode 100644 index 2721a666..00000000 --- a/packages/api/routes/notes/[uuid]/replies.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { Status as StatusSchema } from "@versia/client/schemas"; -import * as VersiaEntities from "@versia/sdk/entities"; -import { URICollectionSchema } from "@versia/sdk/schemas"; -import { config } from "@versia-server/config"; -import { ApiError } from "@versia-server/kit"; -import { apiRoute, handleZodError } from "@versia-server/kit/api"; -import { db, Note } from "@versia-server/kit/db"; -import { Notes } from "@versia-server/kit/tables"; -import { and, eq, inArray } from "drizzle-orm"; -import { describeRoute, resolver, validator } from "hono-openapi"; -import { z } from "zod"; - -export default apiRoute((app) => - app.get( - "/notes/:id/replies", - describeRoute({ - summary: "Retrieve all replies to a Versia Note.", - tags: ["Federation"], - responses: { - 200: { - description: "Note replies", - content: { - "application/json": { - schema: resolver(URICollectionSchema), - }, - }, - }, - 404: { - description: - "Entity not found, is remote, or the requester is not allowed to view it.", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - }, - }), - validator( - "param", - z.object({ id: StatusSchema.shape.id }), - handleZodError, - ), - validator( - "query", - z.object({ - limit: z.coerce.number().int().min(1).max(100).default(40), - offset: z.coerce.number().int().nonnegative().default(0), - }), - handleZodError, - ), - async (context) => { - const { id } = context.req.valid("param"); - const { limit, offset } = context.req.valid("query"); - - const note = await Note.fromSql( - and( - eq(Notes.id, id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - ); - - if (!(note && (await note.isViewableByUser(null))) || note.remote) { - throw ApiError.noteNotFound(); - } - - const replies = await Note.manyFromSql( - and( - eq(Notes.replyId, note.id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - undefined, - limit, - offset, - ); - - const replyCount = await db.$count( - Notes, - and( - eq(Notes.replyId, note.id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - ); - - const uriCollection = new VersiaEntities.URICollection({ - author: note.author.uri.href, - first: new URL( - `/notes/${note.id}/replies?offset=0`, - config.http.base_url, - ).href, - last: - replyCount > limit - ? new URL( - `/notes/${note.id}/replies?offset=${ - replyCount - limit - }`, - config.http.base_url, - ).href - : new URL( - `/notes/${note.id}/replies`, - config.http.base_url, - ).href, - next: - offset + limit < replyCount - ? new URL( - `/notes/${note.id}/replies?offset=${ - offset + limit - }`, - config.http.base_url, - ).href - : null, - previous: - offset - limit >= 0 - ? new URL( - `/notes/${note.id}/replies?offset=${ - offset - limit - }`, - config.http.base_url, - ).href - : null, - total: replyCount, - items: replies.map((reply) => reply.getUri().href), - }); - - // If base_url uses https and request uses http, rewrite request to use https - // This fixes reverse proxy errors - const reqUrl = new URL(context.req.url); - if ( - config.http.base_url.protocol === "https:" && - reqUrl.protocol === "http:" - ) { - reqUrl.protocol = "https:"; - } - - const { headers } = await note.author.sign( - uriCollection, - reqUrl, - "GET", - ); - - return context.json(uriCollection, 200, headers.toJSON()); - }, - ), -); diff --git a/packages/api/routes/notes/[uuid]/shares.ts b/packages/api/routes/notes/[uuid]/shares.ts deleted file mode 100644 index 18be1fa4..00000000 --- a/packages/api/routes/notes/[uuid]/shares.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { Status as StatusSchema } from "@versia/client/schemas"; -import * as VersiaEntities from "@versia/sdk/entities"; -import { URICollectionSchema } from "@versia/sdk/schemas"; -import { config } from "@versia-server/config"; -import { ApiError } from "@versia-server/kit"; -import { apiRoute, handleZodError } from "@versia-server/kit/api"; -import { db, Note } from "@versia-server/kit/db"; -import { Notes } from "@versia-server/kit/tables"; -import { and, eq, inArray } from "drizzle-orm"; -import { describeRoute, resolver, validator } from "hono-openapi"; -import { z } from "zod"; - -export default apiRoute((app) => - app.get( - "/notes/:id/shares", - describeRoute({ - summary: "Retrieve all shares of a Versia Note.", - tags: ["Federation"], - responses: { - 200: { - description: "Note shares", - content: { - "application/json": { - schema: resolver(URICollectionSchema), - }, - }, - }, - 404: { - description: - "Entity not found, is remote, or the requester is not allowed to view it.", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - }, - }), - validator( - "param", - z.object({ - id: StatusSchema.shape.id, - }), - handleZodError, - ), - validator( - "query", - z.object({ - limit: z.coerce.number().int().min(1).max(100).default(40), - offset: z.coerce.number().int().nonnegative().default(0), - }), - handleZodError, - ), - async (context) => { - const { id } = context.req.valid("param"); - const { limit, offset } = context.req.valid("query"); - - const note = await Note.fromSql( - and( - eq(Notes.id, id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - ); - - if (!(note && (await note.isViewableByUser(null))) || note.remote) { - throw ApiError.noteNotFound(); - } - - const shares = await Note.manyFromSql( - and( - eq(Notes.reblogId, note.id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - undefined, - limit, - offset, - ); - - const shareCount = await db.$count( - Notes, - and( - eq(Notes.reblogId, note.id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - ); - - const uriCollection = new VersiaEntities.URICollection({ - author: note.author.uri.href, - first: new URL( - `/notes/${note.id}/shares?offset=0`, - config.http.base_url, - ).href, - last: - shareCount > limit - ? new URL( - `/notes/${note.id}/shares?offset=${ - shareCount - limit - }`, - config.http.base_url, - ).href - : new URL( - `/notes/${note.id}/shares`, - config.http.base_url, - ).href, - next: - offset + limit < shareCount - ? new URL( - `/notes/${note.id}/shares?offset=${ - offset + limit - }`, - config.http.base_url, - ).href - : null, - previous: - offset - limit >= 0 - ? new URL( - `/notes/${note.id}/shares?offset=${ - offset - limit - }`, - config.http.base_url, - ).href - : null, - total: shareCount, - items: shares.map( - (share) => - new URL(`/shares/${share.id}`, config.http.base_url) - .href, - ), - }); - - // If base_url uses https and request uses http, rewrite request to use https - // This fixes reverse proxy errors - const reqUrl = new URL(context.req.url); - if ( - config.http.base_url.protocol === "https:" && - reqUrl.protocol === "http:" - ) { - reqUrl.protocol = "https:"; - } - - const { headers } = await note.author.sign( - uriCollection, - reqUrl, - "GET", - ); - - return context.json(uriCollection, 200, headers.toJSON()); - }, - ), -); diff --git a/packages/api/routes/shares/[uuid]/index.ts b/packages/api/routes/shares/[uuid]/index.ts deleted file mode 100644 index 4c5b376f..00000000 --- a/packages/api/routes/shares/[uuid]/index.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Status as StatusSchema } from "@versia/client/schemas"; -import { ShareSchema } from "@versia/sdk/schemas"; -import { config } from "@versia-server/config"; -import { ApiError } from "@versia-server/kit"; -import { apiRoute, handleZodError } from "@versia-server/kit/api"; -import { Note } from "@versia-server/kit/db"; -import { Notes } from "@versia-server/kit/tables"; -import { and, eq, inArray } from "drizzle-orm"; -import { describeRoute, resolver, validator } from "hono-openapi"; -import { z } from "zod"; - -export default apiRoute((app) => - app.get( - "/shares/:id", - describeRoute({ - summary: "Retrieve the Versia representation of a share.", - tags: ["Federation"], - responses: { - 200: { - description: "Share", - content: { - "application/json": { - schema: resolver(ShareSchema), - }, - }, - }, - 404: { - description: - "Entity not found, is remote, or the requester is not allowed to view it.", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - }, - }), - validator( - "param", - z.object({ - id: StatusSchema.shape.id, - }), - handleZodError, - ), - async (context) => { - const { id } = context.req.valid("param"); - - const note = await Note.fromSql( - and( - eq(Notes.id, id), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - ); - - if (!(note && (await note.isViewableByUser(null))) || note.remote) { - throw ApiError.noteNotFound(); - } - - // If base_url uses https and request uses http, rewrite request to use https - // This fixes reverse proxy errors - const reqUrl = new URL(context.req.url); - if ( - config.http.base_url.protocol === "https:" && - reqUrl.protocol === "http:" - ) { - reqUrl.protocol = "https:"; - } - - const { headers } = await note.author.sign( - note.toVersiaShare(), - reqUrl, - "GET", - ); - - return context.json(note.toVersiaShare(), 200, headers.toJSON()); - }, - ), -); diff --git a/packages/api/routes/users/[uuid]/inbox/index.ts b/packages/api/routes/users/[uuid]/inbox/index.ts deleted file mode 100644 index 7c7a376d..00000000 --- a/packages/api/routes/users/[uuid]/inbox/index.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { ApiError } from "@versia-server/kit"; -import { apiRoute, handleZodError } from "@versia-server/kit/api"; -import { InboxJobType, inboxQueue } from "@versia-server/kit/queues/inbox"; -import { describeRoute, resolver, validator } from "hono-openapi"; -import { z } from "zod"; - -export default apiRoute((app) => - app.post( - "/users/:uuid/inbox", - describeRoute({ - summary: "Receive federation inbox", - tags: ["Federation"], - responses: { - 200: { - description: "Request processed", - }, - 201: { - description: "Request accepted", - }, - 400: { - description: "Bad request", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - 401: { - description: "Signature could not be verified", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - 403: { - description: "Cannot view users from remote instances", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - 404: { - description: "Not found", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - 500: { - description: "Internal server error", - content: { - "application/json": { - schema: resolver( - z.object({ - error: z.string(), - message: z.string(), - }), - ), - }, - }, - }, - }, - }), - validator( - "param", - z.object({ - uuid: z.uuid(), - }), - handleZodError, - ), - validator( - "header", - z.object({ - "versia-signature": z.string().optional(), - "versia-signed-at": z.coerce.number().optional(), - "versia-signed-by": z - .url() - .or(z.string().startsWith("instance ")) - .optional(), - authorization: z.string().optional(), - }), - handleZodError, - ), - async (context) => { - const body = await context.req.json(); - const { - "versia-signature": signature, - "versia-signed-at": signedAt, - "versia-signed-by": signedBy, - authorization, - } = context.req.valid("header"); - - await inboxQueue.add(InboxJobType.ProcessEntity, { - data: body, - headers: { - "versia-signature": signature, - "versia-signed-at": signedAt, - "versia-signed-by": signedBy, - authorization, - }, - request: { - body: await context.req.text(), - method: context.req.method, - url: context.req.url, - }, - ip: context.env.ip ?? null, - }); - - return context.body( - "Request processing initiated.\nImplement the Instance Messaging Extension to receive any eventual feedback (errors, etc.)", - 200, - ); - }, - ), -); diff --git a/packages/api/routes/users/[uuid]/index.ts b/packages/api/routes/users/[uuid]/index.ts deleted file mode 100644 index b47aecb6..00000000 --- a/packages/api/routes/users/[uuid]/index.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { UserSchema } from "@versia/sdk/schemas"; -import { ApiError } from "@versia-server/kit"; -import { apiRoute, handleZodError } from "@versia-server/kit/api"; -import { User } from "@versia-server/kit/db"; -import { describeRoute, resolver, validator } from "hono-openapi"; -import { z } from "zod"; - -export default apiRoute((app) => - app.get( - "/users/:uuid", - describeRoute({ - summary: "Get user data", - tags: ["Federation"], - responses: { - 200: { - description: "User data", - content: { - "application/json": { - schema: resolver(UserSchema), - }, - }, - }, - 301: { - description: - "Redirect to user profile (for web browsers). Uses user-agent for detection.", - }, - 404: ApiError.accountNotFound().schema, - 403: { - description: "Cannot view users from remote instances", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - }, - }), - validator( - "param", - z.object({ - uuid: z.uuid(), - }), - handleZodError, - ), - // @ts-expect-error idk why this is happening and I don't care - async (context) => { - const { uuid } = context.req.valid("param"); - - const user = await User.fromId(uuid); - - if (!user) { - throw ApiError.accountNotFound(); - } - - if (user.remote) { - throw new ApiError(403, "User is not on this instance"); - } - - // Try to detect a web browser and redirect to the user's profile page - if (context.req.header("user-agent")?.includes("Mozilla")) { - return context.redirect(user.toApi().url); - } - - const userJson = user.toVersia(); - - const { headers } = await user.sign( - userJson, - new URL(context.req.url), - "GET", - ); - - return context.json(userJson, 200, headers.toJSON()); - }, - ), -); diff --git a/packages/api/routes/users/[uuid]/outbox/index.ts b/packages/api/routes/users/[uuid]/outbox/index.ts deleted file mode 100644 index 0f86b784..00000000 --- a/packages/api/routes/users/[uuid]/outbox/index.ts +++ /dev/null @@ -1,137 +0,0 @@ -import * as VersiaEntities from "@versia/sdk/entities"; -import { CollectionSchema, NoteSchema } from "@versia/sdk/schemas"; -import { config } from "@versia-server/config"; -import { ApiError } from "@versia-server/kit"; -import { apiRoute, handleZodError } from "@versia-server/kit/api"; -import { db, Note, User } from "@versia-server/kit/db"; -import { Notes } from "@versia-server/kit/tables"; -import { and, eq, inArray } from "drizzle-orm"; -import { describeRoute, resolver, validator } from "hono-openapi"; -import { z } from "zod"; - -const NOTES_PER_PAGE = 20; - -export default apiRoute((app) => - app.get( - "/users/:uuid/outbox", - describeRoute({ - summary: "Get user outbox", - tags: ["Federation"], - responses: { - 200: { - description: "User outbox", - content: { - "application/json": { - schema: resolver( - CollectionSchema.extend({ - items: z.array(NoteSchema), - }), - ), - }, - }, - }, - 404: { - description: "User not found", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - 403: { - description: "Cannot view users from remote instances", - content: { - "application/json": { - schema: resolver(ApiError.zodSchema), - }, - }, - }, - }, - }), - validator( - "param", - z.object({ - uuid: z.uuid(), - }), - handleZodError, - ), - validator( - "query", - z.object({ - page: z.string().optional(), - }), - handleZodError, - ), - async (context) => { - const { uuid } = context.req.valid("param"); - - const author = await User.fromId(uuid); - - if (!author) { - throw new ApiError(404, "User not found"); - } - - if (author.remote) { - throw new ApiError(403, "User is not on this instance"); - } - - const pageNumber = Number(context.req.valid("query").page) || 1; - - const notes = await Note.manyFromSql( - and( - eq(Notes.authorId, uuid), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - undefined, - NOTES_PER_PAGE, - NOTES_PER_PAGE * (pageNumber - 1), - ); - - const totalNotes = await db.$count( - Notes, - and( - eq(Notes.authorId, uuid), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - ); - - const json = new VersiaEntities.Collection({ - first: new URL( - `/users/${uuid}/outbox?page=1`, - config.http.base_url, - ).href, - last: new URL( - `/users/${uuid}/outbox?page=${Math.ceil( - totalNotes / NOTES_PER_PAGE, - )}`, - config.http.base_url, - ).href, - total: totalNotes, - author: author.uri.href, - next: - notes.length === NOTES_PER_PAGE - ? new URL( - `/users/${uuid}/outbox?page=${pageNumber + 1}`, - config.http.base_url, - ).href - : null, - previous: - pageNumber > 1 - ? new URL( - `/users/${uuid}/outbox?page=${pageNumber - 1}`, - config.http.base_url, - ).href - : null, - items: notes.map((note) => note.toVersia()), - }); - - const { headers } = await author.sign( - json, - new URL(context.req.url), - "GET", - ); - - return context.json(json, 200, headers.toJSON()); - }, - ), -); diff --git a/packages/api/routes/versia/v0.6/[entity_type]/[id]/collections/[collection_type].ts b/packages/api/routes/versia/v0.6/[entity_type]/[id]/collections/[collection_type].ts new file mode 100644 index 00000000..d4e5a217 --- /dev/null +++ b/packages/api/routes/versia/v0.6/[entity_type]/[id]/collections/[collection_type].ts @@ -0,0 +1,324 @@ +import * as VersiaEntities from "@versia/sdk/entities"; +import { + CollectionSchema, + EntitySchema, + URICollectionSchema, +} from "@versia/sdk/schemas"; +import { ApiError } from "@versia-server/kit"; +import { apiRoute, handleZodError } from "@versia-server/kit/api"; +import { db, Instance, Note, User } from "@versia-server/kit/db"; +import { Notes, Users } from "@versia-server/kit/tables"; +import { and, eq, inArray, sql } from "drizzle-orm"; +import { describeRoute, resolver, validator } from "hono-openapi"; +import { z } from "zod"; + +export default apiRoute((app) => + app.get( + "/.versia/v0.6/entities/:entity_type/:id/collections/:collection_type", + describeRoute({ + summary: + "Retrieve the Versia representation of a collection attached to an entity.", + tags: ["Federation"], + responses: { + 200: { + description: "Collection", + content: { + "application/json": { + schema: resolver( + z.union([ + CollectionSchema, + URICollectionSchema, + ]), + ), + }, + }, + }, + 404: { + description: "Collection not found.", + content: { + "application/json": { + schema: resolver(ApiError.zodSchema), + }, + }, + }, + }, + }), + validator( + "param", + z.object({ + entity_type: EntitySchema.shape.type, + id: EntitySchema.shape.id, + collection_type: z.string(), + }), + handleZodError, + ), + validator( + "query", + z.object({ + limit: z.coerce.number().int().min(1).max(40).default(40), + offset: z.coerce.number().int().nonnegative().default(0), + }), + handleZodError, + ), + async (context) => { + const { entity_type, id, collection_type } = + context.req.valid("param"); + const { limit, offset } = context.req.valid("query"); + + let entity: + | VersiaEntities.Collection + | VersiaEntities.URICollection + | null = null; + + switch (entity_type) { + case "Note": { + const note = await Note.fromSql( + and( + eq(Notes.id, id), + inArray(Notes.visibility, ["public", "unlisted"]), + ), + ); + + if ( + !(note && (await note.isViewableByUser(null))) || + note.remote + ) { + throw ApiError.noteNotFound(); + } + + switch (collection_type) { + case "replies": { + const replies = await Note.manyFromSql( + and( + eq(Notes.replyId, note.id), + inArray(Notes.visibility, [ + "public", + "unlisted", + ]), + ), + undefined, + limit, + offset, + ); + + const replyCount = await db.$count( + Notes, + and( + eq(Notes.replyId, note.id), + inArray(Notes.visibility, [ + "public", + "unlisted", + ]), + ), + ); + + entity = new VersiaEntities.URICollection({ + author: note.author.id, + total: replyCount, + items: replies.map((reply) => + reply.reference.toString(), + ), + }); + break; + } + case "quotes": { + const quotes = await Note.manyFromSql( + and( + eq(Notes.quotingId, note.id), + inArray(Notes.visibility, [ + "public", + "unlisted", + ]), + ), + undefined, + limit, + offset, + ); + + const quoteCount = await db.$count( + Notes, + and( + eq(Notes.quotingId, note.id), + inArray(Notes.visibility, [ + "public", + "unlisted", + ]), + ), + ); + + entity = new VersiaEntities.URICollection({ + author: note.author.id, + total: quoteCount, + items: quotes.map((quote) => + quote.reference.toString(), + ), + }); + break; + } + case "pub.versia:share/Shares": { + const shares = await Note.manyFromSql( + and( + eq(Notes.reblogId, note.id), + inArray(Notes.visibility, [ + "public", + "unlisted", + ]), + ), + undefined, + limit, + offset, + ); + + const shareCount = await db.$count( + Notes, + and( + eq(Notes.reblogId, note.id), + inArray(Notes.visibility, [ + "public", + "unlisted", + ]), + ), + ); + + entity = new VersiaEntities.URICollection({ + author: note.author.id, + total: shareCount, + items: shares.map((share) => + share.reference.toString(), + ), + }); + break; + } + } + break; + } + + case "User": { + const user = await User.fromId(id); + + if (!user || user.remote) { + throw ApiError.notFound(); + } + + switch (collection_type) { + case "outbox": { + const total = await db.$count( + Notes, + and( + eq(Notes.authorId, id), + inArray(Notes.visibility, [ + "public", + "unlisted", + ]), + ), + ); + + const outboxItems = await Note.manyFromSql( + and( + eq(Notes.authorId, id), + inArray(Notes.visibility, [ + "public", + "unlisted", + ]), + ), + undefined, + limit, + offset, + ); + + entity = new VersiaEntities.Collection({ + author: user.id, + total, + items: outboxItems.map((note) => + note.toVersia(), + ), + }); + break; + } + + case "followers": { + if (user.data.isHidingCollections) { + entity = new VersiaEntities.URICollection({ + author: user.id, + items: [], + total: 0, + }); + break; + } + + const total = await db.$count( + Users, + sql`EXISTS (SELECT 1 FROM "Relationships" WHERE "Relationships"."subjectId" = ${user.id} AND "Relationships"."ownerId" = ${Users.id} AND "Relationships"."following" = true)`, + ); + + const followers = await User.manyFromSql( + sql`EXISTS (SELECT 1 FROM "Relationships" WHERE "Relationships"."subjectId" = ${user.id} AND "Relationships"."ownerId" = ${Users.id} AND "Relationships"."following" = true)`, + undefined, + limit, + offset, + ); + + entity = new VersiaEntities.URICollection({ + author: user.id, + items: followers.map((follower) => + follower.reference.toString(), + ), + total, + }); + break; + } + + case "following": { + if (user.data.isHidingCollections) { + entity = new VersiaEntities.URICollection({ + author: user.id, + items: [], + total: 0, + }); + break; + } + + const total = await db.$count( + Users, + sql`EXISTS (SELECT 1 FROM "Relationships" WHERE "Relationships"."ownerId" = ${user.id} AND "Relationships"."subjectId" = ${Users.id} AND "Relationships"."following" = true)`, + ); + + const following = await User.manyFromSql( + sql`EXISTS (SELECT 1 FROM "Relationships" WHERE "Relationships"."ownerId" = ${user.id} AND "Relationships"."subjectId" = ${Users.id} AND "Relationships"."following" = true)`, + undefined, + limit, + offset, + ); + + entity = new VersiaEntities.URICollection({ + author: user.id, + items: following.map((followed) => + followed.reference.toString(), + ), + total, + }); + break; + } + + default: { + throw ApiError.notFound(); + } + } + break; + } + } + + if (!entity) { + throw ApiError.notFound(); + } + + const { headers } = await Instance.sign( + entity, + new URL(context.req.url), + "GET", + ); + + return context.json(entity, 200, headers.toJSON()); + }, + ), +); diff --git a/packages/api/routes/versia/v0.6/[entity_type]/[id]/index.ts b/packages/api/routes/versia/v0.6/[entity_type]/[id]/index.ts new file mode 100644 index 00000000..d8d45b01 --- /dev/null +++ b/packages/api/routes/versia/v0.6/[entity_type]/[id]/index.ts @@ -0,0 +1,178 @@ +import type * as VersiaEntities from "@versia/sdk/entities"; +import { + DislikeSchema, + EntitySchema, + LikeSchema, + NoteSchema, + ReactionSchema, + ShareSchema, + UserSchema, +} from "@versia/sdk/schemas"; +import { ApiError } from "@versia-server/kit"; +import { apiRoute, handleZodError } from "@versia-server/kit/api"; +import { Instance, Like, Note, Reaction, User } from "@versia-server/kit/db"; +import { Likes, Notes } from "@versia-server/kit/tables"; +import { and, eq, inArray, sql } from "drizzle-orm"; +import { describeRoute, resolver, validator } from "hono-openapi"; +import { z } from "zod"; + +export default apiRoute((app) => + app.get( + "/.versia/v0.6/entities/:entity_type/:id", + describeRoute({ + summary: "Retrieve the Versia representation of an entity.", + tags: ["Federation"], + responses: { + 200: { + description: "Entity", + content: { + "application/json": { + schema: resolver( + z.union([ + NoteSchema, + UserSchema, + LikeSchema, + DislikeSchema, + ReactionSchema, + ShareSchema, + ]), + ), + }, + }, + }, + 301: { + description: + "Redirect to user profile (for web browsers). Uses Accept header for detection.", + }, + 404: { + description: + "Entity not found, is remote, or the requester is not allowed to view it.", + content: { + "application/json": { + schema: resolver(ApiError.zodSchema), + }, + }, + }, + }, + }), + validator( + "param", + z.object({ + entity_type: EntitySchema.shape.type, + id: EntitySchema.shape.id, + }), + handleZodError, + ), + async (context) => { + const { entity_type, id } = context.req.valid("param"); + + let entity: + | VersiaEntities.Note + | VersiaEntities.User + | VersiaEntities.Like + | VersiaEntities.Dislike + | VersiaEntities.Reaction + | VersiaEntities.Share + | null = null; + + switch (entity_type) { + case "pub.versia:notes/Note": { + const note = await Note.fromSql( + and( + eq(Notes.id, id), + inArray(Notes.visibility, ["public", "unlisted"]), + ), + ); + + if ( + !(note && (await note.isViewableByUser(null))) || + note.remote + ) { + throw ApiError.noteNotFound(); + } + + entity = note.toVersia(); + break; + } + case "pub.versia:users/User": { + const user = await User.fromId(id); + + if (!user || user.remote) { + throw ApiError.accountNotFound(); + } + + entity = user.toVersia(); + break; + } + case "pub.versia:likes/Like": { + // Don't fetch a like of a note that is not public or unlisted + // prevents leaking the existence of a private note + const like = await Like.fromSql( + and( + eq(Likes.id, id), + sql`EXISTS (SELECT 1 FROM "Notes" WHERE "Notes"."id" = ${Likes.likedId} AND "Notes"."visibility" IN ('public', 'unlisted'))`, + ), + ); + + if (!like) { + throw ApiError.likeNotFound(); + } + + const liker = await User.fromId(like.data.likerId); + + if (!liker || liker.remote) { + throw ApiError.accountNotFound(); + } + + entity = like.toVersia(); + break; + } + case "pub.versia:likes/Dislike": { + // Versia Server does not support dislikes + throw ApiError.notFound(); + } + case "pub.versia:shares/Share": { + const note = await Note.fromSql( + and( + eq(Notes.id, id), + inArray(Notes.visibility, ["public", "unlisted"]), + ), + ); + + if ( + !(note && (await note.isViewableByUser(null))) || + note.remote || + !note.data.reblogId + ) { + throw ApiError.notFound(); + } + + entity = note.toVersiaShare(); + break; + } + case "pub.versia:reactions/Reaction": { + const reaction = await Reaction.fromId(id); + + if (!reaction) { + throw ApiError.notFound(); + } + + entity = reaction.toVersia(); + break; + } + } + + if (!entity) { + throw ApiError.notFound(); + } + + const { headers } = await Instance.sign( + entity, + new URL(context.req.url), + "GET", + ); + + return context.json(entity, 200, headers.toJSON()); + }, + ), +); diff --git a/packages/api/routes/inbox/index.test.ts b/packages/api/routes/versia/v0.6/inbox.test.ts similarity index 69% rename from packages/api/routes/inbox/index.test.ts rename to packages/api/routes/versia/v0.6/inbox.test.ts index 608c3c7e..b9c12a80 100644 --- a/packages/api/routes/inbox/index.test.ts +++ b/packages/api/routes/versia/v0.6/inbox.test.ts @@ -24,16 +24,13 @@ const userId = randomUUIDv7(); const shareId = randomUUIDv7(); const reactionId = randomUUIDv7(); const reaction2Id = randomUUIDv7(); -const userKeys = await User.generateKeys(); -const privateKey = await crypto.subtle.importKey( - "pkcs8", - Buffer.from(userKeys.private_key, "base64"), - "Ed25519", - false, - ["sign"], -); -const instanceKeys = await User.generateKeys(); -const inboxUrl = new URL("/inbox", config.http.base_url); + +const instanceKeys = await crypto.subtle.generateKey("Ed25519", true, [ + "sign", + "verify", +]); + +const inboxUrl = new URL("/.versia/v0.6/inbox", config.http.base_url); const { users, deleteUsers } = await getTestUsers(1); disableRealRequests(); @@ -48,24 +45,29 @@ mock(new URL("/.well-known/versia", instanceUrl).href, { name: "Versia", description: "Versia instance", created_at: new Date().toISOString(), - host: instanceUrl.hostname, + domain: instanceUrl.hostname, software: { name: "Versia", version: "1.0.0", }, compatibility: { extensions: [], - versions: ["0.5.0"], + versions: ["0.6.0"], }, public_key: { algorithm: "ed25519", - key: instanceKeys.public_key, + key: Buffer.from( + await crypto.subtle.exportKey( + "spki", + instanceKeys.publicKey, + ), + ).toString("base64"), }, }).toJSON(), }, }); -mock(new URL(`/users/${userId}`, instanceUrl).href, { +mock(new URL(`/.versia/v0.6/entities/User/${userId}`, instanceUrl).href, { response: { headers: { "Content-Type": "application/json", @@ -73,31 +75,18 @@ mock(new URL(`/users/${userId}`, instanceUrl).href, { data: new VersiaEntities.User({ id: userId, created_at: "2025-04-18T10:32:01.427Z", - uri: new URL(`/users/${userId}`, instanceUrl).href, type: "User", username: "testuser", - public_key: { - algorithm: "ed25519", - key: userKeys.public_key, - actor: new URL(`/users/${userId}`, instanceUrl).href, - }, - inbox: new URL(`/users/${userId}/inbox`, instanceUrl).href, - collections: { - featured: new URL(`/users/${userId}/featured`, instanceUrl) - .href, - followers: new URL(`/users/${userId}/followers`, instanceUrl) - .href, - following: new URL(`/users/${userId}/following`, instanceUrl) - .href, - outbox: new URL(`/users/${userId}/outbox`, instanceUrl).href, - }, + fields: [], + manually_approves_followers: false, + indexable: true, }).toJSON(), }, }); afterAll(async () => { // Delete the instance in database - const instance = await Instance.resolve(instanceUrl); + const instance = await Instance.resolve(instanceUrl.hostname); if (!instance) { throw new Error("Instance not found"); @@ -111,18 +100,18 @@ afterAll(async () => { describe("Inbox Tests", () => { test("should correctly process inbox request", async () => { - const exampleRequest = new VersiaEntities.Note({ + const exampleNote = new VersiaEntities.Note({ id: noteId, created_at: "2025-04-18T10:32:01.427Z", - uri: new URL(`/notes/${noteId}`, instanceUrl).href, type: "Note", extensions: { "pub.versia:custom_emojis": { emojis: [], }, }, + previews: [], attachments: [], - author: new URL(`/users/${userId}`, instanceUrl).href, + author: userId, content: { "text/html": { content: "

Hello!

", @@ -133,10 +122,6 @@ describe("Inbox Tests", () => { remote: false, }, }, - collections: { - replies: new URL(`/notes/${noteId}/replies`, instanceUrl).href, - quotes: new URL(`/notes/${noteId}/quotes`, instanceUrl).href, - }, group: "public", is_sensitive: false, mentions: [], @@ -146,16 +131,17 @@ describe("Inbox Tests", () => { }); const signedRequest = await sign( - privateKey, - new URL(exampleRequest.data.author), + instanceKeys.privateKey, + new URL(exampleNote.data.author), new Request(inboxUrl, { method: "POST", headers: { - "Content-Type": "application/json", - Accept: "application/json", + "Content-Type": + "application/vnd.versia+json; charset=utf-8", + Accept: "application/vnd.versia+json", "User-Agent": "Versia/1.0.0", }, - body: JSON.stringify(exampleRequest.toJSON()), + body: JSON.stringify(exampleNote.toJSON()), }), ); @@ -170,7 +156,9 @@ describe("Inbox Tests", () => { await sleep(500); // Check if note was created in the database - const note = await Note.fromSql(eq(Notes.uri, exampleRequest.data.uri)); + const note = await Note.fromSql( + eq(Notes.remoteId, exampleNote.data.id), + ); expect(note).not.toBeNull(); }); @@ -179,20 +167,20 @@ describe("Inbox Tests", () => { const exampleRequest = new VersiaEntities.Share({ id: shareId, created_at: "2025-04-18T10:32:01.427Z", - uri: new URL(`/shares/${shareId}`, instanceUrl).href, type: "pub.versia:share/Share", - author: new URL(`/users/${userId}`, instanceUrl).href, - shared: new URL(`/notes/${noteId}`, instanceUrl).href, + author: userId, + shared: noteId, }); const signedRequest = await sign( - privateKey, + instanceKeys.privateKey, new URL(exampleRequest.data.author), new Request(inboxUrl, { method: "POST", headers: { - "Content-Type": "application/json", - Accept: "application/json", + "Content-Type": + "application/vnd.versia+json; charset=utf-8", + Accept: "application/vnd.versia+json", "User-Agent": "Versia/1.0.0", }, body: JSON.stringify(exampleRequest.toJSON()), @@ -209,9 +197,7 @@ describe("Inbox Tests", () => { await sleep(500); - const dbNote = await Note.fromSql( - eq(Notes.uri, new URL(`/notes/${noteId}`, instanceUrl).href), - ); + const dbNote = await Note.fromSql(eq(Notes.remoteId, noteId)); if (!dbNote) { throw new Error("DBNote not found"); @@ -221,6 +207,7 @@ describe("Inbox Tests", () => { const share = await Note.fromSql( and( eq(Notes.reblogId, dbNote.id), + eq(Notes.remoteId, shareId), eq(Notes.authorId, dbNote.data.authorId), ), ); @@ -232,21 +219,21 @@ describe("Inbox Tests", () => { const exampleRequest = new VersiaEntities.Reaction({ id: reactionId, created_at: "2025-04-18T10:32:01.427Z", - uri: new URL(`/reactions/${reactionId}`, instanceUrl).href, type: "pub.versia:reactions/Reaction", - author: new URL(`/users/${userId}`, instanceUrl).href, - object: new URL(`/notes/${noteId}`, instanceUrl).href, + author: userId, + object: noteId, content: "👍", }); const signedRequest = await sign( - privateKey, + instanceKeys.privateKey, new URL(exampleRequest.data.author), new Request(inboxUrl, { method: "POST", headers: { - "Content-Type": "application/json", - Accept: "application/json", + "Content-Type": + "application/vnd.versia+json; charset=utf-8", + Accept: "application/vnd.versia+json", "User-Agent": "Versia/1.0.0", }, body: JSON.stringify(exampleRequest.toJSON()), @@ -263,18 +250,14 @@ describe("Inbox Tests", () => { await sleep(500); - const dbNote = await Note.fromSql( - eq(Notes.uri, new URL(`/notes/${noteId}`, instanceUrl).href), - ); + const dbNote = await Note.fromSql(eq(Notes.remoteId, noteId)); if (!dbNote) { throw new Error("DBNote not found"); } // Find the remote user who reacted by URI - const remoteUser = await User.fromSql( - eq(Users.uri, new URL(`/users/${userId}`, instanceUrl).href), - ); + const remoteUser = await User.fromSql(eq(Users.remoteId, userId)); if (!remoteUser) { throw new Error("Remote user not found"); @@ -311,10 +294,9 @@ describe("Inbox Tests", () => { const exampleRequest = new VersiaEntities.Reaction({ id: reaction2Id, created_at: "2025-04-18T10:32:01.427Z", - uri: new URL(`/reactions/${reaction2Id}`, instanceUrl).href, type: "pub.versia:reactions/Reaction", - author: new URL(`/users/${userId}`, instanceUrl).href, - object: new URL(`/notes/${noteId}`, instanceUrl).href, + author: userId, + object: noteId, content: ":neocat:", extensions: { "pub.versia:custom_emojis": { @@ -323,9 +305,7 @@ describe("Inbox Tests", () => { name: ":neocat:", url: { "image/webp": { - hash: { - sha256: "e06240155d2cb90e8dc05327d023585ab9d47216ff547ad72aaf75c485fe9649", - }, + hash: "e06240155d2cb90e8dc05327d023585ab9d47216ff547ad72aaf75c485fe9649", size: 4664, width: 256, height: 256, @@ -341,13 +321,14 @@ describe("Inbox Tests", () => { }); const signedRequest = await sign( - privateKey, + instanceKeys.privateKey, new URL(exampleRequest.data.author), new Request(inboxUrl, { method: "POST", headers: { - "Content-Type": "application/json", - Accept: "application/json", + "Content-Type": + "application/vnd.versia+json; charset=utf-8", + Accept: "application/vnd.versia+json", "User-Agent": "Versia/1.0.0", }, body: JSON.stringify(exampleRequest.toJSON()), @@ -364,18 +345,14 @@ describe("Inbox Tests", () => { await sleep(500); - const dbNote = await Note.fromSql( - eq(Notes.uri, new URL(`/notes/${noteId}`, instanceUrl).href), - ); + const dbNote = await Note.fromSql(eq(Notes.remoteId, noteId)); if (!dbNote) { throw new Error("DBNote not found"); } // Find the remote user who reacted by URI - const remoteUser = await User.fromSql( - eq(Users.uri, new URL(`/users/${userId}`, instanceUrl).href), - ); + const remoteUser = await User.fromSql(eq(Users.remoteId, userId)); if (!remoteUser) { throw new Error("Remote user not found"); @@ -409,36 +386,29 @@ describe("Inbox Tests", () => { }); test("should correctly process Delete", async () => { - const deleteId = randomUUIDv7(); - // First check that the note exists in the database - const noteToDelete = await Note.fromSql( - eq(Notes.uri, new URL(`/notes/${noteId}`, instanceUrl).href), - ); + const noteToDelete = await Note.fromSql(eq(Notes.remoteId, noteId)); expect(noteToDelete).not.toBeNull(); // Create a Delete request const exampleRequest = new VersiaEntities.Delete({ - id: deleteId, created_at: new Date().toISOString(), type: "Delete", - author: new URL(`/users/${userId}`, instanceUrl).href, + author: userId, deleted_type: "Note", - deleted: new URL(`/notes/${noteId}`, instanceUrl).href, + deleted: noteId, }); - // The author field is non-null in our test case, so we can safely assert it as a string - const authorUrl = exampleRequest.data.author as string; - const signedRequest = await sign( - privateKey, - new URL(authorUrl), + instanceKeys.privateKey, + new URL(exampleRequest.data.author), new Request(inboxUrl, { method: "POST", headers: { - "Content-Type": "application/json", - Accept: "application/json", + "Content-Type": + "application/vnd.versia+json; charset=utf-8", + Accept: "application/vnd.versia+json", "User-Agent": "Versia/1.0.0", }, body: JSON.stringify(exampleRequest.toJSON()), @@ -456,9 +426,7 @@ describe("Inbox Tests", () => { await sleep(500); // Verify that the note was deleted from the database - const noteExists = await Note.fromSql( - eq(Notes.uri, new URL(`/notes/${noteId}`, instanceUrl).href), - ); + const noteExists = await Note.fromSql(eq(Notes.remoteId, noteId)); expect(noteExists).toBeNull(); }); diff --git a/packages/api/routes/inbox/index.ts b/packages/api/routes/versia/v0.6/inbox.ts similarity index 78% rename from packages/api/routes/inbox/index.ts rename to packages/api/routes/versia/v0.6/inbox.ts index 98fd4182..c642b3d5 100644 --- a/packages/api/routes/inbox/index.ts +++ b/packages/api/routes/versia/v0.6/inbox.ts @@ -1,13 +1,13 @@ import { apiRoute, handleZodError } from "@versia-server/kit/api"; -import { InboxJobType, inboxQueue } from "@versia-server/kit/queues/inbox"; import { describeRoute, validator } from "hono-openapi"; -import { z } from "zod"; +import z from "zod"; +import { InboxJobType, inboxQueue } from "~/packages/kit/queues/inbox/queue"; export default apiRoute((app) => - app.post( - "/inbox", + app.get( + "/.versia/v0.6/inbox", describeRoute({ - summary: "Instance federation inbox", + summary: "Instance inbox endpoint", tags: ["Federation"], responses: { 200: { @@ -18,12 +18,9 @@ export default apiRoute((app) => validator( "header", z.object({ - "versia-signature": z.string().optional(), - "versia-signed-at": z.coerce.number().optional(), - "versia-signed-by": z - .url() - .or(z.string().startsWith("instance ")) - .optional(), + "versia-signature": z.string(), + "versia-signed-at": z.coerce.number(), + "versia-signed-by": z.string(), authorization: z.string().optional(), }), handleZodError, diff --git a/packages/api/routes/versia/v0.6/instance.ts b/packages/api/routes/versia/v0.6/instance.ts new file mode 100644 index 00000000..c5e9ae44 --- /dev/null +++ b/packages/api/routes/versia/v0.6/instance.ts @@ -0,0 +1,88 @@ +import { + type ImageContentFormatSchema, + InstanceMetadataSchema, +} from "@versia/sdk/schemas"; +import { config } from "@versia-server/config"; +import { apiRoute } from "@versia-server/kit/api"; +import { User } from "@versia-server/kit/db"; +import { Users } from "@versia-server/kit/tables"; +import { asc } from "drizzle-orm"; +import { describeRoute, resolver } from "hono-openapi"; +import type z from "zod"; +import { urlToContentFormat } from "@/content_types"; +import pkg from "../../../../../package.json" with { type: "json" }; + +export default apiRoute((app) => + app.get( + "/.versia/v0.6/instance", + describeRoute({ + summary: "Get instance metadata", + tags: ["Federation"], + responses: { + 200: { + description: "Instance metadata", + content: { + "application/json": { + schema: resolver(InstanceMetadataSchema), + }, + }, + }, + }, + }), + async (context) => { + // Get date of first user creation + const firstUser = await User.fromSql( + undefined, + asc(Users.createdAt), + ); + + const publicKey = Buffer.from( + await crypto.subtle.exportKey( + "spki", + config.instance.keys.public, + ), + ).toString("base64"); + + return context.json( + { + type: "InstanceMetadata" as const, + compatibility: { + extensions: [ + "pub.versia:custom_emojis", + "pub.versia:instance_messaging", + "pub.versia:likes", + "pub.versia:shares", + "pub.versia:reactions", + ], + versions: ["0.6.0"], + }, + domain: config.http.base_url.hostname, + name: config.instance.name, + description: config.instance.description, + public_key: { + key: publicKey, + algorithm: "ed25519" as const, + }, + software: { + name: "Versia Server", + version: pkg.version, + }, + banner: config.instance.branding.banner + ? (urlToContentFormat( + config.instance.branding.banner, + ) as z.infer) + : undefined, + logo: config.instance.branding.logo + ? (urlToContentFormat( + config.instance.branding.logo, + ) as z.infer) + : undefined, + created_at: + firstUser?.data.createdAt.toISOString() || + "1970-01-01T00:00:00Z", + } satisfies z.infer, + 200, + ); + }, + ), +); diff --git a/packages/api/routes/well-known/versia.ts b/packages/api/routes/well-known/versia.ts index ea221c96..e836ca82 100644 --- a/packages/api/routes/well-known/versia.ts +++ b/packages/api/routes/well-known/versia.ts @@ -1,87 +1,32 @@ -import { InstanceMetadataSchema } from "@versia/sdk/schemas"; -import { config } from "@versia-server/config"; import { apiRoute } from "@versia-server/kit/api"; -import { User } from "@versia-server/kit/db"; -import { Users } from "@versia-server/kit/tables"; -import { asc } from "drizzle-orm"; import { describeRoute, resolver } from "hono-openapi"; -import { urlToContentFormat } from "@/content_types"; -import pkg from "../../../../package.json" with { type: "json" }; +import z from "zod"; export default apiRoute((app) => app.get( "/.well-known/versia", describeRoute({ - summary: "Get instance metadata", + summary: "Get supported versia protocol versions", tags: ["Federation"], responses: { 200: { description: "Instance metadata", content: { "application/json": { - schema: resolver(InstanceMetadataSchema), + schema: resolver( + z.strictObject({ + versions: z.array(z.string().min(1)), + }), + ), }, }, }, }, }), - async (context) => { - // Get date of first user creation - const firstUser = await User.fromSql( - undefined, - asc(Users.createdAt), - ); - - const publicKey = Buffer.from( - await crypto.subtle.exportKey( - "spki", - config.instance.keys.public, - ), - ).toString("base64"); - + (context) => { return context.json( { - type: "InstanceMetadata" as const, - compatibility: { - extensions: [ - "pub.versia:custom_emojis", - "pub.versia:instance_messaging", - "pub.versia:likes", - "pub.versia:shares", - "pub.versia:reactions", - ], - versions: ["0.5.0"], - }, - host: config.http.base_url.host, - name: config.instance.name, - description: config.instance.description, - public_key: { - key: publicKey, - algorithm: "ed25519" as const, - }, - software: { - name: "Versia Server", - version: pkg.version, - }, - banner: config.instance.branding.banner - ? urlToContentFormat(config.instance.branding.banner) - : undefined, - logo: config.instance.branding.logo - ? urlToContentFormat(config.instance.branding.logo) - : undefined, - shared_inbox: new URL( - "/inbox", - config.http.base_url, - ).toString(), - created_at: firstUser?.data.createdAt.toISOString(), - extensions: { - "pub.versia:instance_messaging": { - endpoint: new URL( - "/messaging", - config.http.base_url, - ).toString(), - }, - }, + versions: ["0.6.0"], }, 200, ); diff --git a/packages/kit/db/instance.ts b/packages/kit/db/instance.ts index c064a5b0..a524c1c7 100644 --- a/packages/kit/db/instance.ts +++ b/packages/kit/db/instance.ts @@ -1,3 +1,4 @@ +import { sign } from "@versia/sdk/crypto"; import * as VersiaEntities from "@versia/sdk/entities"; import { FederationRequester } from "@versia/sdk/http"; import { config } from "@versia-server/config"; @@ -15,6 +16,7 @@ import { inArray, type SQL, } from "drizzle-orm"; +import type { HttpVerb, KnownEntity } from "~/types/api.ts"; import { ApiError } from "../api-error.ts"; import { db } from "../tables/db.ts"; import { Instances } from "../tables/schema.ts"; @@ -111,6 +113,13 @@ export class Instance extends BaseInterface { } } + public static get federationRequester(): FederationRequester { + return new FederationRequester( + config.instance.keys.private, + config.http.base_url, + ); + } + public static async fromUser(user: User): Promise { if (!user.data.instanceId) { return null; @@ -139,29 +148,24 @@ export class Instance extends BaseInterface { return this.data.id; } - public static async fetchMetadata(url: URL): Promise<{ + public static async fetchMetadata(domain: string): Promise<{ metadata: VersiaEntities.InstanceMetadata; protocol: "versia" | "activitypub"; }> { - const origin = new URL(url).origin; - const wellKnownUrl = new URL("/.well-known/versia", origin); - try { - const metadata = await new FederationRequester( - config.instance.keys.private, - config.http.base_url, - ).fetchEntity(wellKnownUrl, VersiaEntities.InstanceMetadata); + const metadata = + await Instance.federationRequester.resolveInstance(domain); return { metadata, protocol: "versia" }; } catch { // If the server doesn't have a Versia well-known endpoint, it's not a Versia instance // Try to resolve ActivityPub metadata instead - const data = await Instance.fetchActivityPubMetadata(url); + const data = await Instance.fetchActivityPubMetadata(domain); if (!data) { throw new ApiError( 404, - `Instance at ${origin} is not reachable or does not exist`, + `Instance at ${domain} is not reachable or does not exist`, ); } @@ -173,9 +177,9 @@ export class Instance extends BaseInterface { } private static async fetchActivityPubMetadata( - url: URL, + domain: string, ): Promise { - const origin = new URL(url).origin; + const origin = new URL(`https://${domain}`); const wellKnownUrl = new URL("/.well-known/nodeinfo", origin); // Go to endpoint, then follow the links to the actual metadata @@ -254,7 +258,7 @@ export class Instance extends BaseInterface { key: "", algorithm: "ed25519", }, - host: new URL(url).host, + domain: origin.hostname, compatibility: { extensions: [], versions: [], @@ -268,50 +272,33 @@ export class Instance extends BaseInterface { } } - public static resolveFromHost(host: string): Promise { - if (host.startsWith("http")) { - const url = new URL(host); - - return Instance.resolve(url); - } - - const url = new URL(`https://${host}`); - - return Instance.resolve(url); - } - - public static async resolve(url: URL): Promise { - const host = url.host; - + public static async resolve(domain: string): Promise { const existingInstance = await Instance.fromSql( - eq(Instances.baseUrl, host), + eq(Instances.baseUrl, domain), ); if (existingInstance) { return existingInstance; } - const output = await Instance.fetchMetadata(url); + const output = await Instance.fetchMetadata(domain); const { metadata, protocol } = output; return Instance.insert({ id: randomUUIDv7(), - baseUrl: host, + baseUrl: domain, name: metadata.data.name, version: metadata.data.software.version, logo: metadata.data.logo, protocol, publicKey: metadata.data.public_key, - inbox: metadata.data.shared_inbox ?? null, extensions: metadata.data.extensions ?? null, }); } public async updateFromRemote(): Promise { - const output = await Instance.fetchMetadata( - new URL(`https://${this.data.baseUrl}`), - ); + const output = await Instance.fetchMetadata(this.data.baseUrl); if (!output) { federationResolversLogger.error`Failed to update instance ${chalk.bold( @@ -328,13 +315,39 @@ export class Instance extends BaseInterface { logo: metadata.data.logo, protocol, publicKey: metadata.data.public_key, - inbox: metadata.data.shared_inbox ?? null, extensions: metadata.data.extensions ?? null, }); return this; } + /** + * Signs a Versia entity with this instance's private key + * + * @param entity Entity to sign + * @param signatureUrl URL to embed in signature (must be the same URI of queries made with this signature) + * @param signatureMethod HTTP method to embed in signature (default: POST) + * @returns The signed string and headers to send with the request + */ + public static async sign( + entity: KnownEntity | VersiaEntities.Collection, + signatureUrl: URL, + signatureMethod: HttpVerb = "POST", + ): Promise<{ + headers: Headers; + }> { + const { headers } = await sign( + config.instance.keys.private, + config.http.base_url, + new Request(signatureUrl, { + method: signatureMethod, + body: JSON.stringify(entity), + }), + ); + + return { headers }; + } + public async sendMessage(content: string): Promise { if ( !this.data.extensions?.["pub.versia:instance_messaging"]?.endpoint diff --git a/packages/kit/db/like.ts b/packages/kit/db/like.ts index 647415a0..ad6effa8 100644 --- a/packages/kit/db/like.ts +++ b/packages/kit/db/like.ts @@ -11,17 +11,22 @@ import { } from "drizzle-orm"; import { db } from "../tables/db.ts"; import { + type Instances, Likes, type Notes, Notifications, type Users, } from "../tables/schema.ts"; import { BaseInterface } from "./base.ts"; -import { User } from "./user.ts"; +import type { User } from "./user.ts"; type LikeType = InferSelectModel & { liker: InferSelectModel; - liked: InferSelectModel; + liked: InferSelectModel & { + author: InferSelectModel & { + instance: InferSelectModel | null; + }; + }; }; export class Like extends BaseInterface { @@ -57,7 +62,15 @@ export class Like extends BaseInterface { where: sql, orderBy, with: { - liked: true, + liked: { + with: { + author: { + with: { + instance: true, + }, + }, + }, + }, liker: true, }, }); @@ -65,6 +78,7 @@ export class Like extends BaseInterface { if (!found) { return null; } + return new Like(found); } @@ -73,7 +87,6 @@ export class Like extends BaseInterface { orderBy: SQL | undefined = desc(Likes.id), limit?: number, offset?: number, - extra?: Parameters[0], ): Promise { const found = await db.query.Likes.findMany({ where: sql, @@ -81,9 +94,16 @@ export class Like extends BaseInterface { limit, offset, with: { - liked: true, + liked: { + with: { + author: { + with: { + instance: true, + }, + }, + }, + }, liker: true, - ...extra?.with, }, }); @@ -146,37 +166,28 @@ export class Like extends BaseInterface { } public toVersia(): VersiaEntities.Like { + let likedReference = this.data.liked.id; + + if (this.data.liked.author.instance) { + likedReference = `${this.data.liked.author.instance.baseUrl}:${this.data.liked.remoteId}`; + } + return new VersiaEntities.Like({ - id: this.data.id, - author: User.getUri( - this.data.liker.id, - this.data.liker.uri ? new URL(this.data.liker.uri) : null, - ).href, + id: this.id, + author: this.data.liker.id, type: "pub.versia:likes/Like", created_at: this.data.createdAt.toISOString(), - liked: this.data.liked.uri - ? new URL(this.data.liked.uri).href - : new URL(`/notes/${this.data.liked.id}`, config.http.base_url) - .href, - uri: this.getUri().href, + liked: likedReference, }); } public unlikeToVersia(unliker?: User): VersiaEntities.Delete { return new VersiaEntities.Delete({ type: "Delete", - id: crypto.randomUUID(), created_at: new Date().toISOString(), - author: User.getUri( - unliker?.id ?? this.data.liker.id, - unliker?.data.uri - ? new URL(unliker.data.uri) - : this.data.liker.uri - ? new URL(this.data.liker.uri) - : null, - ).href, + author: unliker ? unliker.id : this.data.liker.id, deleted_type: "pub.versia:likes/Like", - deleted: this.getUri().href, + deleted: this.id, }); } } diff --git a/packages/kit/db/media.ts b/packages/kit/db/media.ts index b5f7e4b3..4c54a18d 100644 --- a/packages/kit/db/media.ts +++ b/packages/kit/db/media.ts @@ -476,9 +476,7 @@ export class Media extends BaseInterface { [file.type]: { content: uri.toString(), remote: true, - hash: { - sha256: hash, - }, + hash, width, height, description: options?.description, diff --git a/packages/kit/db/note.ts b/packages/kit/db/note.ts index 24b344ab..2c56f4c7 100644 --- a/packages/kit/db/note.ts +++ b/packages/kit/db/note.ts @@ -3,7 +3,6 @@ import type { Status as StatusSchema, } from "@versia/client/schemas"; import * as VersiaEntities from "@versia/sdk/entities"; -import { FederationRequester } from "@versia/sdk/http"; import type { NonTextContentFormatSchema } from "@versia/sdk/schemas"; import { config } from "@versia-server/config"; import { randomUUIDv7 } from "bun"; @@ -25,7 +24,6 @@ import { mergeAndDeduplicate } from "@/lib.ts"; import { sanitizedHtmlStrip } from "@/sanitization"; import { versiaTextToHtml } from "../parsers.ts"; import { DeliveryJobType, deliveryQueue } from "../queues/delivery/queue.ts"; -import { uuid } from "../regex.ts"; import { db } from "../tables/db.ts"; import { EmojiToNote, @@ -166,8 +164,24 @@ const findManyNotes = async ( : sql`false`.as("liked"), }, }, - reply: true, - quote: true, + reply: { + with: { + author: { + with: { + instance: true, + }, + }, + }, + }, + quote: { + with: { + author: { + with: { + instance: true, + }, + }, + }, + }, }, extras: { pinned: userId @@ -197,19 +211,13 @@ const findManyNotes = async ( return output.map((post) => ({ ...post, author: transformOutputToUserWithRelations(post.author), - mentions: post.mentions.map((mention) => ({ - ...mention.user, - endpoints: mention.user.endpoints, - })), + mentions: post.mentions.map((mention) => mention.user), attachments: post.attachments.map((attachment) => attachment.media), emojis: (post.emojis ?? []).map((emoji) => emoji.emoji), reblog: post.reblog && { ...post.reblog, author: transformOutputToUserWithRelations(post.reblog.author), - mentions: post.reblog.mentions.map((mention) => ({ - ...mention.user, - endpoints: mention.user.endpoints, - })), + mentions: post.reblog.mentions.map((mention) => mention.user), attachments: post.reblog.attachments.map( (attachment) => attachment.media, ), @@ -236,8 +244,20 @@ type NoteTypeWithRelations = NoteType & { attachments: (typeof Media.$type)[]; reblog: NoteTypeWithoutRecursiveRelations | null; emojis: (typeof Emoji.$type)[]; - reply: NoteType | null; - quote: NoteType | null; + reply: + | (NoteType & { + author: InferSelectModel & { + instance: typeof Instance.$type | null; + }; + }) + | null; + quote: + | (NoteType & { + author: InferSelectModel & { + instance: typeof Instance.$type | null; + }; + }) + | null; client: typeof Client.$type | null; pinned: boolean; reblogged: boolean; @@ -404,6 +424,17 @@ export class Note extends BaseInterface { return this.data.id; } + public get reference(): VersiaEntities.Reference { + if (this.remote) { + const instanceUrl = new URL( + this.author.data.instance?.baseUrl || "", + ); + return new VersiaEntities.Reference(this.id, instanceUrl.hostname); + } + + return new VersiaEntities.Reference(this.id); + } + public async federateToUsers(): Promise { const users = await this.getUsersToFederateTo(); @@ -489,13 +520,13 @@ export class Note extends BaseInterface { * If the note is already reblogged, it will return the existing reblog. Also creates a notification for the author of the note. * @param reblogger The user reblogging the note * @param visibility The visibility of the reblog - * @param uri The URI of the reblog, if it is remote + * @param remoteId The remote ID of the reblog, if it is from a remote user * @returns The reblog object created or the existing reblog */ public async reblog( reblogger: User, visibility: z.infer, - uri?: URL, + remoteId?: string, ): Promise { const existingReblog = await Note.fromSql( and(eq(Notes.authorId, reblogger.id), eq(Notes.reblogId, this.id)), @@ -515,7 +546,7 @@ export class Note extends BaseInterface { sensitive: false, updatedAt: new Date(), clientId: null, - uri: uri?.href, + remoteId, }); await this.recalculateReblogCount(); @@ -612,10 +643,10 @@ export class Note extends BaseInterface { * * If the note is already liked, it will return the existing like. Also creates a notification for the author of the note. * @param liker The user liking the note - * @param uri The URI of the like, if it is remote + * @param remoteId The id of the like, if it is remote * @returns The like object created or the existing like */ - public async like(liker: User, uri?: URL): Promise { + public async like(liker: User, remoteId?: string): Promise { // Check if the user has already liked the note const existingLike = await Like.fromSql( and(eq(Likes.likerId, liker.id), eq(Likes.likedId, this.id)), @@ -629,7 +660,7 @@ export class Note extends BaseInterface { id: randomUUIDv7(), likerId: liker.id, likedId: this.id, - uri: uri?.href, + remoteId, }); await this.recalculateLikeCount(); @@ -904,73 +935,84 @@ export class Note extends BaseInterface { } /** - * Resolve a note from a URI - * @param uri - The URI of the note to resolve + * Resolve a note from a reference + * @param reference - The URI of the note to resolve * @returns The resolved note */ - public static async resolve(uri: URL): Promise { + public static async resolve( + reference: VersiaEntities.Reference, + ): Promise { // Check if note not already in database - const foundNote = await Note.fromSql(eq(Notes.uri, uri.href)); + if ( + !reference.domain || + reference.domain === config.http.base_url.hostname + ) { + return await Note.fromId(reference.id); + } + + const instance = await Instance.resolve(reference.domain); + + if (!instance) { + return null; + } + + const foundNote = await Note.fromSql( + and( + eq(Notes.remoteId, reference.id), + eq( + Notes.authorId, + sql`( + SELECT "Users".id FROM "Users" + WHERE "Users".instanceId = ${instance.id} + LIMIT 1 + )`, + ), + ), + ); if (foundNote) { return foundNote; } - // Check if URI is of a local note - if (uri.origin === config.http.base_url.origin) { - const noteUuid = uri.pathname.match(uuid); - - if (!noteUuid?.[0]) { - throw new Error( - `URI ${uri} is of a local note, but it could not be parsed`, - ); - } - - return await Note.fromId(noteUuid[0]); - } - - return Note.fromVersia(uri); + return Note.fromVersia(reference); } /** * Takes a Versia Note representation, and serializes it to the database. * * If the note already exists, it will update it. - * @param versiaNote - URL or Versia Note representation + * @param versiaNote - Reference or Versia Note representation */ public static async fromVersia( - versiaNote: VersiaEntities.Note | URL, + versiaNote: VersiaEntities.Note | VersiaEntities.Reference, ): Promise { - if (versiaNote instanceof URL) { + if (versiaNote instanceof VersiaEntities.Reference) { // No bridge support for notes yet - const note = await new FederationRequester( - config.instance.keys.private, - config.http.base_url, - ).fetchEntity(versiaNote, VersiaEntities.Note); + const note = await Instance.federationRequester.fetchEntity( + versiaNote, + VersiaEntities.Note, + ); return Note.fromVersia(note); } - const { - author: authorUrl, - created_at, - uri, - extensions, - group, - is_sensitive, - mentions: noteMentions, - quotes, - replies_to, - subject, - } = versiaNote.data; - const instance = await Instance.resolve(new URL(authorUrl)); - const author = await User.resolve(new URL(authorUrl)); + const { created_at, extensions, group, id, is_sensitive, subject } = + versiaNote.data; + + if (!versiaNote.author.domain) { + throw new Error("Entity author domain is missing"); + } + + const instance = await Instance.resolve(versiaNote.author.domain); + const author = await User.resolve(versiaNote.author); if (!author) { throw new Error("Entity author could not be resolved"); } - const existingNote = await Note.fromSql(eq(Notes.uri, uri)); + const existingNote = await Note.fromSql( + and(eq(Notes.remoteId, id), eq(Notes.authorId, author.id)), + ); const note = existingNote ?? @@ -978,7 +1020,7 @@ export class Note extends BaseInterface { id: randomUUIDv7(), authorId: author.id, visibility: "public", - uri, + remoteId: id, createdAt: new Date(created_at), })); @@ -999,9 +1041,7 @@ export class Note extends BaseInterface { const mentions = ( await Promise.all( - noteMentions?.map((mention) => - User.resolve(new URL(mention)), - ) ?? [], + versiaNote.mentions.map((m) => User.resolve(m)) ?? [], ) ).filter((m) => m !== null); @@ -1011,10 +1051,12 @@ export class Note extends BaseInterface { ? "direct" : (group as "public" | "followers" | "unlisted"); - const reply = replies_to - ? await Note.resolve(new URL(replies_to)) + const reply = versiaNote.repliesTo + ? await Note.resolve(versiaNote.repliesTo) + : null; + const quote = versiaNote.quotes + ? await Note.resolve(versiaNote.quotes) : null; - const quote = quotes ? await Note.resolve(new URL(quotes)) : null; const spoiler = subject ? await sanitizedHtmlStrip(subject) : undefined; await note.update({ @@ -1169,9 +1211,11 @@ export class Note extends BaseInterface { mention.username, mention.instance?.baseUrl, ), - url: User.getUri( - mention.id, - mention.uri ? new URL(mention.uri) : null, + url: new URL( + `/@${mention.username}${ + mention.instance ? `@${mention.instance.baseUrl}` : "" + }`, + config.http.base_url, ).toString(), username: mention.username, })), @@ -1191,9 +1235,9 @@ export class Note extends BaseInterface { sensitive: data.sensitive, spoiler_text: data.spoilerText, tags: [], - uri: data.uri || this.getUri().toString(), + uri: this.getUri().toString(), visibility: data.visibility, - url: data.uri || this.getMastoUri().toString(), + url: this.getMastoUri().toString(), bookmarked: false, quote: data.quotingId ? ((await Note.fromId(data.quotingId, userFetching?.id).then( @@ -1207,9 +1251,14 @@ export class Note extends BaseInterface { } public getUri(): URL { - return this.data.uri - ? new URL(this.data.uri) - : new URL(`/notes/${this.id}`, config.http.base_url); + const domain = this.author.data.instance?.baseUrl + ? new URL(`https://${this.author.data.instance.baseUrl}`) + : config.http.base_url; + + return new URL( + `/.versia/v0.6/entities/Note/${this.id}`, + `https://${domain}`, + ); } /** @@ -1224,14 +1273,11 @@ export class Note extends BaseInterface { } public deleteToVersia(): VersiaEntities.Delete { - const id = crypto.randomUUID(); - return new VersiaEntities.Delete({ type: "Delete", - id, - author: this.author.uri.href, + author: this.author.id, deleted_type: "Note", - deleted: this.getUri().href, + deleted: this.id, created_at: new Date().toISOString(), }); } @@ -1242,12 +1288,24 @@ export class Note extends BaseInterface { */ public toVersia(): VersiaEntities.Note { const status = this.data; + + let quoteReference = status.quote?.id ?? null; + + if (quoteReference && status.quote?.author.instance) { + quoteReference = `${status.quote.author.instance.baseUrl}:${status.quote.remoteId}`; + } + + let replyReference = status.reply?.id ?? null; + + if (replyReference && status.reply?.author.instance) { + replyReference = `${status.reply.author.instance.baseUrl}:${status.reply.remoteId}`; + } + return new VersiaEntities.Note({ type: "Note", created_at: status.createdAt.toISOString(), id: status.id, - author: this.author.uri.href, - uri: this.getUri().href, + author: this.author.id, content: { "text/html": { content: status.content, @@ -1258,20 +1316,7 @@ export class Note extends BaseInterface { remote: false, }, }, - collections: { - replies: new URL( - `/notes/${status.id}/replies`, - config.http.base_url, - ).href, - quotes: new URL( - `/notes/${status.id}/quotes`, - config.http.base_url, - ).href, - "pub.versia:share/Shares": new URL( - `/notes/${status.id}/shares`, - config.http.base_url, - ).href, - }, + previews: [], attachments: status.attachments.map( (attachment) => new Media(attachment).toVersia().data as z.infer< @@ -1279,25 +1324,13 @@ export class Note extends BaseInterface { >, ), is_sensitive: status.sensitive, - mentions: status.mentions.map( - (mention) => - User.getUri( - mention.id, - mention.uri ? new URL(mention.uri) : null, - ).href, + mentions: status.mentions.map((mention) => + mention.instance + ? `${mention.instance.baseUrl}:${mention.id}` + : mention.id, ), - quotes: status.quote - ? status.quote.uri - ? new URL(status.quote.uri).href - : new URL(`/notes/${status.quote.id}`, config.http.base_url) - .href - : null, - replies_to: status.reply - ? status.reply.uri - ? new URL(status.reply.uri).href - : new URL(`/notes/${status.reply.id}`, config.http.base_url) - .href - : null, + quotes: quoteReference, + replies_to: replyReference, subject: status.spoilerText, // TODO: Refactor as part of groups group: status.visibility === "public" ? "public" : "followers", @@ -1319,26 +1352,22 @@ export class Note extends BaseInterface { return new VersiaEntities.Share({ type: "pub.versia:share/Share", - id: crypto.randomUUID(), - author: this.author.uri.href, - uri: new URL(`/shares/${this.id}`, config.http.base_url).href, + author: this.author.id, + id: this.id, created_at: new Date().toISOString(), - shared: new Note(this.data.reblog as NoteTypeWithRelations).getUri() - .href, + shared: this.data.reblog.author.instance + ? `${this.data.reblog.author.instance.baseUrl}:${this.data.reblog.id}` + : this.data.reblog.id, }); } public toVersiaUnshare(): VersiaEntities.Delete { return new VersiaEntities.Delete({ type: "Delete", - id: crypto.randomUUID(), created_at: new Date().toISOString(), - author: User.getUri( - this.data.authorId, - this.data.author.uri ? new URL(this.data.author.uri) : null, - ).href, + author: this.author.id, deleted_type: "pub.versia:share/Share", - deleted: new URL(`/shares/${this.id}`, config.http.base_url).href, + deleted: this.id, }); } diff --git a/packages/kit/db/reaction.ts b/packages/kit/db/reaction.ts index d193371c..662ae967 100644 --- a/packages/kit/db/reaction.ts +++ b/packages/kit/db/reaction.ts @@ -1,5 +1,4 @@ import * as VersiaEntities from "@versia/sdk/entities"; -import { config } from "@versia-server/config"; import { randomUUIDv7 } from "bun"; import { and, @@ -12,17 +11,26 @@ import { type SQL, } from "drizzle-orm"; import { db } from "../tables/db.ts"; -import { type Notes, Reactions, type Users } from "../tables/schema.ts"; +import { + type Instances, + type Notes, + Reactions, + type Users, +} from "../tables/schema.ts"; import { BaseInterface } from "./base.ts"; import { Emoji } from "./emoji.ts"; import { Instance } from "./instance.ts"; import type { Note } from "./note.ts"; -import { User } from "./user.ts"; +import type { User } from "./user.ts"; type ReactionType = InferSelectModel & { emoji: typeof Emoji.$type | null; author: InferSelectModel; - note: InferSelectModel; + note: InferSelectModel & { + author: InferSelectModel & { + instance: InferSelectModel | null; + }; + }; }; export class Reaction extends BaseInterface { @@ -64,7 +72,15 @@ export class Reaction extends BaseInterface { }, }, author: true, - note: true, + note: { + with: { + author: { + with: { + instance: true, + }, + }, + }, + }, }, orderBy, }); @@ -96,7 +112,15 @@ export class Reaction extends BaseInterface { }, }, author: true, - note: true, + note: { + with: { + author: { + with: { + instance: true, + }, + }, + }, + }, }, }); @@ -210,19 +234,18 @@ export class Reaction extends BaseInterface { throw new Error("Cannot convert a non-local reaction to Versia"); } + let noteReference = this.data.note.id; + + if (this.data.note.author.instance) { + noteReference = `${this.data.note.author.instance.baseUrl}:${this.data.note.remoteId}`; + } + return new VersiaEntities.Reaction({ - uri: this.getUri(config.http.base_url).href, type: "pub.versia:reactions/Reaction", - author: User.getUri( - this.data.authorId, - this.data.author.uri ? new URL(this.data.author.uri) : null, - ).href, + author: this.data.author.id, created_at: this.data.createdAt.toISOString(), id: this.id, - object: this.data.note.uri - ? new URL(this.data.note.uri).href - : new URL(`/notes/${this.data.noteId}`, config.http.base_url) - .href, + object: noteReference, content: this.hasCustomEmoji() ? `:${this.data.emoji?.shortcode}:` : this.data.emojiText || "", @@ -243,14 +266,10 @@ export class Reaction extends BaseInterface { public toVersiaUnreact(): VersiaEntities.Delete { return new VersiaEntities.Delete({ type: "Delete", - id: crypto.randomUUID(), created_at: new Date().toISOString(), - author: User.getUri( - this.data.authorId, - this.data.author.uri ? new URL(this.data.author.uri) : null, - ).href, + author: this.data.authorId, deleted_type: "pub.versia:reactions/Reaction", - deleted: this.getUri(config.http.base_url).href, + deleted: this.id, }); } @@ -279,7 +298,7 @@ export class Reaction extends BaseInterface { return Reaction.insert({ id: randomUUIDv7(), - uri: reactionToConvert.data.uri, + remoteId: reactionToConvert.data.id, authorId: author.id, noteId: note.id, emojiId: emoji ? emoji.id : null, diff --git a/packages/kit/db/user.ts b/packages/kit/db/user.ts index 7d5ef546..4d63a931 100644 --- a/packages/kit/db/user.ts +++ b/packages/kit/db/user.ts @@ -4,15 +4,11 @@ import type { RolePermission, Source, } from "@versia/client/schemas"; -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 { config, ProxiableUrl } from "@versia-server/config"; -import { - federationDeliveryLogger, - federationResolversLogger, -} from "@versia-server/logging"; +import { federationDeliveryLogger } from "@versia-server/logging"; import { password as bunPassword, randomUUIDv7 } from "bun"; import chalk from "chalk"; import { @@ -33,10 +29,9 @@ import { htmlToText } from "html-to-text"; import type { z } from "zod"; import { getBestContentType } from "@/content_types"; import { randomString } from "@/math"; -import type { HttpVerb, KnownEntity } from "~/types/api.ts"; +import type { KnownEntity } from "~/types/api.ts"; import { DeliveryJobType, deliveryQueue } from "../queues/delivery/queue.ts"; import { PushJobType, pushQueue } from "../queues/push/queue.ts"; -import { uuid } from "../regex.ts"; import { db } from "../tables/db.ts"; import { EmojiToUser, @@ -79,7 +74,7 @@ export const userRelations = { // TODO: Remove this function and use what drizzle outputs directly instead of transforming it export const transformOutputToUserWithRelations = ( - user: Omit, "endpoints"> & { + user: InferSelectModel & { followerCount: unknown; followingCount: unknown; statusCount: unknown; @@ -96,7 +91,6 @@ export const transformOutputToUserWithRelations = ( roleId: string; role?: typeof Role.$type; }[]; - endpoints: unknown; }, ): typeof User.$type => { return { @@ -104,17 +98,6 @@ export const transformOutputToUserWithRelations = ( followerCount: Number(user.followerCount), followingCount: Number(user.followingCount), statusCount: Number(user.statusCount), - endpoints: - user.endpoints ?? - ({} as Partial<{ - dislikes: string; - featured: string; - likes: string; - followers: string; - following: string; - inbox: string; - outbox: string; - }>), emojis: user.emojis.map( (emoji) => (emoji as unknown as Record) @@ -239,14 +222,26 @@ export class User extends BaseInterface { return !this.local; } - public get uri(): URL { - return this.data.uri - ? new URL(this.data.uri) - : new URL(`/users/${this.data.id}`, config.http.base_url); + public get reference(): VersiaEntities.Reference { + if (this.local) { + return new VersiaEntities.Reference(this.id); + } + + return new VersiaEntities.Reference( + this.data.remoteId as string, + (this.data.instance as typeof Instance.$type).baseUrl, + ); } - public static getUri(id: string, uri: URL | null): URL { - return uri ? uri : new URL(`/users/${id}`, config.http.base_url); + public get uri(): URL { + const domain = this.data.instance?.baseUrl + ? new URL(`https://${this.data.instance.baseUrl}`) + : config.http.base_url; + + return new URL( + `/.versia/v0.6/entities/User/${this.id}`, + `https://${domain}`, + ); } public hasPermission(permission: RolePermission): boolean { @@ -335,13 +330,13 @@ export class User extends BaseInterface { } private unfollowToVersia(followee: User): VersiaEntities.Unfollow { - const id = crypto.randomUUID(); return new VersiaEntities.Unfollow({ type: "Unfollow", - id, - author: this.uri.href, + author: this.id, created_at: new Date().toISOString(), - followee: followee.uri.href, + followee: followee.data.instance + ? `${followee.data.instance.baseUrl}:${followee.id}` + : followee.id, }); } @@ -359,10 +354,11 @@ export class User extends BaseInterface { const entity = new VersiaEntities.FollowAccept({ type: "FollowAccept", - id: crypto.randomUUID(), - author: this.uri.href, + author: this.id, created_at: new Date().toISOString(), - follower: follower.uri.href, + follower: follower.data.instance + ? `${follower.data.instance.baseUrl}:${follower.id}` + : follower.id, }); await deliveryQueue.add(DeliveryJobType.FederateEntity, { @@ -383,10 +379,11 @@ export class User extends BaseInterface { const entity = new VersiaEntities.FollowReject({ type: "FollowReject", - id: crypto.randomUUID(), - author: this.uri.href, + author: this.id, created_at: new Date().toISOString(), - follower: follower.uri.href, + follower: follower.data.instance + ? `${follower.data.instance.baseUrl}:${follower.id}` + : follower.id, }); await deliveryQueue.add(DeliveryJobType.FederateEntity, { @@ -396,41 +393,6 @@ export class User extends BaseInterface { }); } - /** - * Signs a Versia entity with that user's private key - * - * @param entity Entity to sign - * @param signatureUrl URL to embed in signature (must be the same URI of queries made with this signature) - * @param signatureMethod HTTP method to embed in signature (default: POST) - * @returns The signed string and headers to send with the request - */ - public async sign( - entity: KnownEntity | VersiaEntities.Collection, - signatureUrl: URL, - signatureMethod: HttpVerb = "POST", - ): Promise<{ - headers: Headers; - }> { - const privateKey = await crypto.subtle.importKey( - "pkcs8", - Buffer.from(this.data.privateKey ?? "", "base64"), - "Ed25519", - false, - ["sign"], - ); - - const { headers } = await sign( - privateKey, - this.uri, - new Request(signatureUrl, { - method: signatureMethod, - body: JSON.stringify(entity), - }), - ); - - return { headers }; - } - /** * Perform a WebFinger lookup to find a user's URI * @param username @@ -708,54 +670,41 @@ export class User extends BaseInterface { * Takes a Versia User representation, and serializes it to the database. * * If the user already exists, it will update it. - * @param versiaUser URL or Versia User representation + * @param versiaUser Reference or Versia User representation */ public static async fromVersia( - versiaUser: VersiaEntities.User | URL, + versiaUser: VersiaEntities.User | VersiaEntities.Reference, + domain: string, ): Promise { - if (versiaUser instanceof URL) { - let uri = versiaUser; - const instance = await Instance.resolve(uri); - - if (instance.data.protocol === "activitypub") { - if (!config.federation.bridge) { - throw new Error("ActivityPub bridge is not enabled"); - } - - uri = new URL( - `/apbridge/versia/query?${new URLSearchParams({ - user_url: uri.href, - })}`, - config.federation.bridge.url, + if (versiaUser instanceof VersiaEntities.Reference) { + if (!versiaUser.domain) { + throw new Error( + "Cannot fetch Versia user from reference without domain", ); } - const user = await new FederationRequester( - config.instance.keys.private, - config.http.base_url, - ).fetchEntity(uri, VersiaEntities.User); + const user = await Instance.federationRequester.fetchEntity( + versiaUser, + VersiaEntities.User, + ); - return User.fromVersia(user); + return User.fromVersia(user, versiaUser.domain); } const { username, - inbox, - avatar, - header, display_name, + id, fields, - collections, created_at, manually_approves_followers, bio, - public_key, - uri, extensions, } = versiaUser.data; - const instance = await Instance.resolve(new URL(versiaUser.data.uri)); + + const instance = await Instance.resolve(domain); const existingUser = await User.fromSql( - eq(Users.uri, versiaUser.data.uri), + and(eq(Users.instanceId, instance.id), eq(Users.remoteId, id)), ); const user = @@ -763,60 +712,50 @@ export class User extends BaseInterface { (await User.insert({ username, id: randomUUIDv7(), - publicKey: public_key.key, - uri, instanceId: instance.id, + remoteId: id, })); // Avatars and headers are stored in a separate table, so we need to update them separately let userAvatar: Media | null = null; let userHeader: Media | null = null; - if (avatar) { + if (versiaUser.avatar) { if (user.avatar) { userAvatar = new Media( await user.avatar.update({ - content: avatar, + content: versiaUser.avatar.data, }), ); } else { userAvatar = await Media.insert({ id: randomUUIDv7(), - content: avatar, + content: versiaUser.avatar.data, }); } } - if (header) { + if (versiaUser.header) { if (user.header) { userHeader = new Media( await user.header.update({ - content: header, + content: versiaUser.header.data, }), ); } else { userHeader = await Media.insert({ id: randomUUIDv7(), - content: header, + content: versiaUser.header.data, }); } } await user.update({ createdAt: new Date(created_at), - endpoints: { - inbox, - outbox: collections.outbox, - followers: collections.followers, - following: collections.following, - featured: collections.featured, - likes: collections["pub.versia:likes/Likes"] ?? undefined, - dislikes: collections["pub.versia:likes/Dislikes"] ?? undefined, - }, - isLocked: manually_approves_followers ?? false, + isLocked: manually_approves_followers, avatarId: userAvatar?.id, headerId: userHeader?.id, - fields: fields ?? [], + fields, displayName: display_name, note: getBestContentType(bio).content, }); @@ -847,31 +786,39 @@ export class User extends BaseInterface { return user; } - public static async resolve(uri: URL): Promise { - federationResolversLogger.debug`Resolving user ${chalk.gray(uri)}`; + public static async resolve( + reference: VersiaEntities.Reference, + ): Promise { // Check if user not already in database - const foundUser = await User.fromSql(eq(Users.uri, uri.href)); + if ( + !reference.domain || + reference.domain === config.http.base_url.hostname + ) { + const user = await User.fromId(reference.id); + + if (!user) { + throw new Error( + "Failed to resolve user reference: User not found", + ); + } + + return user; + } + + const instance = await Instance.resolve(reference.domain); + + const foundUser = await User.fromSql( + and( + eq(Users.instanceId, instance.id), + eq(Users.remoteId, reference.id), + ), + ); if (foundUser) { return foundUser; } - // Check if URI is of a local user - if (uri.origin === config.http.base_url.origin) { - const userUuid = uri.href.match(uuid); - - if (!userUuid?.[0]) { - throw new Error( - `URI ${uri} is of a local user, but it could not be parsed`, - ); - } - - return await User.fromId(userUuid[0]); - } - - federationResolversLogger.debug`User not found in database, fetching from remote`; - - return User.fromVersia(uri); + return User.fromVersia(reference, reference.domain); } /** @@ -890,31 +837,6 @@ export class User extends BaseInterface { return this.avatar?.getUrl(); } - public static async generateKeys(): Promise<{ - private_key: string; - public_key: string; - }> { - const keys = await crypto.subtle.generateKey("Ed25519", true, [ - "sign", - "verify", - ]); - - const privateKey = Buffer.from( - await crypto.subtle.exportKey("pkcs8", keys.privateKey), - ).toString("base64"); - - const publicKey = Buffer.from( - await crypto.subtle.exportKey("spki", keys.publicKey), - ).toString("base64"); - - // Add header, footer and newlines later on - // These keys are base64 encrypted - return { - private_key: privateKey, - public_key: publicKey, - }; - } - public static async register( username: string, options?: Partial<{ @@ -924,8 +846,6 @@ export class User extends BaseInterface { isAdmin: boolean; }>, ): Promise { - const keys = await User.generateKeys(); - const user = await User.insert({ id: randomUUIDv7(), username, @@ -937,9 +857,7 @@ export class User extends BaseInterface { note: "", avatarId: options?.avatar?.id, isAdmin: options?.isAdmin, - publicKey: keys.public_key, fields: [], - privateKey: keys.private_key, updatedAt: new Date(), source: { language: "en", @@ -999,11 +917,9 @@ export class User extends BaseInterface { newUser.avatar || newUser.header || newUser.fields || - newUser.publicKey || newUser.isAdmin || newUser.isBot || newUser.isLocked || - newUser.endpoints || newUser.isDiscoverable || newUser.isIndexable) ) { @@ -1013,20 +929,6 @@ export class User extends BaseInterface { return updated.data; } - public get federationRequester(): Promise { - return crypto.subtle - .importKey( - "pkcs8", - Buffer.from(this.data.privateKey ?? "", "base64"), - "Ed25519", - false, - ["sign"], - ) - .then((k) => { - return new FederationRequester(k, this.uri); - }); - } - /** * Get all remote followers of the user * @returns The remote followers @@ -1076,17 +978,13 @@ export class User extends BaseInterface { entity: KnownEntity, user: User, ): Promise<{ ok: boolean }> { - const inbox = user.data.instance?.inbox || user.data.endpoints?.inbox; - - if (!inbox) { - throw new Error( - `User ${chalk.gray(user.uri)} does not have an inbox endpoint`, - ); + if (!user.data.instance) { + throw new Error("Cannot federate to a local user"); } try { - await (await this.federationRequester).postEntity( - new URL(inbox), + await Instance.federationRequester.postEntity( + user.data.instance.baseUrl, entity, ); } catch (e) { @@ -1110,9 +1008,12 @@ export class User extends BaseInterface { display_name: user.displayName || user.username, note: user.note, uri: this.uri.href, - url: - user.uri || - new URL(`/@${user.username}`, config.http.base_url).href, + url: new URL( + `/@${user.username}${ + user.instanceId ? `@${user.instance?.baseUrl}` : "" + }`, + config.http.base_url, + ).href, avatar: this.getAvatarUrl().proxied, header: this.getHeaderUrl()?.proxied ?? "", locked: user.isLocked, @@ -1166,7 +1067,6 @@ export class User extends BaseInterface { return new VersiaEntities.User({ id: user.id, type: "User", - uri: this.uri.href, bio: { "text/html": { content: user.note, @@ -1178,34 +1078,6 @@ export class User extends BaseInterface { }, }, created_at: user.createdAt.toISOString(), - collections: { - featured: new URL( - `/users/${user.id}/featured`, - config.http.base_url, - ).href, - "pub.versia:likes/Likes": new URL( - `/users/${user.id}/likes`, - config.http.base_url, - ).href, - "pub.versia:likes/Dislikes": new URL( - `/users/${user.id}/dislikes`, - config.http.base_url, - ).href, - followers: new URL( - `/users/${user.id}/followers`, - config.http.base_url, - ).href, - following: new URL( - `/users/${user.id}/following`, - config.http.base_url, - ).href, - outbox: new URL( - `/users/${user.id}/outbox`, - config.http.base_url, - ).href, - }, - inbox: new URL(`/users/${user.id}/inbox`, config.http.base_url) - .href, indexable: this.data.isIndexable, username: user.username, manually_approves_followers: this.data.isLocked, @@ -1217,11 +1089,6 @@ export class User extends BaseInterface { >, display_name: user.displayName, fields: user.fields, - public_key: { - actor: new URL(`/users/${user.id}`, config.http.base_url).href, - key: user.publicKey, - algorithm: "ed25519", - }, extensions: { "pub.versia:custom_emojis": { emojis: user.emojis.map((emoji) => diff --git a/packages/kit/inbox-processor.ts b/packages/kit/inbox-processor.ts index f7c4a631..7e704c88 100644 --- a/packages/kit/inbox-processor.ts +++ b/packages/kit/inbox-processor.ts @@ -199,7 +199,12 @@ export class InboxProcessor { .on(VersiaEntities.Delete, (d) => InboxProcessor.processDelete(d), ) - .on(VersiaEntities.User, (u) => InboxProcessor.processUser(u)) + .on(VersiaEntities.User, (u) => + InboxProcessor.processUser( + u, + this.sender?.instance.data.baseUrl ?? "", + ), + ) .on(VersiaEntities.Share, (s) => InboxProcessor.processShare(s)) .on(VersiaEntities.Reaction, (r) => InboxProcessor.processReaction(r), @@ -221,8 +226,8 @@ export class InboxProcessor { private static async processReaction( reaction: VersiaEntities.Reaction, ): Promise { - const author = await User.resolve(new URL(reaction.data.author)); - const note = await Note.resolve(new URL(reaction.data.object)); + const author = await User.resolve(reaction.author); + const note = await Note.resolve(reaction.object); if (!author) { throw new ApiError(404, "Author not found"); @@ -264,9 +269,13 @@ export class InboxProcessor { * Handles User entity processing. * * @param {VersiaUser} user - The User entity to process. + * @param {string} domain - The domain of the user. * @returns {Promise} */ - private static async processUser(user: VersiaEntities.User): Promise { + private static async processUser( + user: VersiaEntities.User, + domain: string, + ): Promise { if ( config.validation.filters.username.some((filter) => filter.test(user.data.username), @@ -294,7 +303,7 @@ export class InboxProcessor { return; } - await User.fromVersia(user); + await User.fromVersia(user, domain); } /** @@ -306,8 +315,8 @@ export class InboxProcessor { private static async processFollowRequest( follow: VersiaEntities.Follow, ): Promise { - const author = await User.resolve(new URL(follow.data.author)); - const followee = await User.resolve(new URL(follow.data.followee)); + const author = await User.resolve(follow.author); + const followee = await User.resolve(follow.followee); if (!author) { throw new ApiError(404, "Author not found"); @@ -354,10 +363,8 @@ export class InboxProcessor { private static async processFollowAccept( followAccept: VersiaEntities.FollowAccept, ): Promise { - const author = await User.resolve(new URL(followAccept.data.author)); - const follower = await User.resolve( - new URL(followAccept.data.follower), - ); + const author = await User.resolve(followAccept.author); + const follower = await User.resolve(followAccept.follower); if (!author) { throw new ApiError(404, "Author not found"); @@ -391,10 +398,8 @@ export class InboxProcessor { private static async processFollowReject( followReject: VersiaEntities.FollowReject, ): Promise { - const author = await User.resolve(new URL(followReject.data.author)); - const follower = await User.resolve( - new URL(followReject.data.follower), - ); + const author = await User.resolve(followReject.author); + const follower = await User.resolve(followReject.follower); if (!author) { throw new ApiError(404, "Author not found"); @@ -428,8 +433,8 @@ export class InboxProcessor { private static async processShare( share: VersiaEntities.Share, ): Promise { - const author = await User.resolve(new URL(share.data.author)); - const sharedNote = await Note.resolve(new URL(share.data.shared)); + const author = await User.resolve(share.author); + const sharedNote = await Note.resolve(share.shared); if (!author) { throw new ApiError(404, "Author not found"); @@ -439,7 +444,7 @@ export class InboxProcessor { throw new ApiError(404, "Shared Note not found"); } - await sharedNote.reblog(author, "public", new URL(share.data.uri)); + await sharedNote.reblog(author, "public", share.data.id); } /** @@ -451,17 +456,15 @@ export class InboxProcessor { public static async processDelete( delete_: VersiaEntities.Delete, ): Promise { - const toDelete = delete_.data.deleted; + const toDelete = delete_.deleted; - const author = delete_.data.author - ? await User.resolve(new URL(delete_.data.author)) - : null; + const author = await User.resolve(delete_.author); switch (delete_.data.deleted_type) { case "Note": { const note = await Note.fromSql( - eq(Notes.uri, toDelete), - author ? eq(Notes.authorId, author.id) : undefined, + eq(Notes.remoteId, toDelete.id), + eq(Notes.authorId, author.id), ); if (!note) { @@ -475,7 +478,7 @@ export class InboxProcessor { return; } case "User": { - const userToDelete = await User.resolve(new URL(toDelete)); + const userToDelete = await User.resolve(toDelete); if (!userToDelete) { throw new ApiError(404, "User to delete not found"); @@ -490,8 +493,8 @@ export class InboxProcessor { } case "pub.versia:likes/Like": { const like = await Like.fromSql( - eq(Likes.uri, toDelete), - author ? eq(Likes.likerId, author.id) : undefined, + eq(Likes.remoteId, toDelete.id), + eq(Likes.likerId, author.id), ); if (!like) { @@ -525,7 +528,10 @@ export class InboxProcessor { } const reblog = await Note.fromSql( - and(eq(Notes.uri, toDelete), eq(Notes.authorId, author.id)), + and( + eq(Notes.remoteId, toDelete.id), + eq(Notes.authorId, author.id), + ), ); if (!reblog) { @@ -568,8 +574,8 @@ export class InboxProcessor { private static async processLikeRequest( like: VersiaEntities.Like, ): Promise { - const author = await User.resolve(new URL(like.data.author)); - const likedNote = await Note.resolve(new URL(like.data.liked)); + const author = await User.resolve(like.author); + const likedNote = await Note.resolve(like.liked); if (!author) { throw new ApiError(404, "Author not found"); @@ -579,7 +585,7 @@ export class InboxProcessor { throw new ApiError(404, "Liked Note not found"); } - await likedNote.like(author, new URL(like.data.uri)); + await likedNote.like(author, like.data.id); } /** diff --git a/packages/kit/parsers.ts b/packages/kit/parsers.ts index 5d0e66ac..c02e0a21 100644 --- a/packages/kit/parsers.ts +++ b/packages/kit/parsers.ts @@ -1,4 +1,4 @@ -import type * as VersiaEntities from "@versia/sdk/entities"; +import * as VersiaEntities from "@versia/sdk/entities"; import { FederationRequester } from "@versia/sdk/http"; import { config } from "@versia-server/config"; import { and, eq, inArray, isNull, or } from "drizzle-orm"; @@ -13,6 +13,7 @@ import { letter, } from "magic-regexp"; import { sanitizeHtml, sanitizeHtmlInline } from "@/sanitization"; +import { Instance } from "./db/instance.ts"; import { User } from "./db/user.ts"; import { markdownToHtml } from "./markdown.ts"; import { mention } from "./regex.ts"; @@ -81,7 +82,12 @@ export const parseMentionsFromText = async (text: string): Promise => { ); if (url) { - const user = await User.resolve(url); + const userEntity = await Instance.federationRequester.fetchSigned( + url, + VersiaEntities.User, + ); + + const user = await User.fromVersia(userEntity, url.hostname); if (user) { finalList.push(user); diff --git a/packages/kit/queues/fetch/worker.ts b/packages/kit/queues/fetch/worker.ts index 90ddfbff..c463fe73 100644 --- a/packages/kit/queues/fetch/worker.ts +++ b/packages/kit/queues/fetch/worker.ts @@ -17,7 +17,7 @@ export const getFetchWorker = (): Worker => await job.log(`Fetching instance metadata from [${uri}]`); // Check if exists - const host = new URL(uri).host; + const host = new URL(uri).hostname; const existingInstance = await Instance.fromSql( eq(Instances.baseUrl, host), @@ -37,7 +37,7 @@ export const getFetchWorker = (): Worker => return; } - await Instance.resolve(new URL(uri)); + await Instance.resolve(host); await job.log( `✔ Finished fetching instance metadata from [${uri}]`, diff --git a/packages/kit/queues/inbox/worker.ts b/packages/kit/queues/inbox/worker.ts index 95220d92..11848be1 100644 --- a/packages/kit/queues/inbox/worker.ts +++ b/packages/kit/queues/inbox/worker.ts @@ -2,7 +2,6 @@ import { config } from "@versia-server/config"; import { Worker } from "bullmq"; import { ApiError } from "../../api-error.ts"; import { Instance } from "../../db/instance.ts"; -import { User } from "../../db/user.ts"; import { InboxProcessor } from "../../inbox-processor.ts"; import { connection } from "../../redis.ts"; import { type InboxJobData, InboxJobType, inboxQueue } from "./queue.ts"; @@ -72,51 +71,29 @@ export const getInboxWorker = (): Worker => "versia-signed-by": string; }; - const sender = await User.resolve(new URL(signedBy)); + const sender = await Instance.resolve(signedBy); - if (!(sender || signedBy.startsWith("instance "))) { + if (!sender) { await job.log( - `Could not resolve sender URI [${signedBy}]`, + `Could not resolve sender domain [${signedBy}]`, ); return; } - if (sender?.local) { - throw new Error( - "Cannot process federation requests from local users", - ); - } - - const remoteInstance = sender - ? await Instance.fromUser(sender) - : await Instance.resolveFromHost( - signedBy.split(" ")[1], - ); - - if (!remoteInstance) { - await job.log("Could not resolve the remote instance."); - - return; - } - await job.log( - `Entity [${data.id}] is from remote instance [${remoteInstance.data.baseUrl}]`, + `Entity [${data.id}] is from remote instance [${sender.data.baseUrl}]`, ); - if (!remoteInstance.data.publicKey?.key) { + if (!sender.data.publicKey?.key) { throw new Error( - `Instance ${remoteInstance.data.baseUrl} has no public key stored in database`, + `Instance ${sender.data.baseUrl} has no public key stored in database`, ); } const key = await crypto.subtle.importKey( "spki", - Buffer.from( - sender?.data.publicKey ?? - remoteInstance.data.publicKey.key, - "base64", - ), + Buffer.from(sender.data.publicKey.key, "base64"), "Ed25519", false, ["verify"], @@ -127,7 +104,7 @@ export const getInboxWorker = (): Worker => req, data, { - instance: remoteInstance, + instance: sender, key, }, undefined, @@ -147,10 +124,10 @@ export const getInboxWorker = (): Worker => ); await job.log( - `Sending error message to instance [${remoteInstance.data.baseUrl}]`, + `Sending error message to instance [${sender.data.baseUrl}]`, ); - await remoteInstance.sendMessage( + await sender.sendMessage( `Failed processing entity [${ data.uri }] delivered to inbox. Returned error:\n\n${JSON.stringify( diff --git a/packages/kit/tables/schema.ts b/packages/kit/tables/schema.ts index f379c579..53a2d4d9 100644 --- a/packages/kit/tables/schema.ts +++ b/packages/kit/tables/schema.ts @@ -137,6 +137,7 @@ export const PushSubscriptionsRelations = relations( export const Reactions = pgTable("Reaction", { id: id(), uri: uri(), + remoteId: text("remote_id"), // Emoji ID is nullable, in which case it is a text emoji, and the emojiText field is used emojiId: uuid("emojiId").references(() => Emojis.id, { onDelete: "cascade", @@ -244,7 +245,7 @@ export const Markers = pgTable("Markers", { export const Likes = pgTable("Likes", { id: id(), - uri: uri(), + remoteId: text("remote_id"), likerId: uuid("likerId") .notNull() .references(() => Users.id, { @@ -472,7 +473,7 @@ export const NotificationsRelations = relations(Notifications, ({ one }) => ({ export const Notes = pgTable("Notes", { id: id(), - uri: uri(), + remoteId: text("remote_id"), authorId: uuid("authorId") .notNull() .references(() => Users.id, { @@ -600,7 +601,7 @@ export const Users = pgTable( "Users", { id: id(), - uri: uri(), + remoteId: text("remote_id"), username: text("username").notNull(), displayName: text("display_name"), password: text("password"), @@ -615,15 +616,6 @@ export const Users = pgTable( value: z.infer; }[] >(), - endpoints: jsonb("endpoints").$type | null>(), source: jsonb("source").$type>(), avatarId: uuid("avatarId").references(() => Medias.id, { onDelete: "set null", @@ -646,8 +638,6 @@ export const Users = pgTable( .notNull(), isIndexable: boolean("is_indexable").default(true).notNull(), sanctions: text("sanctions").array(), - publicKey: text("public_key").notNull(), - privateKey: text("private_key"), instanceId: uuid("instanceId").references(() => Instances.id, { onDelete: "cascade", onUpdate: "cascade", @@ -656,11 +646,7 @@ export const Users = pgTable( .default(false) .notNull(), }, - (table) => [ - uniqueIndex().on(table.uri), - index().on(table.username), - uniqueIndex().on(table.email), - ], + (table) => [index().on(table.username), uniqueIndex().on(table.email)], ); export const UsersRelations = relations(Users, ({ many, one }) => ({ diff --git a/packages/sdk/crypto.ts b/packages/sdk/crypto.ts index 7133fc7e..b61c9b72 100644 --- a/packages/sdk/crypto.ts +++ b/packages/sdk/crypto.ts @@ -13,15 +13,15 @@ const base64ToArrayBuffer = (base64: string): 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 privateKey - Private key of the instance that is signing the request. + * @param instance - URL of the instance 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, + instance: URL, req: Request, timestamp = new Date(), ): Promise => { @@ -48,7 +48,7 @@ export const sign = async ( ...req.headers, "Versia-Signature": signatureBase64, "Versia-Signed-At": String(timestampSecs), - "Versia-Signed-By": authorUrl.href, + "Versia-Signed-By": instance.hostname, }, }); diff --git a/packages/sdk/entities/delete.ts b/packages/sdk/entities/delete.ts index 6df3d896..7a16b5fa 100644 --- a/packages/sdk/entities/delete.ts +++ b/packages/sdk/entities/delete.ts @@ -1,7 +1,7 @@ import type { z } from "zod"; import { DeleteSchema } from "../schemas/delete.ts"; import type { JSONObject } from "../types.ts"; -import { Entity } from "./entity.ts"; +import { Entity, Reference } from "./entity.ts"; export class Delete extends Entity { public static override name = "Delete"; @@ -10,6 +10,14 @@ export class Delete extends Entity { super(data); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get deleted(): Reference { + return Reference.fromString(this.data.deleted); + } + public static override fromJSON(json: JSONObject): Promise { return DeleteSchema.parseAsync(json).then((u) => new Delete(u)); } diff --git a/packages/sdk/entities/entity.ts b/packages/sdk/entities/entity.ts index cd495399..a21beef6 100644 --- a/packages/sdk/entities/entity.ts +++ b/packages/sdk/entities/entity.ts @@ -15,3 +15,31 @@ export class Entity { return this.data; } } + +export class Reference { + public constructor( + public id: string, + public domain?: string, + ) {} + + public static fromString(str: string): Reference { + // Expect format: domain:id or id (if domain is the local instance) + // Handle IPv6 addresses in brackets + const chunks = str.split(":"); + if (chunks.length === 2) { + return new Reference(chunks[1], chunks[0]); + } + + if (chunks.length > 2) { + const domain = chunks.slice(0, -1).join(":"); + const id = chunks.at(-1) as string; + return new Reference(id, domain); + } + + return new Reference(str); + } + + public toString(): string { + return this.domain ? `${this.domain}:${this.id}` : this.id; + } +} diff --git a/packages/sdk/entities/extensions/likes.ts b/packages/sdk/entities/extensions/likes.ts index f8db6885..8615b3fc 100644 --- a/packages/sdk/entities/extensions/likes.ts +++ b/packages/sdk/entities/extensions/likes.ts @@ -1,7 +1,7 @@ import type { z } from "zod"; import { DislikeSchema, LikeSchema } from "../../schemas/extensions/likes.ts"; import type { JSONObject } from "../../types.ts"; -import { Entity } from "../entity.ts"; +import { Entity, Reference } from "../entity.ts"; export class Like extends Entity { public static override name = "pub.versia:likes/Like"; @@ -10,6 +10,14 @@ export class Like extends Entity { super(data); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get liked(): Reference { + return Reference.fromString(this.data.liked); + } + public static override fromJSON(json: JSONObject): Promise { return LikeSchema.parseAsync(json).then((u) => new Like(u)); } @@ -22,6 +30,14 @@ export class Dislike extends Entity { super(data); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get disliked(): Reference { + return Reference.fromString(this.data.disliked); + } + public static override fromJSON(json: JSONObject): Promise { return DislikeSchema.parseAsync(json).then((u) => new Dislike(u)); } diff --git a/packages/sdk/entities/extensions/polls.ts b/packages/sdk/entities/extensions/polls.ts index 995e324d..4c508552 100644 --- a/packages/sdk/entities/extensions/polls.ts +++ b/packages/sdk/entities/extensions/polls.ts @@ -1,7 +1,7 @@ import type { z } from "zod"; import { VoteSchema } from "../../schemas/extensions/polls.ts"; import type { JSONObject } from "../../types.ts"; -import { Entity } from "../entity.ts"; +import { Entity, Reference } from "../entity.ts"; export class Vote extends Entity { public static override name = "pub.versia:polls/Vote"; @@ -10,6 +10,14 @@ export class Vote extends Entity { super(data); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get poll(): Reference { + return Reference.fromString(this.data.poll); + } + public static override fromJSON(json: JSONObject): Promise { return VoteSchema.parseAsync(json).then((u) => new Vote(u)); } diff --git a/packages/sdk/entities/extensions/reactions.ts b/packages/sdk/entities/extensions/reactions.ts index 5f3f785e..3299c248 100644 --- a/packages/sdk/entities/extensions/reactions.ts +++ b/packages/sdk/entities/extensions/reactions.ts @@ -1,7 +1,7 @@ import type { z } from "zod"; import { ReactionSchema } from "../../schemas/extensions/reactions.ts"; import type { JSONObject } from "../../types.ts"; -import { Entity } from "../entity.ts"; +import { Entity, Reference } from "../entity.ts"; export class Reaction extends Entity { public static override name = "pub.versia:reactions/Reaction"; @@ -10,6 +10,14 @@ export class Reaction extends Entity { super(data); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get object(): Reference { + return Reference.fromString(this.data.object); + } + public static override fromJSON(json: JSONObject): Promise { return ReactionSchema.parseAsync(json).then((u) => new Reaction(u)); } diff --git a/packages/sdk/entities/extensions/reports.ts b/packages/sdk/entities/extensions/reports.ts index d15cfe48..31c2ad5e 100644 --- a/packages/sdk/entities/extensions/reports.ts +++ b/packages/sdk/entities/extensions/reports.ts @@ -1,7 +1,7 @@ import type { z } from "zod"; import { ReportSchema } from "../../schemas/extensions/reports.ts"; import type { JSONObject } from "../../types.ts"; -import { Entity } from "../entity.ts"; +import { Entity, Reference } from "../entity.ts"; export class Report extends Entity { public static override name = "pub.versia:reports/Report"; @@ -10,6 +10,14 @@ export class Report extends Entity { super(data); } + public get author(): Reference | null { + return this.data.author ? Reference.fromString(this.data.author) : null; + } + + public get reported(): Reference[] { + return this.data.reported.map((r) => Reference.fromString(r)); + } + public static override fromJSON(json: JSONObject): Promise { return ReportSchema.parseAsync(json).then((u) => new Report(u)); } diff --git a/packages/sdk/entities/extensions/share.ts b/packages/sdk/entities/extensions/share.ts index f3817744..ea2fb8ad 100644 --- a/packages/sdk/entities/extensions/share.ts +++ b/packages/sdk/entities/extensions/share.ts @@ -1,7 +1,7 @@ import type { z } from "zod"; import { ShareSchema } from "../../schemas/extensions/share.ts"; import type { JSONObject } from "../../types.ts"; -import { Entity } from "../entity.ts"; +import { Entity, Reference } from "../entity.ts"; export class Share extends Entity { public static override name = "pub.versia:share/Share"; @@ -10,6 +10,14 @@ export class Share extends Entity { super(data); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get shared(): Reference { + return Reference.fromString(this.data.shared); + } + public static override fromJSON(json: JSONObject): Promise { return ShareSchema.parseAsync(json).then((u) => new Share(u)); } diff --git a/packages/sdk/entities/follow.ts b/packages/sdk/entities/follow.ts index d38d9728..9ba9db5f 100644 --- a/packages/sdk/entities/follow.ts +++ b/packages/sdk/entities/follow.ts @@ -6,7 +6,7 @@ import { UnfollowSchema, } from "../schemas/follow.ts"; import type { JSONObject } from "../types.ts"; -import { Entity } from "./entity.ts"; +import { Entity, Reference } from "./entity.ts"; export class Follow extends Entity { public static override name = "Follow"; @@ -15,6 +15,14 @@ export class Follow extends Entity { super(data); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get followee(): Reference { + return Reference.fromString(this.data.followee); + } + public static override fromJSON(json: JSONObject): Promise { return FollowSchema.parseAsync(json).then((u) => new Follow(u)); } @@ -29,6 +37,14 @@ export class FollowAccept extends Entity { super(data); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get follower(): Reference { + return Reference.fromString(this.data.follower); + } + public static override fromJSON(json: JSONObject): Promise { return FollowAcceptSchema.parseAsync(json).then( (u) => new FollowAccept(u), @@ -45,6 +61,14 @@ export class FollowReject extends Entity { super(data); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get follower(): Reference { + return Reference.fromString(this.data.follower); + } + public static override fromJSON(json: JSONObject): Promise { return FollowRejectSchema.parseAsync(json).then( (u) => new FollowReject(u), @@ -59,6 +83,14 @@ export class Unfollow extends Entity { super(data); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get followee(): Reference { + return Reference.fromString(this.data.followee); + } + public static override fromJSON(json: JSONObject): Promise { return UnfollowSchema.parseAsync(json).then((u) => new Unfollow(u)); } diff --git a/packages/sdk/entities/index.ts b/packages/sdk/entities/index.ts index 2b80228f..8c9f25ff 100644 --- a/packages/sdk/entities/index.ts +++ b/packages/sdk/entities/index.ts @@ -8,7 +8,7 @@ export { VideoContentFormat, } from "./contentformat.ts"; export { Delete } from "./delete.ts"; -export { Entity } from "./entity.ts"; +export { Entity, Reference } from "./entity.ts"; export { Dislike, Like } from "./extensions/likes.ts"; export { Vote } from "./extensions/polls.ts"; export { Reaction } from "./extensions/reactions.ts"; diff --git a/packages/sdk/entities/note.ts b/packages/sdk/entities/note.ts index 7314e763..3a84cb68 100644 --- a/packages/sdk/entities/note.ts +++ b/packages/sdk/entities/note.ts @@ -2,7 +2,7 @@ import type { z } from "zod"; import { NoteSchema } from "../schemas/note.ts"; import type { JSONObject } from "../types.ts"; import { NonTextContentFormat, TextContentFormat } from "./contentformat.ts"; -import { Entity } from "./entity.ts"; +import { Entity, Reference } from "./entity.ts"; export class Note extends Entity { public static override name = "Note"; @@ -15,6 +15,35 @@ export class Note extends Entity { return NoteSchema.parseAsync(json).then((n) => new Note(n)); } + public get author(): Reference { + return Reference.fromString(this.data.author); + } + + public get group(): Reference | null { + if ( + !this.data.group || + ["public", "followers"].includes(this.data.group) + ) { + return null; + } + + return Reference.fromString(this.data.group); + } + + public get mentions(): Reference[] { + return this.data.mentions.map((m) => Reference.fromString(m)); + } + + public get quotes(): Reference | null { + return this.data.quotes ? Reference.fromString(this.data.quotes) : null; + } + + public get repliesTo(): Reference | null { + return this.data.replies_to + ? Reference.fromString(this.data.replies_to) + : null; + } + public get attachments(): NonTextContentFormat[] { return ( this.data.attachments?.map((a) => new NonTextContentFormat(a)) ?? [] diff --git a/packages/sdk/http.ts b/packages/sdk/http.ts index 02e94175..e87aef6a 100644 --- a/packages/sdk/http.ts +++ b/packages/sdk/http.ts @@ -1,10 +1,12 @@ import { sign } from "./crypto.ts"; import { Collection, URICollection } from "./entities/collection.ts"; -import type { Entity } from "./entities/entity.ts"; +import type { Entity, Reference } from "./entities/entity.ts"; +import { InstanceMetadata } from "./entities/instancemetadata.ts"; import { homepage, version } from "./package.json" with { type: "json" }; import { WebFingerSchema } from "./schemas/webfinger.ts"; const DEFAULT_UA = `VersiaFederationClient/${version} (+${homepage})`; +const CONTENT_TYPE = "application/vnd.versia+json"; /** * A class that handles fetching Versia entities @@ -22,22 +24,22 @@ const DEFAULT_UA = `VersiaFederationClient/${version} (+${homepage})`; export class FederationRequester { public constructor( private readonly privateKey: CryptoKey, - private readonly authorUrl: URL, + private readonly instance: URL, ) {} - public async fetchEntity( + public async fetchSigned( url: URL, - expectedType: T, + entityType: T, ): Promise> { const req = new Request(url, { method: "GET", headers: { - Accept: "application/json", + Accept: CONTENT_TYPE, "User-Agent": DEFAULT_UA, }, }); - const finalReq = await sign(this.privateKey, this.authorUrl, req); + const finalReq = await sign(this.privateKey, this.instance, req); const res = await fetch(finalReq); @@ -49,79 +51,116 @@ export class FederationRequester { const contentType = res.headers.get("Content-Type"); - if (!contentType?.includes("application/json")) { + if ( + !( + contentType?.includes("application/vnd.versia+json") && + contentType?.includes("charset=utf-8") + ) + ) { throw new Error( - `Expected JSON response from ${url.toString()}, got "${contentType}"`, + `Expected application/vnd.versia+json; charset=utf-8 response from ${url.toString()}, got "${contentType}"`, ); } const jsonData = await res.json(); const type = jsonData.type; - if (type && type !== expectedType.name) { + if ( + (!type || type !== entityType.name) && + // (URI)Collections don't have a type field + ![Collection, URICollection].some((et) => et === entityType) + ) { throw new Error( - `Expected entity type "${expectedType.name}", got "${type}"`, + `Expected entity type "${entityType.name}", got "${type}"`, ); } - const entity = await expectedType.fromJSON(jsonData); + const entity = await entityType.fromJSON(jsonData); return entity as InstanceType; } - public async postEntity(url: URL, entity: Entity): Promise { + public fetchEntity( + reference: Reference, + entityType: T, + ): Promise> { + const url = new URL( + `/.versia/v0.6/entities/${encodeURIComponent( + entityType.name, + )}/${encodeURIComponent(reference.id)}`, + `https://${reference.domain}`, + ); + + return this.fetchSigned(url, entityType); + } + + public async postEntity(domain: string, entity: Entity): Promise { + const url = new URL("/.versia/v0.6/inbox", `https://${domain}`); + const req = new Request(url, { method: "POST", headers: { - Accept: "application/json", + Accept: CONTENT_TYPE, "User-Agent": DEFAULT_UA, - "Content-Type": "application/json; charset=utf-8", + "Content-Type": "application/vnd.versia+json; charset=utf-8", }, body: JSON.stringify(entity.toJSON()), }); - const finalReq = await sign(this.privateKey, this.authorUrl, req); + const finalReq = await sign(this.privateKey, this.instance, req); return fetch(finalReq); } /** * Recursively go through a Collection of entities until reaching the end - * @param url URL to reach the Collection - * @param expectedType + * @param reference Entity Reference + * @param entityType + * @param collectionItemType * @param options.limit Limit the number of entities to fetch */ - public async resolveCollection( - url: URL, - expectedType: T, + public async resolveCollection< + E extends typeof Entity, + T extends typeof Entity, + >( + reference: Reference, + collectionName: string, + entityType: E, + collectionItemType: T, options?: { limit?: number; }, ): Promise[]> { + const url = new URL( + `/.versia/v0.6/entities/${encodeURIComponent( + entityType.name, + )}/${encodeURIComponent(reference.id)}/collections/${encodeURIComponent( + collectionName, + )}`, + `https://${reference.domain}`, + ); + const entities: InstanceType[] = []; - let nextUrl: URL | null = url; let limit = options?.limit ?? Number.POSITIVE_INFINITY; - while (nextUrl && limit > 0) { - const collection: Collection = await this.fetchEntity( - nextUrl, - Collection, - ); + let collection = await this.fetchSigned(url, Collection); + const total = collection.data.total; - for (const entity of collection.data.items) { - if (entity.type === expectedType.name) { - entities.push( - (await expectedType.fromJSON( - entity, - )) as InstanceType, - ); - } + while (collection && limit > 0) { + entities.push( + ...collection.data.items.map( + (item) => + collectionItemType.fromJSON(item) as InstanceType, + ), + ); + limit -= collection.data.items.length; + + if (entities.length >= total) { + break; } - nextUrl = collection.data.next - ? new URL(collection.data.next) - : null; - limit -= collection.data.items.length; + url.searchParams.set("offset", entities.length.toString()); + collection = await this.fetchSigned(url, Collection); } return entities; @@ -129,33 +168,46 @@ export class FederationRequester { /** * Recursively go through a URICollection of entities until reaching the end - * @param url URL to reach the Collection + * @param reference Entity Reference + * @param entityType * @param options.limit Limit the number of entities to fetch */ - public async resolveURICollection( - url: URL, + public async resolveURICollection( + reference: Reference, + collectionName: string, + entityType: E, options?: { limit?: number; }, - ): Promise { - const entities: string[] = []; - let nextUrl: URL | null = url; + ): Promise { + const url = new URL( + `/.versia/v0.6/entities/${encodeURIComponent( + entityType.name, + )}/${encodeURIComponent(reference.id)}/collections/${encodeURIComponent( + collectionName, + )}`, + `https://${reference.domain}`, + ); + + const uris: string[] = []; let limit = options?.limit ?? Number.POSITIVE_INFINITY; - while (nextUrl && limit > 0) { - const collection: URICollection = await this.fetchEntity( - nextUrl, - URICollection, - ); + let collection = await this.fetchSigned(url, URICollection); + const total = collection.data.total; - entities.push(...collection.data.items); - nextUrl = collection.data.next - ? new URL(collection.data.next) - : null; + while (collection && limit > 0) { + uris.push(...collection.data.items); limit -= collection.data.items.length; + + if (uris.length >= total) { + break; + } + + url.searchParams.set("offset", uris.length.toString()); + collection = await this.fetchSigned(url, URICollection); } - return entities.map((u) => new URL(u)); + return uris; } /** @@ -164,21 +216,21 @@ export class FederationRequester { */ public static async resolveWebFinger( username: string, - hostname: string, - contentType = "application/json", - serverUrl = `https://${hostname}`, + domain: string, + contentType = "application/vnd.versia+json", + serverUrl = `https://${domain}`, ): Promise { const res = await fetch( new URL( `/.well-known/webfinger?${new URLSearchParams({ - resource: `acct:${username}@${hostname}`, + resource: `acct:${username}@${domain}`, })}`, serverUrl, ), { method: "GET", headers: { - Accept: "application/json", + Accept: "application/jrd+json, application/json", "User-Agent": DEFAULT_UA, }, }, @@ -204,4 +256,57 @@ export class FederationRequester { return new URL(selfLink.href); } + + /** + * Resolve instance metadata from a domain + * + * Fetches well-known for version discovery, and if versia is supported, fetches the instance metadata + * @param domain + */ + public async resolveInstance(domain: string): Promise { + const wellKnownUrl = new URL( + "/.well-known/versia", + `https://${domain}`, + ); + + const wellKnownRes = await fetch(wellKnownUrl, { + method: "GET", + headers: { + Accept: "application/json", + "User-Agent": DEFAULT_UA, + }, + }); + + if (!wellKnownRes.ok) { + throw new Error( + `Failed to fetch well-known from ${wellKnownUrl.toString()}: got HTTP code ${wellKnownRes.status} with body "${await wellKnownRes.text()}"`, + ); + } + + const wellKnownData = await wellKnownRes.json(); + + if ( + !( + wellKnownData.versions && + Array.isArray(wellKnownData.versions) && + wellKnownData.versions.includes("0.6.0") + ) + ) { + throw new Error( + `Instance at ${domain} does not support Versia v0.6`, + ); + } + + const metadataUrl = new URL( + "/.versia/v0.6/instance", + `https://${domain}`, + ); + + const metadataRes = await this.fetchSigned( + metadataUrl, + InstanceMetadata, + ); + + return metadataRes; + } } diff --git a/packages/sdk/schemas/collection.ts b/packages/sdk/schemas/collection.ts index 92accefb..993d577a 100644 --- a/packages/sdk/schemas/collection.ts +++ b/packages/sdk/schemas/collection.ts @@ -1,16 +1,13 @@ import { z } from "zod"; -import { u64, url } from "./common.ts"; +import { u64 } from "./common.ts"; +import { ReferenceSchema } from "./entity.ts"; export const CollectionSchema = z.strictObject({ - author: url.nullable(), - first: url, - last: url, + author: ReferenceSchema.nullable(), total: u64, - next: url.nullable(), - previous: url.nullable(), items: z.array(z.any()), }); export const URICollectionSchema = CollectionSchema.extend({ - items: z.array(url), + items: z.array(ReferenceSchema), }); diff --git a/packages/sdk/schemas/contentformat.ts b/packages/sdk/schemas/contentformat.ts index 42e5c6a5..4ee35569 100644 --- a/packages/sdk/schemas/contentformat.ts +++ b/packages/sdk/schemas/contentformat.ts @@ -2,26 +2,6 @@ import { types } from "mime-types"; import { z } from "zod"; import { f64, u64 } from "./common.ts"; -const hashSizes = { - sha256: 64, - sha512: 128, - "sha3-256": 64, - "sha3-512": 128, - "blake2b-256": 64, - "blake2b-512": 128, - "blake3-256": 64, - "blake3-512": 128, - md5: 32, - sha1: 40, - sha224: 56, - sha384: 96, - "sha3-224": 56, - "sha3-384": 96, - "blake2s-256": 64, - "blake2s-512": 128, - "blake3-224": 56, - "blake3-384": 96, -}; const allMimeTypes = Object.values(types) as [string, ...string[]]; const textMimeTypes = Object.values(types).filter((v) => v.startsWith("text/"), @@ -46,16 +26,7 @@ export const ContentFormatSchema = z.partialRecord( remote: z.boolean(), description: z.string().nullish(), size: u64.nullish(), - hash: z - .strictObject( - Object.fromEntries( - Object.entries(hashSizes).map(([k, v]) => [ - k, - z.string().length(v).nullish(), - ]), - ), - ) - .nullish(), + hash: z.hash("sha256").nullish(), thumbhash: z.string().nullish(), width: u64.nullish(), height: u64.nullish(), diff --git a/packages/sdk/schemas/delete.ts b/packages/sdk/schemas/delete.ts index 9cd7d9a8..b0a4733f 100644 --- a/packages/sdk/schemas/delete.ts +++ b/packages/sdk/schemas/delete.ts @@ -1,11 +1,9 @@ import { z } from "zod"; -import { url } from "./common.ts"; -import { EntitySchema } from "./entity.ts"; +import { ReferenceSchema, TransientEntitySchema } from "./entity.ts"; -export const DeleteSchema = EntitySchema.extend({ - uri: z.null().optional(), +export const DeleteSchema = TransientEntitySchema.extend({ type: z.literal("Delete"), - author: url.nullable(), + author: ReferenceSchema, deleted_type: z.string(), - deleted: url, + deleted: ReferenceSchema, }); diff --git a/packages/sdk/schemas/entity.ts b/packages/sdk/schemas/entity.ts index 4cb6f7b7..2ef7dd8e 100644 --- a/packages/sdk/schemas/entity.ts +++ b/packages/sdk/schemas/entity.ts @@ -1,6 +1,5 @@ import { z } from "zod"; import { isISOString } from "../regex.ts"; -import { url } from "./common.ts"; import { CustomEmojiExtensionSchema } from "./extensions/emojis.ts"; export const ExtensionPropertySchema = z @@ -10,14 +9,26 @@ export const ExtensionPropertySchema = z }) .catchall(z.any()); +export const ReferenceSchema = z.string(); + export const EntitySchema = z.strictObject({ // biome-ignore lint/style/useNamingConvention: required for JSON schema $schema: z.url().nullish(), - id: z.string().max(512), + id: z + .string() + .max(512) + .regex( + // a-z, A-Z, 0-9, - and _ + /^[A-Za-z0-9\-_]+$/, + "can only contain alphanumeric characters, hyphens and underscores", + ), created_at: z .string() - .refine((v) => isISOString(v), "must be a valid ISO8601 datetime"), - uri: url, + .refine((v) => isISOString(v), "must be a valid RFC 3339 datetime"), type: z.string(), extensions: ExtensionPropertySchema.nullish(), }); + +export const TransientEntitySchema = EntitySchema.extend({ + id: z.null().optional(), +}); diff --git a/packages/sdk/schemas/extensions/groups.ts b/packages/sdk/schemas/extensions/groups.ts index 8c246056..6d56f49c 100644 --- a/packages/sdk/schemas/extensions/groups.ts +++ b/packages/sdk/schemas/extensions/groups.ts @@ -1,41 +1,38 @@ import { z } from "zod"; -import { url } from "../common.ts"; import { TextContentFormatSchema } from "../contentformat.ts"; -import { EntitySchema } from "../entity.ts"; +import { + EntitySchema, + ReferenceSchema, + TransientEntitySchema, +} from "../entity.ts"; export const GroupSchema = EntitySchema.extend({ type: z.literal("pub.versia:groups/Group"), name: TextContentFormatSchema.nullish(), description: TextContentFormatSchema.nullish(), - open: z.boolean().nullish(), - members: url, - notes: url.nullish(), + open: z.boolean(), }); -export const GroupSubscribeSchema = EntitySchema.extend({ +export const GroupSubscribeSchema = TransientEntitySchema.extend({ type: z.literal("pub.versia:groups/Subscribe"), - uri: z.null().optional(), - subscriber: url, - group: url, + subscriber: ReferenceSchema, + group: ReferenceSchema, }); -export const GroupUnsubscribeSchema = EntitySchema.extend({ +export const GroupUnsubscribeSchema = TransientEntitySchema.extend({ type: z.literal("pub.versia:groups/Unsubscribe"), - uri: z.null().optional(), - subscriber: url, - group: url, + subscriber: ReferenceSchema, + group: ReferenceSchema, }); -export const GroupSubscribeAcceptSchema = EntitySchema.extend({ +export const GroupSubscribeAcceptSchema = TransientEntitySchema.extend({ type: z.literal("pub.versia:groups/SubscribeAccept"), - uri: z.null().optional(), - subscriber: url, - group: url, + subscriber: ReferenceSchema, + group: ReferenceSchema, }); -export const GroupSubscribeRejectSchema = EntitySchema.extend({ +export const GroupSubscribeRejectSchema = TransientEntitySchema.extend({ type: z.literal("pub.versia:groups/SubscribeReject"), - uri: z.null().optional(), - subscriber: url, - group: url, + subscriber: ReferenceSchema, + group: ReferenceSchema, }); diff --git a/packages/sdk/schemas/extensions/likes.ts b/packages/sdk/schemas/extensions/likes.ts index 75208fb7..b9c14fbc 100644 --- a/packages/sdk/schemas/extensions/likes.ts +++ b/packages/sdk/schemas/extensions/likes.ts @@ -1,15 +1,14 @@ import { z } from "zod"; -import { url } from "../common.ts"; -import { EntitySchema } from "../entity.ts"; +import { EntitySchema, ReferenceSchema } from "../entity.ts"; export const LikeSchema = EntitySchema.extend({ type: z.literal("pub.versia:likes/Like"), - author: url, - liked: url, + author: ReferenceSchema, + liked: ReferenceSchema, }); export const DislikeSchema = EntitySchema.extend({ type: z.literal("pub.versia:likes/Dislike"), - author: url, - disliked: url, + author: ReferenceSchema, + disliked: ReferenceSchema, }); diff --git a/packages/sdk/schemas/extensions/migration.ts b/packages/sdk/schemas/extensions/migration.ts index da215ce3..844bbcfa 100644 --- a/packages/sdk/schemas/extensions/migration.ts +++ b/packages/sdk/schemas/extensions/migration.ts @@ -1,15 +1,13 @@ import { z } from "zod"; -import { url } from "../common.ts"; -import { EntitySchema } from "../entity.ts"; +import { ReferenceSchema, TransientEntitySchema } from "../entity.ts"; -export const MigrationSchema = EntitySchema.extend({ +export const MigrationSchema = TransientEntitySchema.extend({ type: z.literal("pub.versia:migration/Migration"), - uri: z.null().optional(), - author: url, - destination: url, + author: ReferenceSchema, + destination: ReferenceSchema, }); export const MigrationExtensionSchema = z.strictObject({ - previous: url, - new: url.nullish(), + previous: ReferenceSchema, + new: ReferenceSchema.nullish(), }); diff --git a/packages/sdk/schemas/extensions/polls.ts b/packages/sdk/schemas/extensions/polls.ts index 09741b8c..8455c295 100644 --- a/packages/sdk/schemas/extensions/polls.ts +++ b/packages/sdk/schemas/extensions/polls.ts @@ -1,13 +1,13 @@ import { z } from "zod"; import { isISOString } from "../../regex.ts"; -import { u64, url } from "../common.ts"; +import { u64 } from "../common.ts"; import { TextContentFormatSchema } from "../contentformat.ts"; -import { EntitySchema } from "../entity.ts"; +import { EntitySchema, ReferenceSchema } from "../entity.ts"; export const VoteSchema = EntitySchema.extend({ type: z.literal("pub.versia:polls/Vote"), - author: url, - poll: url, + author: ReferenceSchema, + poll: ReferenceSchema, option: u64, }); @@ -17,6 +17,6 @@ export const PollExtensionSchema = z.strictObject({ multiple_choice: z.boolean(), expires_at: z .string() - .refine((v) => isISOString(v), "must be a valid ISO8601 datetime") + .refine((v) => isISOString(v), "must be a valid RFC 3339 datetime") .nullish(), }); diff --git a/packages/sdk/schemas/extensions/reactions.ts b/packages/sdk/schemas/extensions/reactions.ts index 99b7162d..4fddbb4e 100644 --- a/packages/sdk/schemas/extensions/reactions.ts +++ b/packages/sdk/schemas/extensions/reactions.ts @@ -1,10 +1,9 @@ import { z } from "zod"; -import { url } from "../common.ts"; -import { EntitySchema } from "../entity.ts"; +import { EntitySchema, ReferenceSchema } from "../entity.ts"; export const ReactionSchema = EntitySchema.extend({ type: z.literal("pub.versia:reactions/Reaction"), - author: url, - object: url, + author: ReferenceSchema, + object: ReferenceSchema, content: z.string().min(1).max(256), }); diff --git a/packages/sdk/schemas/extensions/reports.ts b/packages/sdk/schemas/extensions/reports.ts index c49bc8db..9b925b2d 100644 --- a/packages/sdk/schemas/extensions/reports.ts +++ b/packages/sdk/schemas/extensions/reports.ts @@ -1,12 +1,10 @@ import { z } from "zod"; -import { url } from "../common.ts"; -import { EntitySchema } from "../entity.ts"; +import { ReferenceSchema, TransientEntitySchema } from "../entity.ts"; -export const ReportSchema = EntitySchema.extend({ +export const ReportSchema = TransientEntitySchema.extend({ type: z.literal("pub.versia:reports/Report"), - uri: z.null().optional(), - author: url.nullish(), - reported: z.array(url), + author: ReferenceSchema.nullish(), + reported: z.array(ReferenceSchema), tags: z.array(z.string()), comment: z .string() diff --git a/packages/sdk/schemas/extensions/share.ts b/packages/sdk/schemas/extensions/share.ts index 20968a08..31c46c66 100644 --- a/packages/sdk/schemas/extensions/share.ts +++ b/packages/sdk/schemas/extensions/share.ts @@ -1,9 +1,8 @@ import { z } from "zod"; -import { url } from "../common.ts"; -import { EntitySchema } from "../entity.ts"; +import { EntitySchema, ReferenceSchema } from "../entity.ts"; export const ShareSchema = EntitySchema.extend({ type: z.literal("pub.versia:share/Share"), - author: url, - shared: url, + author: ReferenceSchema, + shared: ReferenceSchema, }); diff --git a/packages/sdk/schemas/extensions/vanity.ts b/packages/sdk/schemas/extensions/vanity.ts index 6d47136a..cf168226 100644 --- a/packages/sdk/schemas/extensions/vanity.ts +++ b/packages/sdk/schemas/extensions/vanity.ts @@ -7,11 +7,11 @@ import { z } from "zod"; import { ianaTimezoneRegex, isISOString } from "../../regex.ts"; -import { url } from "../common.ts"; import { AudioContentFormatSchema, ImageContentFormatSchema, } from "../contentformat.ts"; +import { ReferenceSchema } from "../entity.ts"; export const VanityExtensionSchema = z.strictObject({ avatar_overlays: z.array(ImageContentFormatSchema).nullish(), @@ -21,24 +21,21 @@ export const VanityExtensionSchema = z.strictObject({ pronouns: z.record( z.string(), z.array( - z.union([ - z.strictObject({ - subject: z.string(), - object: z.string(), - dependent_possessive: z.string(), - independent_possessive: z.string(), - reflexive: z.string(), - }), - z.string(), - ]), + z.strictObject({ + subject: z.string(), + object: z.string(), + dependent_possessive: z.string(), + independent_possessive: z.string(), + reflexive: z.string(), + }), ), ), birthday: z .string() - .refine((v) => isISOString(v), "must be a valid ISO8601 datetime") + .refine((v) => isISOString(v), "must be a valid RFC 3339 datetime") .nullish(), location: z.string().nullish(), - aliases: z.array(url).nullish(), + aliases: z.array(ReferenceSchema).nullish(), timezone: z .string() .regex(ianaTimezoneRegex, "must be a valid IANA timezone") diff --git a/packages/sdk/schemas/follow.ts b/packages/sdk/schemas/follow.ts index 62c89c32..67b7d731 100644 --- a/packages/sdk/schemas/follow.ts +++ b/packages/sdk/schemas/follow.ts @@ -1,31 +1,26 @@ import { z } from "zod"; -import { url } from "./common.ts"; -import { EntitySchema } from "./entity.ts"; +import { ReferenceSchema, TransientEntitySchema } from "./entity.ts"; -export const FollowSchema = EntitySchema.extend({ +export const FollowSchema = TransientEntitySchema.extend({ type: z.literal("Follow"), - uri: z.null().optional(), - author: url, - followee: url, + author: ReferenceSchema, + followee: ReferenceSchema, }); -export const FollowAcceptSchema = EntitySchema.extend({ +export const FollowAcceptSchema = TransientEntitySchema.extend({ type: z.literal("FollowAccept"), - uri: z.null().optional(), - author: url, - follower: url, + author: ReferenceSchema, + follower: ReferenceSchema, }); -export const FollowRejectSchema = EntitySchema.extend({ +export const FollowRejectSchema = TransientEntitySchema.extend({ type: z.literal("FollowReject"), - uri: z.null().optional(), - author: url, - follower: url, + author: ReferenceSchema, + follower: ReferenceSchema, }); -export const UnfollowSchema = EntitySchema.extend({ +export const UnfollowSchema = TransientEntitySchema.extend({ type: z.literal("Unfollow"), - uri: z.null().optional(), - author: url, - followee: url, + author: ReferenceSchema, + followee: ReferenceSchema, }); diff --git a/packages/sdk/schemas/index.ts b/packages/sdk/schemas/index.ts index aa061705..3c7efdfc 100644 --- a/packages/sdk/schemas/index.ts +++ b/packages/sdk/schemas/index.ts @@ -8,7 +8,11 @@ export { VideoContentFormatSchema, } from "./contentformat.ts"; export { DeleteSchema } from "./delete.ts"; -export { EntitySchema } from "./entity.ts"; +export { + EntitySchema, + ReferenceSchema, + TransientEntitySchema, +} from "./entity.ts"; export { DislikeSchema, LikeSchema } from "./extensions/likes.ts"; export { VoteSchema } from "./extensions/polls.ts"; export { ReactionSchema } from "./extensions/reactions.ts"; diff --git a/packages/sdk/schemas/instance.ts b/packages/sdk/schemas/instance.ts index e62648b5..e014b00e 100644 --- a/packages/sdk/schemas/instance.ts +++ b/packages/sdk/schemas/instance.ts @@ -1,13 +1,10 @@ import { z } from "zod"; import { extensionRegex, semverRegex } from "../regex.ts"; -import { url } from "./common.ts"; import { ImageContentFormatSchema } from "./contentformat.ts"; -import { EntitySchema } from "./entity.ts"; +import { TransientEntitySchema } from "./entity.ts"; -export const InstanceMetadataSchema = EntitySchema.extend({ +export const InstanceMetadataSchema = TransientEntitySchema.extend({ type: z.literal("InstanceMetadata"), - id: z.null().optional(), - uri: z.null().optional(), name: z.string().min(1), software: z.strictObject({ name: z.string().min(1), @@ -28,14 +25,11 @@ export const InstanceMetadataSchema = EntitySchema.extend({ ), }), description: z.string().nullish(), - host: z.string(), - shared_inbox: url.nullish(), + domain: z.string(), public_key: z.strictObject({ key: z.string().min(1), algorithm: z.literal("ed25519"), }), - moderators: url.nullish(), - admins: url.nullish(), logo: ImageContentFormatSchema.nullish(), banner: ImageContentFormatSchema.nullish(), }); diff --git a/packages/sdk/schemas/note.ts b/packages/sdk/schemas/note.ts index 9d58beca..6236a46a 100644 --- a/packages/sdk/schemas/note.ts +++ b/packages/sdk/schemas/note.ts @@ -4,13 +4,13 @@ import { NonTextContentFormatSchema, TextContentFormatSchema, } from "./contentformat.ts"; -import { EntitySchema } from "./entity.ts"; +import { EntitySchema, ReferenceSchema } from "./entity.ts"; import { PollExtensionSchema } from "./extensions/polls.ts"; export const NoteSchema = EntitySchema.extend({ type: z.literal("Note"), - attachments: z.array(NonTextContentFormatSchema).nullish(), - author: url, + attachments: z.array(NonTextContentFormatSchema), + author: ReferenceSchema, category: z .enum([ "microblog", @@ -23,16 +23,6 @@ export const NoteSchema = EntitySchema.extend({ ]) .nullish(), content: TextContentFormatSchema.nullish(), - collections: z - .strictObject({ - replies: url, - quotes: url, - "pub.versia:reactions/Reactions": url.nullish(), - "pub.versia:share/Shares": url.nullish(), - "pub.versia:likes/Likes": url.nullish(), - "pub.versia:likes/Dislikes": url.nullish(), - }) - .catchall(url), device: z .strictObject({ name: z.string(), @@ -40,22 +30,20 @@ export const NoteSchema = EntitySchema.extend({ url: url.nullish(), }) .nullish(), - group: url.or(z.enum(["public", "followers"])).nullish(), - is_sensitive: z.boolean().nullish(), - mentions: z.array(url).nullish(), - previews: z - .array( - z.strictObject({ - link: url, - title: z.string(), - description: z.string().nullish(), - image: url.nullish(), - icon: url.nullish(), - }), - ) - .nullish(), - quotes: url.nullish(), - replies_to: url.nullish(), + group: ReferenceSchema.or(z.enum(["public", "followers"])).nullish(), + is_sensitive: z.boolean(), + mentions: z.array(ReferenceSchema), + previews: z.array( + z.strictObject({ + link: url, + title: z.string(), + description: z.string().nullish(), + image: url.nullish(), + icon: url.nullish(), + }), + ), + quotes: ReferenceSchema.nullish(), + replies_to: ReferenceSchema.nullish(), subject: z.string().nullish(), extensions: EntitySchema.shape.extensions .unwrap() diff --git a/packages/sdk/schemas/user.ts b/packages/sdk/schemas/user.ts index aeaf1256..d0f89982 100644 --- a/packages/sdk/schemas/user.ts +++ b/packages/sdk/schemas/user.ts @@ -1,5 +1,4 @@ import { z } from "zod"; -import { url } from "./common.ts"; import { ImageContentFormatSchema, TextContentFormatSchema, @@ -8,25 +7,17 @@ import { EntitySchema } from "./entity.ts"; import { MigrationExtensionSchema } from "./extensions/migration.ts"; import { VanityExtensionSchema } from "./extensions/vanity.ts"; -export const PublicKeyDataSchema = z.strictObject({ - key: z.string().min(1), - actor: url, - algorithm: z.literal("ed25519"), -}); - export const UserSchema = EntitySchema.extend({ type: z.literal("User"), avatar: ImageContentFormatSchema.nullish(), bio: TextContentFormatSchema.nullish(), display_name: z.string().nullish(), - fields: z - .array( - z.strictObject({ - key: TextContentFormatSchema, - value: TextContentFormatSchema, - }), - ) - .nullish(), + fields: z.array( + z.strictObject({ + key: TextContentFormatSchema, + value: TextContentFormatSchema, + }), + ), username: z .string() .min(1) @@ -35,20 +26,8 @@ export const UserSchema = EntitySchema.extend({ "must be alphanumeric, and may contain _ or -", ), header: ImageContentFormatSchema.nullish(), - public_key: PublicKeyDataSchema, - manually_approves_followers: z.boolean().nullish(), - indexable: z.boolean().nullish(), - inbox: url, - collections: z - .object({ - featured: url, - followers: url, - following: url, - outbox: url, - "pub.versia:likes/Likes": url.nullish(), - "pub.versia:likes/Dislikes": url.nullish(), - }) - .catchall(url), + manually_approves_followers: z.boolean(), + indexable: z.boolean(), extensions: EntitySchema.shape.extensions .unwrap() .unwrap() diff --git a/types/api.ts b/types/api.ts index 22fbeda2..026904e9 100644 --- a/types/api.ts +++ b/types/api.ts @@ -29,6 +29,7 @@ export interface ApiRouteExports { } export type KnownEntity = + | VersiaEntities.Entity | VersiaEntities.Note | VersiaEntities.InstanceMetadata | VersiaEntities.User From b7e77097ba8673936bfe96e6e5f81100ec7b1747 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 31 Mar 2026 04:13:16 +0200 Subject: [PATCH 2/3] feat(federation): Finalize Versia 0.6 port --- bun.lock | 565 ++-- cli/user/refetch.ts | 5 +- flake.nix | 2 +- package.json | 7 +- .../routes/api/v1/accounts/[id]/refetch.ts | 5 +- .../routes/api/v1/accounts/lookup/index.ts | 5 +- .../routes/api/v1/accounts/search/index.ts | 2 +- packages/api/routes/api/v2/search/index.ts | 2 +- .../api/routes/oauth/sso/[issuer]/callback.ts | 1 + packages/api/routes/versia/v0.6/inbox.test.ts | 25 +- packages/api/routes/versia/v0.6/inbox.ts | 2 +- packages/kit/db/note.ts | 59 +- packages/kit/db/user.ts | 36 +- packages/kit/inbox-processor.ts | 74 +- packages/kit/parsers.ts | 4 +- .../migrations/0054_good_madelyne_pryor.sql | 14 + .../tables/migrations/meta/0054_snapshot.json | 2394 +++++++++++++++++ .../kit/tables/migrations/meta/_journal.json | 7 + patches/bun-bagel@1.2.0.patch | 11 + utils/bull-board.ts | 7 +- 20 files changed, 2788 insertions(+), 439 deletions(-) create mode 100644 packages/kit/tables/migrations/0054_good_madelyne_pryor.sql create mode 100644 packages/kit/tables/migrations/meta/0054_snapshot.json create mode 100644 patches/bun-bagel@1.2.0.patch diff --git a/bun.lock b/bun.lock index 827fb5fc..e9221c83 100644 --- a/bun.lock +++ b/bun.lock @@ -228,6 +228,9 @@ "msgpackr-extract", "protobufjs", ], + "patchedDependencies": { + "bun-bagel@1.2.0": "patches/bun-bagel@1.2.0.patch", + }, "catalog": { "@biomejs/biome": "2.3.10", "@bull-board/api": "~6.15.0", @@ -267,7 +270,7 @@ "hono-openapi": "~1.1.2", "hono-rate-limiter": "~0.5.1", "html-to-text": "~9.0.5", - "ioredis": "~5.8.2", + "ioredis": "5.9.2", "ip-matching": "~2.1.2", "iso-639-1": "~3.1.5", "linkify-html": "~4.3.2", @@ -306,7 +309,7 @@ "zod-validation-error": "~5.0.0", }, "packages": { - "@algolia/abtesting": ["@algolia/abtesting@1.10.0", "", { "dependencies": { "@algolia/client-common": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-mQT3jwuTgX8QMoqbIR7mPlWkqQqBPQaPabQzm37xg2txMlaMogK/4hCiiESGdg39MlHZOVHeV+0VJuE7f5UK8A=="], + "@algolia/abtesting": ["@algolia/abtesting@1.15.1", "", { "dependencies": { "@algolia/client-common": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-2yuIC48rUuHGhU1U5qJ9kJHaxYpJ0jpDHJVI5ekOxSMYXlH4+HP+pA31G820lsAznfmu2nzDV7n5RO44zIY1zw=="], "@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.17.7", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", "@algolia/autocomplete-shared": "1.17.7" } }, "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q=="], @@ -316,47 +319,47 @@ "@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.17.7", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg=="], - "@algolia/client-abtesting": ["@algolia/client-abtesting@5.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-KY5CcrWhRTUo/lV7KcyjrZkPOOF9bjgWpMj9z98VA+sXzVpZtkuskBLCKsWYFp2sbwchZFTd3wJM48H0IGgF7g=="], + "@algolia/client-abtesting": ["@algolia/client-abtesting@5.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-h6M7HzPin+45/l09q0r2dYmocSSt2MMGOOk5c4O5K/bBBlEwf1BKfN6z+iX4b8WXcQQhf7rgQwC52kBZJt/ZZw=="], - "@algolia/client-analytics": ["@algolia/client-analytics@5.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-LKOCE8S4ewI9bN3ot9RZoYASPi8b78E918/DVPW3HHjCMUe6i+NjbNG6KotU4RpP6AhRWZjjswbOkWelUO+OoA=="], + "@algolia/client-analytics": ["@algolia/client-analytics@5.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-048T9/Z8OeLmTk8h76QUqaNFp7Rq2VgS2Zm6Y2tNMYGQ1uNuzePY/udB5l5krlXll7ZGflyCjFvRiOtlPZpE9g=="], - "@algolia/client-common": ["@algolia/client-common@5.44.0", "", {}, "sha512-1yyJm4OYC2cztbS28XYVWwLXdwpLsMG4LoZLOltVglQ2+hc/i9q9fUDZyjRa2Bqt4DmkIfezagfMrokhyH4uxQ=="], + "@algolia/client-common": ["@algolia/client-common@5.49.1", "", {}, "sha512-vp5/a9ikqvf3mn9QvHN8PRekn8hW34aV9eX+O0J5mKPZXeA6Pd5OQEh2ZWf7gJY6yyfTlLp5LMFzQUAU+Fpqpg=="], - "@algolia/client-insights": ["@algolia/client-insights@5.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-wVQWK6jYYsbEOjIMI+e5voLGPUIbXrvDj392IckXaCPvQ6vCMTXakQqOYCd+znQdL76S+3wHDo77HZWiAYKrtA=="], + "@algolia/client-insights": ["@algolia/client-insights@5.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-B6N7PgkvYrul3bntTz/l6uXnhQ2bvP+M7NqTcayh681tSqPaA5cJCUBp/vrP7vpPRpej4Eeyx2qz5p0tE/2N2g=="], - "@algolia/client-personalization": ["@algolia/client-personalization@5.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-lkgRjOjOkqmIkebHjHpU9rLJcJNUDMm+eVSW/KJQYLjGqykEZxal+nYJJTBbLceEU2roByP/+27ZmgIwCdf0iA=="], + "@algolia/client-personalization": ["@algolia/client-personalization@5.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-v+4DN+lkYfBd01Hbnb9ZrCHe7l+mvihyx218INRX/kaCXROIWUDIT1cs3urQxfE7kXBFnLsqYeOflQALv/gA5w=="], - "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-sYfhgwKu6NDVmZHL1WEKVLsOx/jUXCY4BHKLUOcYa8k4COCs6USGgz6IjFkUf+niwq8NCECMmTC4o/fVQOalsA=="], + "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-Un11cab6ZCv0W+Jiak8UktGIqoa4+gSNgEZNfG8m8eTsXGqwIEr370H3Rqwj87zeNSlFpH2BslMXJ/cLNS1qtg=="], - "@algolia/client-search": ["@algolia/client-search@5.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-/FRKUM1G4xn3vV8+9xH1WJ9XknU8rkBGlefruq9jDhYUAvYozKimhrmC2pRqw/RyHhPivmgZCRuC8jHP8piz4Q=="], + "@algolia/client-search": ["@algolia/client-search@5.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-Nt9hri7nbOo0RipAsGjIssHkpLMHHN/P7QqENywAq5TLsoYDzUyJGny8FEiD/9KJUxtGH8blGpMedilI6kK3rA=="], - "@algolia/ingestion": ["@algolia/ingestion@1.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-5+S5ynwMmpTpCLXGjTDpeIa81J+R4BLH0lAojOhmeGSeGEHQTqacl/4sbPyDTcidvnWhaqtyf8m42ue6lvISAw=="], + "@algolia/ingestion": ["@algolia/ingestion@1.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-b5hUXwDqje0Y4CpU6VL481DXgPgxpTD5sYMnfQTHKgUispGnaCLCm2/T9WbJo1YNUbX3iHtYDArp804eD6CmRQ=="], - "@algolia/monitoring": ["@algolia/monitoring@1.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-xhaTN8pXJjR6zkrecg4Cc9YZaQK2LKm2R+LkbAq+AYGBCWJxtSGlNwftozZzkUyq4AXWoyoc0x2SyBtq5LRtqQ=="], + "@algolia/monitoring": ["@algolia/monitoring@1.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-bvrXwZ0WsL3rN6Q4m4QqxsXFCo6WAew7sAdrpMQMK4Efn4/W920r9ptOuckejOSSvyLr9pAWgC5rsHhR2FYuYw=="], - "@algolia/recommend": ["@algolia/recommend@5.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-GNcite/uOIS7wgRU1MT7SdNIupGSW+vbK9igIzMePvD2Dl8dy0O3urKPKIbTuZQqiVH1Cb84y5cgLvwNrdCj/Q=="], + "@algolia/recommend": ["@algolia/recommend@5.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-h2yz3AGeGkQwNgbLmoe3bxYs8fac4An1CprKTypYyTU/k3Q+9FbIvJ8aS1DoBKaTjSRZVoyQS7SZQio6GaHbZw=="], - "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0" } }, "sha512-YZHBk72Cd7pcuNHzbhNzF/FbbYszlc7JhZlDyQAchnX5S7tcemSS96F39Sy8t4O4WQLpFvUf1MTNedlitWdOsQ=="], + "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1" } }, "sha512-2UPyRuUR/qpqSqH8mxFV5uBZWEpxhGPHLlx9Xf6OVxr79XO2ctzZQAhsmTZ6X22x+N8MBWpB9UEky7YU2HGFgA=="], - "@algolia/requester-fetch": ["@algolia/requester-fetch@5.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0" } }, "sha512-B9WHl+wQ7uf46t9cq+vVM/ypVbOeuldVDq9OtKsX2ApL2g/htx6ImB9ugDOOJmB5+fE31/XPTuCcYz/j03+idA=="], + "@algolia/requester-fetch": ["@algolia/requester-fetch@5.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1" } }, "sha512-N+xlE4lN+wpuT+4vhNEwPVlrfN+DWAZmSX9SYhbz986Oq8AMsqdntOqUyiOXVxYsQtfLwmiej24vbvJGYv1Qtw=="], - "@algolia/requester-node-http": ["@algolia/requester-node-http@5.44.0", "", { "dependencies": { "@algolia/client-common": "5.44.0" } }, "sha512-MULm0qeAIk4cdzZ/ehJnl1o7uB5NMokg83/3MKhPq0Pk7+I0uELGNbzIfAkvkKKEYcHALemKdArtySF9eKzh/A=="], + "@algolia/requester-node-http": ["@algolia/requester-node-http@5.49.1", "", { "dependencies": { "@algolia/client-common": "5.49.1" } }, "sha512-zA5bkUOB5PPtTr182DJmajCiizHp0rCJQ0Chf96zNFvkdESKYlDeYA3tQ7r2oyHbu/8DiohAQ5PZ85edctzbXA=="], "@apm-js-collab/code-transformer": ["@apm-js-collab/code-transformer@0.8.2", "", {}, "sha512-YRjJjNq5KFSjDUoqu5pFUWrrsvGOxl6c3bu+uMFc9HNNptZ2rNU/TI2nLw4jnhQNtka972Ee2m3uqbvDQtPeCA=="], "@apm-js-collab/tracing-hooks": ["@apm-js-collab/tracing-hooks@0.3.1", "", { "dependencies": { "@apm-js-collab/code-transformer": "^0.8.0", "debug": "^4.4.1", "module-details-from-path": "^1.0.4" } }, "sha512-Vu1CbmPURlN5fTboVuKMoJjbO5qcq9fA5YXpskx3dXe/zTBvjODFoerw+69rVBlRLrJpwPqSDqEuJDEKIrTldw=="], - "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], - "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], + "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="], - "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], + "@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="], - "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], + "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], "@badgateway/oauth2-client": ["@badgateway/oauth2-client@3.3.1", "", {}, "sha512-7R4mZocEt8nOIMCz9cQyxsrY7n/jhFW9YUW6Er9ySnBzH92wA0KmQUR1cT2encq2Lix6kRD2GyQRAmT1dWtwzg=="], @@ -386,21 +389,23 @@ "@bull-board/ui": ["@bull-board/ui@6.15.0", "", { "dependencies": { "@bull-board/api": "6.15.0" } }, "sha512-bb/j6VMq2cfPoE/ZiUO7AcYTL0IjtxvKxkYV0zu+i1pc+JEv3ct4BItCII57knJR/YjZKGmdfr079KJFvzXC5A=="], - "@clerc/advanced-types": ["@clerc/advanced-types@1.0.0-beta.30", "", {}, "sha512-97nD1jeCNZKh8Zm1/b+o6rX8oBKYEMDZqA2+nrick2Z/EvL/6+foQY4k3bq6eIGZ5OY8VM1PjySouYbaZ05DiQ=="], + "@clerc/advanced-types": ["@clerc/advanced-types@1.0.3", "", { "peerDependencies": { "@clerc/parser": "*" } }, "sha512-tKcWTeZHA4rfPGZojpgeWsXtRkNr+iKFqUIHFyyzA6FKL5zAD1/Dn+KqirHSZeoe9KZhgEWXnEeRttt6GgAE9A=="], - "@clerc/core": ["@clerc/core@1.0.0-beta.30", "", { "dependencies": { "@clerc/advanced-types": "1.0.0-beta.30", "@clerc/parser": "1.0.0-beta.30", "lite-emit": "^4.0.0" } }, "sha512-c2qESM1/BOI0nFP5wivf1dCrM9BzQZzSkuawve6DDdDL8PeF9e/6EDAU854GCSGSa++9eioNqJwrnHT1qkMTKg=="], + "@clerc/core": ["@clerc/core@1.0.3", "", { "dependencies": { "@clerc/advanced-types": "1.0.3", "@clerc/parser": "1.0.3", "@clerc/utils": "1.0.3", "lite-emit": "^4.0.0" } }, "sha512-9pB29hqBI79U02Aghy26ZMPcMvV+dutMEAPT7AZxHj+UZbgcreveWfntkggSUrcEpFUpwXL7/IId5XdulMHuPA=="], - "@clerc/parser": ["@clerc/parser@1.0.0-beta.30", "", {}, "sha512-QC3+EF7yFnamZNQrcpTY8cdpoGHzDPXLjQcDQwX7Qp9TD9cN7RzU4aAu2aEoRP/ZVjZb6BGnMc/zGR/fYSG5IQ=="], + "@clerc/parser": ["@clerc/parser@1.0.3", "", { "dependencies": { "@clerc/utils": "1.0.3" } }, "sha512-EiBJ5n9qI1+qIfFZoWCcCHPqBBXvoDbDa9sxY5x2101Rknr5QFtCCkFLd1e88TLH8sSek6wZL75tlT3fhDsDYA=="], - "@clerc/plugin-completions": ["@clerc/plugin-completions@1.0.0-beta.30", "", { "dependencies": { "@bomb.sh/tab": "^0.0.10" }, "peerDependencies": { "@clerc/core": "*" }, "bin": { "my-cli": "src/a.mjs" } }, "sha512-PsuSVfoVg7gu4gj/3K/LWP2MFgTrUr1xrrxUXVlmTX7prQzdQM5mJX01yXXGdw6pWUMr5Xkc0tNYDgbVeyAF0w=="], + "@clerc/plugin-completions": ["@clerc/plugin-completions@1.0.3", "", { "dependencies": { "@bomb.sh/tab": "^0.0.10" }, "peerDependencies": { "@clerc/core": "*" }, "bin": { "my-cli": "src/a.mjs" } }, "sha512-jlsp0He+5niJ9/cKdDXZsEwqcG9RVNN45IZRyW+/za27EUcTnAdXHEG81FzXSlGbgVCSMio9h46wQYWcilD3sA=="], - "@clerc/plugin-friendly-error": ["@clerc/plugin-friendly-error@1.0.0-beta.30", "", { "dependencies": { "kons": "^0.7.1" }, "peerDependencies": { "@clerc/core": "*" } }, "sha512-VAXzrl24Ak3TJ9/foPh26phnA+a+oeIUZbo+zKajQKKMD54Sa4ToFlxM73+68T/y2juHyc/qkNr+TDpL5VNRRg=="], + "@clerc/plugin-friendly-error": ["@clerc/plugin-friendly-error@1.0.3", "", { "dependencies": { "kons": "^0.7.1" }, "peerDependencies": { "@clerc/core": "*" } }, "sha512-CQsqbC0Q8LmtdH06P4RuJXovh/YI9P7FKMNEhQPbK3AjA7sHEliQZGIrIOOB+2bLTkIf8fr3EjdteOaShIZaJw=="], - "@clerc/plugin-help": ["@clerc/plugin-help@1.0.0-beta.30", "", { "dependencies": { "@types/text-table": "^0.2.5", "string-width": "^8.1.0", "text-table": "^0.2.0", "yoctocolors": "^2.1.2" }, "peerDependencies": { "@clerc/core": "*" } }, "sha512-VMMxIrw5NdLKo3KAZFjbURlRyS/U+A1+FT3tEpGkjmo/mEXsgctsUok7+IMmWaBrkovhoaloSZAoWdd7RSbMUg=="], + "@clerc/plugin-help": ["@clerc/plugin-help@1.0.3", "", { "dependencies": { "@clerc/utils": "1.0.3", "@uttr/tint": "^0.1.3", "string-width": "^8.1.0", "text-table": "^0.2.0" }, "peerDependencies": { "@clerc/core": "*" } }, "sha512-awHSUckNQ6PYclyzknX17SeO+Z+vI8OGDHmubMgRv75Y3qjdkaYW2jZ/8m4vSnB2YDoNwm+5Gq5pJlSH+aKwow=="], - "@clerc/plugin-not-found": ["@clerc/plugin-not-found@1.0.0-beta.30", "", { "dependencies": { "didyoumean2": "^7.0.4", "yoctocolors": "^2.1.2" }, "peerDependencies": { "@clerc/core": "*" } }, "sha512-tWpAYt/08lGBo+7qkI3OpYjgV1W91yWVIFcNawrYEXlsmxAxdGcPG+pg13FJMJqxla0YWHLylploQz7i8k9S/g=="], + "@clerc/plugin-not-found": ["@clerc/plugin-not-found@1.0.3", "", { "dependencies": { "@uttr/tint": "^0.1.3", "didyoumean2": "^7.0.4" }, "peerDependencies": { "@clerc/core": "*" } }, "sha512-sN7lRwje59Zp5aUlZCWD3u9QFkaaGFzMjRdAOolIMzCWhQl63evyBFCxTaiEY02PvsoSeu3sh65k28VLk0show=="], - "@clerc/plugin-version": ["@clerc/plugin-version@1.0.0-beta.30", "", { "peerDependencies": { "@clerc/core": "*" } }, "sha512-1MW065aevUJ7NTzOYg98vhCnZaMYtukvRJld030pg9r9ZF4cTOolFzXENY01AcaTB2HhlfWUyM+/s628dhRbIA=="], + "@clerc/plugin-version": ["@clerc/plugin-version@1.0.3", "", { "dependencies": { "@clerc/utils": "1.0.3" }, "peerDependencies": { "@clerc/core": "*" } }, "sha512-h7SN7ely+PoVqnRLOHerb1EsW1mmJUhOH/dBhbss40wVCfBOdxEFYQgw5FEHfn34Sn3fMawuNXsGqyhAYIJOug=="], + + "@clerc/utils": ["@clerc/utils@1.0.3", "", {}, "sha512-LrkB9y/qKfUSMKpCyxUXrLTvOCM8oKf3RNIpBI90BMzfD9TIpCsU7CEJFTYjIlgtRvp/VV84PwK+YHv/46cxFA=="], "@docsearch/css": ["@docsearch/css@3.8.2", "", {}, "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ=="], @@ -410,7 +415,7 @@ "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], - "@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], + "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="], @@ -474,9 +479,9 @@ "@hackmd/markdown-it-task-lists": ["@hackmd/markdown-it-task-lists@2.1.4", "", {}, "sha512-njMloWVihC7a7N4zxczv547bgNxPVG3GBzh6Z6f2xnO8/92JaxTmQuMV7YvaKKkOyhh2RW4RT84uSgax8u4qfQ=="], - "@hono/standard-validator": ["@hono/standard-validator@0.2.1", "", { "peerDependencies": { "@standard-schema/spec": "1.0.0", "hono": ">=3.9.0" } }, "sha512-uF1W7/iSWi0r5Mugj5ZzdlCVp/KeGatS6JYt+Eht9xKO0IDtdZbdaLApgjrzHINQQa+Wnxw2pcX6EfO+vgB+Wg=="], + "@hono/standard-validator": ["@hono/standard-validator@0.2.2", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "hono": ">=3.9.0" } }, "sha512-mJ7W84Bt/rSvoIl63Ynew+UZOHAzzRAoAXb3JaWuxAkM/Lzg+ZHTCUiz77KOtn2e623WNN8LkD57Dk0szqUrIw=="], - "@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.59", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-fYx/InyQsWFW4wVxWka3CGDJ6m/fXoTqWBSl+oA3FBXO5RhPAb6S3Y5bRgCPnrYevErH8VjAL0TZevIqlN2PhQ=="], + "@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.71", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-rNoDFbq1fAYiEexBvrw613/xiUOPEu5MKVV/X8lI64AgdTzLQUUemr9f9fplxUMPoxCBP2rWzlhOEeTHk/Sf0Q=="], "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], @@ -530,23 +535,19 @@ "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], - "@inquirer/ansi": ["@inquirer/ansi@2.0.2", "", {}, "sha512-SYLX05PwJVnW+WVegZt1T4Ip1qba1ik+pNJPDiqvk6zS5Y/i8PhRzLpGEtVd7sW0G8cMtkD8t4AZYhQwm8vnww=="], + "@inquirer/ansi": ["@inquirer/ansi@2.0.3", "", {}, "sha512-g44zhR3NIKVs0zUesa4iMzExmZpLUdTLRMCStqX3GE5NT6VkPcxQGJ+uC8tDgBUC/vB1rUhUd55cOf++4NZcmw=="], - "@inquirer/confirm": ["@inquirer/confirm@6.0.3", "", { "dependencies": { "@inquirer/core": "^11.1.0", "@inquirer/type": "^4.0.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-lyEvibDFL+NA5R4xl8FUmNhmu81B+LDL9L/MpKkZlQDJZXzG8InxiqYxiAlQYa9cqLLhYqKLQwZqXmSTqCLjyw=="], + "@inquirer/confirm": ["@inquirer/confirm@6.0.8", "", { "dependencies": { "@inquirer/core": "^11.1.5", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-Di6dgmiZ9xCSUxWUReWTqDtbhXCuG2MQm2xmgSAIruzQzBqNf49b8E07/vbCYY506kDe8BiwJbegXweG8M1klw=="], - "@inquirer/core": ["@inquirer/core@11.1.0", "", { "dependencies": { "@inquirer/ansi": "^2.0.2", "@inquirer/figures": "^2.0.2", "@inquirer/type": "^4.0.2", "cli-width": "^4.1.0", "mute-stream": "^3.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^9.0.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-+jD/34T1pK8M5QmZD/ENhOfXdl9Zr+BrQAUc5h2anWgi7gggRq15ZbiBeLoObj0TLbdgW7TAIQRU2boMc9uOKQ=="], + "@inquirer/core": ["@inquirer/core@11.1.5", "", { "dependencies": { "@inquirer/ansi": "^2.0.3", "@inquirer/figures": "^2.0.3", "@inquirer/type": "^4.0.3", "cli-width": "^4.1.0", "fast-wrap-ansi": "^0.2.0", "mute-stream": "^3.0.0", "signal-exit": "^4.1.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-QQPAX+lka8GyLcZ7u7Nb1h6q72iZ/oy0blilC3IB2nSt1Qqxp7akt94Jqhi/DzARuN3Eo9QwJRvtl4tmVe4T5A=="], - "@inquirer/figures": ["@inquirer/figures@2.0.2", "", {}, "sha512-qXm6EVvQx/FmnSrCWCIGtMHwqeLgxABP8XgcaAoywsL0NFga9gD5kfG0gXiv80GjK9Hsoz4pgGwF/+CjygyV9A=="], + "@inquirer/figures": ["@inquirer/figures@2.0.3", "", {}, "sha512-y09iGt3JKoOCBQ3w4YrSJdokcD8ciSlMIWsD+auPu+OZpfxLuyz+gICAQ6GCBOmJJt4KEQGHuZSVff2jiNOy7g=="], - "@inquirer/type": ["@inquirer/type@4.0.2", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-cae7mzluplsjSdgFA6ACLygb5jC8alO0UUnFPyu0E7tNRPrL+q/f8VcSXp+cjZQ7l5CMpDpi2G1+IQvkOiL1Lw=="], + "@inquirer/type": ["@inquirer/type@4.0.3", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-cKZN7qcXOpj1h+1eTTcGDVLaBIHNMT1Rz9JqJP5MnEJ0JhgVWllx7H/tahUp5YEK1qaByH2Itb8wLG/iScD5kw=="], - "@ioredis/commands": ["@ioredis/commands@1.4.0", "", {}, "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ=="], + "@ioredis/commands": ["@ioredis/commands@1.5.0", "", {}, "sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow=="], - "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], - - "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], - - "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + "@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -560,15 +561,15 @@ "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], - "@logtape/file": ["@logtape/file@1.3.4", "", { "peerDependencies": { "@logtape/logtape": "^1.3.4" } }, "sha512-tIE9T/WR3iqnsacN/el0DdvScNeofpZr54M6AP+Pw7kE7tDOTMnzK2JMd7dcx1mrsF3ZVqUkxToolE70u68blg=="], + "@logtape/file": ["@logtape/file@1.3.7", "", { "peerDependencies": { "@logtape/logtape": "^1.3.7" } }, "sha512-7A9BmUc85tn+g+Yq3qLlNH2mwseflJsMNcCIur4Jj8qV8okBl3TnxHFH2yQfbgW/X1Hw1G3bd0nKI3kf63NWCw=="], - "@logtape/hono": ["@logtape/hono@1.3.4", "", { "peerDependencies": { "@logtape/logtape": "^1.3.4", "hono": "^4.0.0" } }, "sha512-+usxX/6b9I6rZaZWPCv/BvI8vdn1rTWeE4JGfwOLKNAVhSuQ/gb0w1r3tRQcCv+Z17jlIVsbqA7qfaBF8V5UTQ=="], + "@logtape/hono": ["@logtape/hono@1.3.7", "", { "peerDependencies": { "@logtape/logtape": "^1.3.7", "hono": "^4.0.0" } }, "sha512-CWTrml+qyHkr7n2c8qgHmFLH+skrYcPQqY/ZX2ddFfONBY233FzpgXAnyuPmFovW4M7U38q607sYpNH4i48Dxg=="], - "@logtape/logtape": ["@logtape/logtape@1.3.4", "", {}, "sha512-zFdMXSvyFp3R9FzjxKD9hP+MGdTlOTOutxL9Kg2qLvIUrZ4+q4KvvQC4Zo7LTGWdR2Z5RlzjwSBjyANhsntriw=="], + "@logtape/logtape": ["@logtape/logtape@1.3.7", "", {}, "sha512-YgF+q9op97oLLPwc7TcTNIllTArVtTwkwyKky6XVzAXQcBrvFXXtMuwJSryONAyOUSItrx994O/HABOrszZyFg=="], - "@logtape/otel": ["@logtape/otel@1.3.4", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.208.0", "@opentelemetry/exporter-logs-otlp-grpc": "^0.208.0", "@opentelemetry/exporter-logs-otlp-http": "^0.208.0", "@opentelemetry/exporter-logs-otlp-proto": "^0.208.0", "@opentelemetry/otlp-exporter-base": "^0.208.0", "@opentelemetry/resources": "^2.2.0", "@opentelemetry/sdk-logs": "^0.208.0", "@opentelemetry/semantic-conventions": "^1.38.0" }, "peerDependencies": { "@logtape/logtape": "^1.3.4" } }, "sha512-88vmByhJ2LYxYdzWtvNxFOAdaVGlwCDpc+8iIQUAB3OmpbvcOot1fRRZcDPg4iA7gLTkYs0pbXb718F/LLafzQ=="], + "@logtape/otel": ["@logtape/otel@1.3.7", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.208.0", "@opentelemetry/exporter-logs-otlp-grpc": "^0.208.0", "@opentelemetry/exporter-logs-otlp-http": "^0.208.0", "@opentelemetry/exporter-logs-otlp-proto": "^0.208.0", "@opentelemetry/otlp-exporter-base": "^0.208.0", "@opentelemetry/resources": "^2.2.0", "@opentelemetry/sdk-logs": "^0.208.0", "@opentelemetry/semantic-conventions": "^1.38.0" }, "peerDependencies": { "@logtape/logtape": "^1.3.7" } }, "sha512-MW9tgdBBMw3iKFQDiCYW4VKY9mWtSlu34JgRGRMqzQgFRjU8P15V7c8mA7daea52jeh3BbjpApQp+Ok9BlJg1Q=="], - "@logtape/sentry": ["@logtape/sentry@1.3.4", "", { "peerDependencies": { "@logtape/logtape": "^1.3.4", "@sentry/core": ">=8.0.0" } }, "sha512-AzXKEZvfHtjX3b/e2a9L7L8hrstll355oThh/F6nun8cplCvzk5fwN1YwcPp8vvAnaPSuUfRXGbAwP0x+nRoMQ=="], + "@logtape/sentry": ["@logtape/sentry@1.3.7", "", { "peerDependencies": { "@logtape/logtape": "^1.3.7", "@sentry/core": ">=8.0.0" } }, "sha512-WL/dORb4rqoZtpjQIh/u3upAfm70tt+BnCR6GyNYFOKkE3+L4q4hfoLvbLhvDxfXd/7LB3szrTsYKoFQgkd0Jg=="], "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="], @@ -592,9 +593,9 @@ "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.208.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg=="], - "@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.2.0", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-qRkLWiUEZNAmYapZ7KGS5C4OmBLcP/H2foXeOEaowYCR0wi89fHejrfYfbuLVCMLp/dWZXKvQusdbUEZjERfwQ=="], + "@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.5.1", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MHbu8XxCHcBn6RwvCt2Vpn1WnLMNECfNKYB14LI5XypcgH4IE0/DiVifVR9tAkwPMyLXN8dOoPJfya3IryLQVw=="], - "@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], + "@opentelemetry/core": ["@opentelemetry/core@2.5.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-Dwlc+3HAZqpgTYq0MUyZABjFkcrKTePwuiFVLjahGD8cx3enqihmpAmdgNFO1R4m/sIe5afjJrA25Prqy4NXlA=="], "@opentelemetry/exporter-logs-otlp-grpc": ["@opentelemetry/exporter-logs-otlp-grpc@0.208.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-exporter-base": "0.208.0", "@opentelemetry/otlp-grpc-exporter-base": "0.208.0", "@opentelemetry/otlp-transformer": "0.208.0", "@opentelemetry/sdk-logs": "0.208.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-AmZDKFzbq/idME/yq68M155CJW1y056MNBekH9OZewiZKaqgwYN4VYfn3mXVPftYsfrCM2r4V6tS8H2LmfiDCg=="], @@ -656,23 +657,23 @@ "@opentelemetry/redis-common": ["@opentelemetry/redis-common@0.38.2", "", {}, "sha512-1BCcU93iwSRZvDAgwUxC/DV4T/406SkMfxGqu5ojc3AvNI+I9GhV7v0J1HljsczuuhcnFLYqD5VmwVXfCGHzxA=="], - "@opentelemetry/resources": ["@opentelemetry/resources@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A=="], + "@opentelemetry/resources": ["@opentelemetry/resources@2.5.1", "", { "dependencies": { "@opentelemetry/core": "2.5.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-BViBCdE/GuXRlp9k7nS1w6wJvY5fnFX5XvuEtWsTAOQFIO89Eru7lGW3WbfbxtCuZ/GbrJfAziXG0w0dpxL7eQ=="], "@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.208.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.208.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-QlAyL1jRpOeaqx7/leG1vJMp84g0xKP6gJmfELBpnI4O/9xPX+Hu5m1POk9Kl+veNkyth5t19hRlN6tNY1sjbA=="], "@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-G5KYP6+VJMZzpGipQw7Giif48h6SGQ2PFKEYCybeXJsOCB4fp8azqMAAzE5lnnHK3ZVwYQrgmFbsUJO/zOnwGw=="], - "@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw=="], + "@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.5.1", "", { "dependencies": { "@opentelemetry/core": "2.5.1", "@opentelemetry/resources": "2.5.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-iZH3Gw8cxQn0gjpOjJMmKLd9GIaNh/E3v3ST67vyzLSxHBs14HsG4dy7jMYyC5WXGdBVEcM7U/XTF5hCQxjDMw=="], - "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.38.0", "", {}, "sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg=="], + "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.39.0", "", {}, "sha512-R5R9tb2AXs2IRLNKLBJDynhkfmx7mX0vi8NkhZb3gUkPWHn6HXk5J8iQ/dql0U3ApfWym4kXXmBDRGO+oeOfjg=="], "@opentelemetry/sql-common": ["@opentelemetry/sql-common@0.41.2", "", { "dependencies": { "@opentelemetry/core": "^2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0" } }, "sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ=="], - "@poppinss/colors": ["@poppinss/colors@4.1.5", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw=="], + "@poppinss/colors": ["@poppinss/colors@4.1.6", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg=="], - "@poppinss/dumper": ["@poppinss/dumper@0.6.5", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw=="], + "@poppinss/dumper": ["@poppinss/dumper@0.7.0", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-0UTYalzk2t6S4rA2uHOz5bSSW2CHdv4vggJI6Alg90yvl0UgXs6XSXpH96OH+bRkX4J/06djv29pqXJ0lq5Kag=="], - "@poppinss/exception": ["@poppinss/exception@1.2.2", "", {}, "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg=="], + "@poppinss/exception": ["@poppinss/exception@1.2.3", "", {}, "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw=="], "@prisma/instrumentation": ["@prisma/instrumentation@6.19.0", "", { "dependencies": { "@opentelemetry/instrumentation": ">=0.52.0 <1" }, "peerDependencies": { "@opentelemetry/api": "^1.8" } }, "sha512-QcuYy25pkXM8BJ37wVFBO7Zh34nyRV1GOb2n3lPkkbRYfl4hWl3PTcImP41P0KrzVXfa/45p6eVCos27x3exIg=="], @@ -696,57 +697,63 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.53.3", "", { "os": "android", "cpu": "arm" }, "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.59.0", "", { "os": "android", "cpu": "arm" }, "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.53.3", "", { "os": "android", "cpu": "arm64" }, "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.59.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.53.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.59.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.53.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.59.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.53.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.59.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.53.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.59.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA=="], - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg=="], - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.53.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw=="], + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g=="], + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA=="], - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A=="], + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.53.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w=="], + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.59.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w=="], - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.53.3", "", { "os": "none", "cpu": "arm64" }, "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg=="], - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.53.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg=="], - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.53.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA=="], + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.59.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ=="], - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg=="], + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.59.0", "", { "os": "none", "cpu": "arm64" }, "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA=="], - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.59.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A=="], - "@scalar/core": ["@scalar/core@0.3.28", "", { "dependencies": { "@scalar/types": "0.5.4" } }, "sha512-Ka+g5P3Fe4f9lsJcBxfI+XAgwMYeZRgzIBWw1/HBrDoRmH3rV/N//410MBKEYXUw7pWpS+dZPJANZRvU5jtxhw=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.59.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA=="], - "@scalar/helpers": ["@scalar/helpers@0.2.4", "", {}, "sha512-G7oGybO2QXM+MIxa4OZLXaYsS9mxKygFgOcY4UOXO6xpVoY5+8rahdak9cPk7HNj8RZSt4m/BveoT8g5BtnXxg=="], + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA=="], - "@scalar/hono-api-reference": ["@scalar/hono-api-reference@0.9.30", "", { "dependencies": { "@scalar/core": "0.3.28" }, "peerDependencies": { "hono": "^4.10.3" } }, "sha512-a9cPluqfi1bgX2p7PJl/2O4jgPcoAl/ecSAe74TbPYIi27A0O0bkUBscO7WNRJhWJ1GVVxX8NvJTNlDxUNBlpg=="], + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA=="], - "@scalar/types": ["@scalar/types@0.5.4", "", { "dependencies": { "@scalar/helpers": "0.2.4", "nanoid": "5.1.5", "type-fest": "5.0.0", "zod": "^4.1.11" } }, "sha512-5FNQH/zx3tnERzxfpErscPHfRxLCuhncmhFYiaSz196Xi2iG1YI08BtxTV2slfT6of52epJ/MrKerarplKf9eg=="], + "@scalar/core": ["@scalar/core@0.3.42", "", { "dependencies": { "@scalar/types": "0.6.7" } }, "sha512-RbyooMuG4oQEOhiA/tC+++bkIK1zeYGNxrTzSAgTrTzVlbFKPzw72fs4gX9/eHDo7qVc9FsymIW6qVpWbySzNg=="], + + "@scalar/helpers": ["@scalar/helpers@0.2.16", "", {}, "sha512-JlDUKdmwAHdcFUdTngNtx/uhLKTBACXlgvri7iKb6Jx6ImRIBgHwxZNAqlil1L047+QBrKh97lnezNpzNQAffQ=="], + + "@scalar/hono-api-reference": ["@scalar/hono-api-reference@0.9.45", "", { "dependencies": { "@scalar/core": "0.3.42" }, "peerDependencies": { "hono": "^4.11.5" } }, "sha512-RH275yhbKlON6N1KgJUCiLIixw0Bd77Dp/6IuYQ6UhIboyq6c4EuSegRLJrb3XpP57+MNKuetYvAljDp8alHpQ=="], + + "@scalar/types": ["@scalar/types@0.6.7", "", { "dependencies": { "@scalar/helpers": "0.2.16", "nanoid": "^5.1.6", "type-fest": "^5.3.1", "zod": "^4.3.5" } }, "sha512-ihHaoPF9qQR05pV3mfE7yBlHQdm5CoJVE0HiJFH6xSrzLfk2yJ6XdD3OzyRCqyxkZ38bj2RIZMS6LJsGy4p66g=="], "@se-oss/deasync": ["@se-oss/deasync@1.0.1", "", { "dependencies": { "type-fest": "^4.37.0" }, "optionalDependencies": { "@se-oss/deasync-darwin-arm64": "1.0.1", "@se-oss/deasync-darwin-x64": "1.0.1", "@se-oss/deasync-linux-arm64-gnu": "1.0.1", "@se-oss/deasync-linux-arm64-musl": "1.0.1", "@se-oss/deasync-linux-x64-gnu": "1.0.1", "@se-oss/deasync-linux-x64-musl": "1.0.1", "@se-oss/deasync-win32-arm64-msvc": "1.0.1", "@se-oss/deasync-win32-x64-msvc": "1.0.1" } }, "sha512-Ha7P/xCNxOuH72BNdLRWs4TT8rsMMrERnHtfKWBeTWu+UFW9OBTrRgfZJOlbAAQFR0l4Q30cpAn8CuR7PXWcPg=="], @@ -768,15 +775,15 @@ "@selderee/plugin-htmlparser2": ["@selderee/plugin-htmlparser2@0.11.0", "", { "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" } }, "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ=="], - "@sentry/bun": ["@sentry/bun@10.32.0", "", { "dependencies": { "@sentry/core": "10.32.0", "@sentry/node": "10.32.0" } }, "sha512-7llq1zSVE1J2MhntXlQ7I3i1a/TYsVdjUCQZkUad5AUXW+V/bg+HgdU+oDB57is3uA/yNmjcYRNKDgOeXQo8WA=="], + "@sentry/bun": ["@sentry/bun@10.32.1", "", { "dependencies": { "@sentry/core": "10.32.1", "@sentry/node": "10.32.1" } }, "sha512-Ksfl+HemrWkVShGX2UU7QUXMp3apgjNWR6NxDroHvdbEKfvdfEWJ+fcK/i/xtd4z5lfUt66C1OCJLivQf/gj4Q=="], - "@sentry/core": ["@sentry/core@10.32.0", "", {}, "sha512-E+ihb8+5PBfYMamnXHalgsmxkcG2YQqhRdgYf3yWJ5dJvi4njh1VWK3kNVj1GvsU6ktaielAx4Rg5dwEFMnbZg=="], + "@sentry/core": ["@sentry/core@10.32.1", "", {}, "sha512-PH2ldpSJlhqsMj2vCTyU0BI2Fx1oIDhm7Izo5xFALvjVCS0gmlqHt1udu6YlKn8BtpGH6bGzssvv5APrk+OdPQ=="], - "@sentry/node": ["@sentry/node@10.32.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^2.2.0", "@opentelemetry/core": "^2.2.0", "@opentelemetry/instrumentation": "^0.208.0", "@opentelemetry/instrumentation-amqplib": "0.55.0", "@opentelemetry/instrumentation-connect": "0.52.0", "@opentelemetry/instrumentation-dataloader": "0.26.0", "@opentelemetry/instrumentation-express": "0.57.0", "@opentelemetry/instrumentation-fs": "0.28.0", "@opentelemetry/instrumentation-generic-pool": "0.52.0", "@opentelemetry/instrumentation-graphql": "0.56.0", "@opentelemetry/instrumentation-hapi": "0.55.0", "@opentelemetry/instrumentation-http": "0.208.0", "@opentelemetry/instrumentation-ioredis": "0.56.0", "@opentelemetry/instrumentation-kafkajs": "0.18.0", "@opentelemetry/instrumentation-knex": "0.53.0", "@opentelemetry/instrumentation-koa": "0.57.0", "@opentelemetry/instrumentation-lru-memoizer": "0.53.0", "@opentelemetry/instrumentation-mongodb": "0.61.0", "@opentelemetry/instrumentation-mongoose": "0.55.0", "@opentelemetry/instrumentation-mysql": "0.54.0", "@opentelemetry/instrumentation-mysql2": "0.55.0", "@opentelemetry/instrumentation-pg": "0.61.0", "@opentelemetry/instrumentation-redis": "0.57.0", "@opentelemetry/instrumentation-tedious": "0.27.0", "@opentelemetry/instrumentation-undici": "0.19.0", "@opentelemetry/resources": "^2.2.0", "@opentelemetry/sdk-trace-base": "^2.2.0", "@opentelemetry/semantic-conventions": "^1.37.0", "@prisma/instrumentation": "6.19.0", "@sentry/core": "10.32.0", "@sentry/node-core": "10.32.0", "@sentry/opentelemetry": "10.32.0", "import-in-the-middle": "^2", "minimatch": "^9.0.0" } }, "sha512-KENGLH34gUlrNd9QVJFp37w64DZmorWarm67sFJ2J+VmBII0JMkbIJy1SdHyHxGtgitbokotMTjjf9isVnWwlw=="], + "@sentry/node": ["@sentry/node@10.32.1", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^2.2.0", "@opentelemetry/core": "^2.2.0", "@opentelemetry/instrumentation": "^0.208.0", "@opentelemetry/instrumentation-amqplib": "0.55.0", "@opentelemetry/instrumentation-connect": "0.52.0", "@opentelemetry/instrumentation-dataloader": "0.26.0", "@opentelemetry/instrumentation-express": "0.57.0", "@opentelemetry/instrumentation-fs": "0.28.0", "@opentelemetry/instrumentation-generic-pool": "0.52.0", "@opentelemetry/instrumentation-graphql": "0.56.0", "@opentelemetry/instrumentation-hapi": "0.55.0", "@opentelemetry/instrumentation-http": "0.208.0", "@opentelemetry/instrumentation-ioredis": "0.56.0", "@opentelemetry/instrumentation-kafkajs": "0.18.0", "@opentelemetry/instrumentation-knex": "0.53.0", "@opentelemetry/instrumentation-koa": "0.57.0", "@opentelemetry/instrumentation-lru-memoizer": "0.53.0", "@opentelemetry/instrumentation-mongodb": "0.61.0", "@opentelemetry/instrumentation-mongoose": "0.55.0", "@opentelemetry/instrumentation-mysql": "0.54.0", "@opentelemetry/instrumentation-mysql2": "0.55.0", "@opentelemetry/instrumentation-pg": "0.61.0", "@opentelemetry/instrumentation-redis": "0.57.0", "@opentelemetry/instrumentation-tedious": "0.27.0", "@opentelemetry/instrumentation-undici": "0.19.0", "@opentelemetry/resources": "^2.2.0", "@opentelemetry/sdk-trace-base": "^2.2.0", "@opentelemetry/semantic-conventions": "^1.37.0", "@prisma/instrumentation": "6.19.0", "@sentry/core": "10.32.1", "@sentry/node-core": "10.32.1", "@sentry/opentelemetry": "10.32.1", "import-in-the-middle": "^2", "minimatch": "^9.0.0" } }, "sha512-oxlybzt8QW0lx/QaEj1DcvZDRXkgouewFelu/10dyUwv5So3YvipfvWInda+yMLmn25OggbloDQ0gyScA2jU3g=="], - "@sentry/node-core": ["@sentry/node-core@10.32.0", "", { "dependencies": { "@apm-js-collab/tracing-hooks": "^0.3.1", "@sentry/core": "10.32.0", "@sentry/opentelemetry": "10.32.0", "import-in-the-middle": "^2" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/resources": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/semantic-conventions": "^1.37.0" } }, "sha512-O+TVuF1fO0j37W6IzdHCpTIr4uUkFzcSKgxNmH9ihYpRzkQgfLDZJWVxtov+H8/1pC5lkvl2VZhWmY+SWj2kHA=="], + "@sentry/node-core": ["@sentry/node-core@10.32.1", "", { "dependencies": { "@apm-js-collab/tracing-hooks": "^0.3.1", "@sentry/core": "10.32.1", "@sentry/opentelemetry": "10.32.1", "import-in-the-middle": "^2" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/resources": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/semantic-conventions": "^1.37.0" } }, "sha512-w56rxdBanBKc832zuwnE+zNzUQ19fPxfHEtOhK8JGPu3aSwQYcIxwz9z52lOx3HN7k/8Fj5694qlT3x/PokhRw=="], - "@sentry/opentelemetry": ["@sentry/opentelemetry@10.32.0", "", { "dependencies": { "@sentry/core": "10.32.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/semantic-conventions": "^1.37.0" } }, "sha512-owGL94JAgbwxgaeUNLktJWMShZPo04ZKTaQhhLz3YmVDJFj8VFOQXdWBMqv1Gv6T6/fCuTlwzJ3rvpSOImxXUQ=="], + "@sentry/opentelemetry": ["@sentry/opentelemetry@10.32.1", "", { "dependencies": { "@sentry/core": "10.32.1" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0 || ^2.2.0", "@opentelemetry/semantic-conventions": "^1.37.0" } }, "sha512-YLssSz5Y+qPvufrh2cDaTXDoXU8aceOhB+YTjT8/DLF6SOj7Tzen52aAcjNaifawaxEsLCC8O+B+A2iA+BllvA=="], "@shikijs/core": ["@shikijs/core@2.5.0", "", { "dependencies": { "@shikijs/engine-javascript": "2.5.0", "@shikijs/engine-oniguruma": "2.5.0", "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.4" } }, "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg=="], @@ -794,19 +801,19 @@ "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], - "@sindresorhus/is": ["@sindresorhus/is@7.1.1", "", {}, "sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ=="], + "@sindresorhus/is": ["@sindresorhus/is@7.2.0", "", {}, "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw=="], - "@speed-highlight/core": ["@speed-highlight/core@1.2.12", "", {}, "sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA=="], + "@speed-highlight/core": ["@speed-highlight/core@1.2.14", "", {}, "sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA=="], "@standard-community/standard-json": ["@standard-community/standard-json@0.3.5", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "@types/json-schema": "^7.0.15", "@valibot/to-json-schema": "^1.3.0", "arktype": "^2.1.20", "effect": "^3.16.8", "quansync": "^0.2.11", "sury": "^10.0.0", "typebox": "^1.0.17", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.5" }, "optionalPeers": ["@valibot/to-json-schema", "arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-to-json-schema"] }, "sha512-4+ZPorwDRt47i+O7RjyuaxHRK/37QY/LmgxlGrRrSTLYoFatEOzvqIc85GTlM18SFZ5E91C+v0o/M37wZPpUHA=="], - "@standard-community/standard-openapi": ["@standard-community/standard-openapi@0.2.8", "", { "peerDependencies": { "@standard-community/standard-json": "^0.3.5", "@standard-schema/spec": "^1.0.0", "arktype": "^2.1.20", "effect": "^3.17.14", "openapi-types": "^12.1.3", "sury": "^10.0.0", "typebox": "^1.0.0", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-openapi": "^4" }, "optionalPeers": ["arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-openapi"] }, "sha512-80ap74p5oy/SU4al5HkPwO5+NbN2wH/FBr6kwaE5ROq7AvcDFaxzUfTazewroNaCotbvdGcvzXb9oEoOIyfC/Q=="], + "@standard-community/standard-openapi": ["@standard-community/standard-openapi@0.2.9", "", { "peerDependencies": { "@standard-community/standard-json": "^0.3.5", "@standard-schema/spec": "^1.0.0", "arktype": "^2.1.20", "effect": "^3.17.14", "openapi-types": "^12.1.3", "sury": "^10.0.0", "typebox": "^1.0.0", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-openapi": "^4" }, "optionalPeers": ["arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-openapi"] }, "sha512-htj+yldvN1XncyZi4rehbf9kLbu8os2Ke/rfqoZHCMHuw34kiF3LP/yQPdA0tQ940y8nDq3Iou8R3wG+AGGyvg=="], - "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], "@ts-morph/common": ["@ts-morph/common@0.12.3", "", { "dependencies": { "fast-glob": "^3.2.7", "minimatch": "^3.0.4", "mkdirp": "^1.0.4", "path-browserify": "^1.0.1" } }, "sha512-4tUmeLyXJnJWvTFOKtcNJ1yh0a3SsTLi2MUoyj8iUNznFRN1ZquaNe7Oukqrnki2FzZkm0J9adCNLDZxUzvj+w=="], - "@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="], + "@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="], "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], @@ -832,7 +839,7 @@ "@types/mysql": ["@types/mysql@2.15.27", "", { "dependencies": { "@types/node": "*" } }, "sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA=="], - "@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="], + "@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="], "@types/parse-json": ["@types/parse-json@4.0.2", "", {}, "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="], @@ -842,12 +849,8 @@ "@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="], - "@types/react": ["@types/react@19.2.6", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w=="], - "@types/tedious": ["@types/tedious@4.0.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw=="], - "@types/text-table": ["@types/text-table@0.2.5", "", {}, "sha512-hcZhlNvMkQG/k1vcZ6yHOl6WAYftQ2MLfTHcYRZ2xYZFD8tGVnE3qFV0lj1smQeDSR7/yY0PyuUalauf33bJeA=="], - "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], "@types/web-bluetooth": ["@types/web-bluetooth@0.0.21", "", {}, "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA=="], @@ -856,6 +859,8 @@ "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + "@uttr/tint": ["@uttr/tint@0.1.3", "", {}, "sha512-nQlAxBriuQ7NPxvMlxCXdw0n4alhEAIzsjFNNyU4CR7AitUwMFp1A5e/47JYQ7NMcooaI06OEQKylYhNhbpuIA=="], + "@versia-server/api": ["@versia-server/api@workspace:packages/api"], "@versia-server/config": ["@versia-server/config@workspace:packages/config"], @@ -874,13 +879,13 @@ "@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.4", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA=="], - "@vue/compiler-core": ["@vue/compiler-core@3.5.26", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.26", "entities": "^7.0.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w=="], + "@vue/compiler-core": ["@vue/compiler-core@3.5.29", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/shared": "3.5.29", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-cuzPhD8fwRHk8IGfmYaR4eEe4cAyJEL66Ove/WZL7yWNL134nqLddSLwNRIsFlnnW1kK+p8Ck3viFnC0chXCXw=="], - "@vue/compiler-dom": ["@vue/compiler-dom@3.5.26", "", { "dependencies": { "@vue/compiler-core": "3.5.26", "@vue/shared": "3.5.26" } }, "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A=="], + "@vue/compiler-dom": ["@vue/compiler-dom@3.5.29", "", { "dependencies": { "@vue/compiler-core": "3.5.29", "@vue/shared": "3.5.29" } }, "sha512-n0G5o7R3uBVmVxjTIYcz7ovr8sy7QObFG8OQJ3xGCDNhbG60biP/P5KnyY8NLd81OuT1WJflG7N4KWYHaeeaIg=="], - "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.26", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/compiler-core": "3.5.26", "@vue/compiler-dom": "3.5.26", "@vue/compiler-ssr": "3.5.26", "@vue/shared": "3.5.26", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA=="], + "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.29", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/compiler-core": "3.5.29", "@vue/compiler-dom": "3.5.29", "@vue/compiler-ssr": "3.5.29", "@vue/shared": "3.5.29", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-oJZhN5XJs35Gzr50E82jg2cYdZQ78wEwvRO6Y63TvLVTc+6xICzJHP1UIecdSPPYIbkautNBanDiWYa64QSFIA=="], - "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.26", "", { "dependencies": { "@vue/compiler-dom": "3.5.26", "@vue/shared": "3.5.26" } }, "sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw=="], + "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.29", "", { "dependencies": { "@vue/compiler-dom": "3.5.29", "@vue/shared": "3.5.29" } }, "sha512-Y/ARJZE6fpjzL5GH/phJmsFwx3g6t2KmHKHx5q+MLl2kencADKIrhH5MLF6HHpRMmlRAYBRSvv347Mepf1zVNw=="], "@vue/devtools-api": ["@vue/devtools-api@7.7.9", "", { "dependencies": { "@vue/devtools-kit": "^7.7.9" } }, "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g=="], @@ -888,15 +893,15 @@ "@vue/devtools-shared": ["@vue/devtools-shared@7.7.9", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA=="], - "@vue/reactivity": ["@vue/reactivity@3.5.26", "", { "dependencies": { "@vue/shared": "3.5.26" } }, "sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ=="], + "@vue/reactivity": ["@vue/reactivity@3.5.29", "", { "dependencies": { "@vue/shared": "3.5.29" } }, "sha512-zcrANcrRdcLtmGZETBxWqIkoQei8HaFpZWx/GHKxx79JZsiZ8j1du0VUJtu4eJjgFvU/iKL5lRXFXksVmI+5DA=="], - "@vue/runtime-core": ["@vue/runtime-core@3.5.26", "", { "dependencies": { "@vue/reactivity": "3.5.26", "@vue/shared": "3.5.26" } }, "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q=="], + "@vue/runtime-core": ["@vue/runtime-core@3.5.29", "", { "dependencies": { "@vue/reactivity": "3.5.29", "@vue/shared": "3.5.29" } }, "sha512-8DpW2QfdwIWOLqtsNcds4s+QgwSaHSJY/SUe04LptianUQ/0xi6KVsu/pYVh+HO3NTVvVJjIPL2t6GdeKbS4Lg=="], - "@vue/runtime-dom": ["@vue/runtime-dom@3.5.26", "", { "dependencies": { "@vue/reactivity": "3.5.26", "@vue/runtime-core": "3.5.26", "@vue/shared": "3.5.26", "csstype": "^3.2.3" } }, "sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ=="], + "@vue/runtime-dom": ["@vue/runtime-dom@3.5.29", "", { "dependencies": { "@vue/reactivity": "3.5.29", "@vue/runtime-core": "3.5.29", "@vue/shared": "3.5.29", "csstype": "^3.2.3" } }, "sha512-AHvvJEtcY9tw/uk+s/YRLSlxxQnqnAkjqvK25ZiM4CllCZWzElRAoQnCM42m9AHRLNJ6oe2kC5DCgD4AUdlvXg=="], - "@vue/server-renderer": ["@vue/server-renderer@3.5.26", "", { "dependencies": { "@vue/compiler-ssr": "3.5.26", "@vue/shared": "3.5.26" }, "peerDependencies": { "vue": "3.5.26" } }, "sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA=="], + "@vue/server-renderer": ["@vue/server-renderer@3.5.29", "", { "dependencies": { "@vue/compiler-ssr": "3.5.29", "@vue/shared": "3.5.29" }, "peerDependencies": { "vue": "3.5.29" } }, "sha512-G/1k6WK5MusLlbxSE2YTcqAAezS+VuwHhOvLx2KnQU7G2zCH6KIb+5Wyt6UjMq7a3qPzNEjJXs1hvAxDclQH+g=="], - "@vue/shared": ["@vue/shared@3.5.24", "", {}, "sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A=="], + "@vue/shared": ["@vue/shared@3.5.29", "", {}, "sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg=="], "@vueuse/core": ["@vueuse/core@12.8.2", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "12.8.2", "@vueuse/shared": "12.8.2", "vue": "^3.5.13" } }, "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ=="], @@ -906,21 +911,19 @@ "@vueuse/shared": ["@vueuse/shared@12.8.2", "", { "dependencies": { "vue": "^3.5.13" } }, "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w=="], - "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], "acorn-import-attributes": ["acorn-import-attributes@1.9.5", "", { "peerDependencies": { "acorn": "^8" } }, "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ=="], "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], - "algoliasearch": ["algoliasearch@5.44.0", "", { "dependencies": { "@algolia/abtesting": "1.10.0", "@algolia/client-abtesting": "5.44.0", "@algolia/client-analytics": "5.44.0", "@algolia/client-common": "5.44.0", "@algolia/client-insights": "5.44.0", "@algolia/client-personalization": "5.44.0", "@algolia/client-query-suggestions": "5.44.0", "@algolia/client-search": "5.44.0", "@algolia/ingestion": "1.44.0", "@algolia/monitoring": "1.44.0", "@algolia/recommend": "5.44.0", "@algolia/requester-browser-xhr": "5.44.0", "@algolia/requester-fetch": "5.44.0", "@algolia/requester-node-http": "5.44.0" } }, "sha512-f8IpsbdQjzTjr/4mJ/jv5UplrtyMnnciGax6/B0OnLCs2/GJTK13O4Y7Ff1AvJVAaztanH+m5nzPoUq6EAy+aA=="], + "algoliasearch": ["algoliasearch@5.49.1", "", { "dependencies": { "@algolia/abtesting": "1.15.1", "@algolia/client-abtesting": "5.49.1", "@algolia/client-analytics": "5.49.1", "@algolia/client-common": "5.49.1", "@algolia/client-insights": "5.49.1", "@algolia/client-personalization": "5.49.1", "@algolia/client-query-suggestions": "5.49.1", "@algolia/client-search": "5.49.1", "@algolia/ingestion": "1.49.1", "@algolia/monitoring": "1.49.1", "@algolia/recommend": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-X3Pp2aRQhg4xUC6PQtkubn5NpRKuUPQ9FPDQlx36SmpFwwH2N0/tw4c+NXV3nw3PsgeUs+BuWGP0gjz3TvENLQ=="], "altcha-lib": ["altcha-lib@1.4.1", "", {}, "sha512-MAXP9tkQOA2SE9Gwoe3LAcZbcDpp3XzYc5GDVej/y3eMNaFG/eVnRY1/7SGFW0RPsViEjPf+hi5eANjuZrH1xA=="], "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - - "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], @@ -928,15 +931,15 @@ "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], - "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - "birpc": ["birpc@2.8.0", "", {}, "sha512-Bz2a4qD/5GRhiHSwj30c/8kC8QGj12nNDwz3D4ErQ4Xhy35dsSDvF+RA/tWpjyU0pdGtSDiEk6B5fBGE1qNVhw=="], + "birpc": ["birpc@2.9.0", "", {}, "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw=="], "blurhash": ["blurhash@2.0.5", "", {}, "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w=="], - "bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="], + "bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], - "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], @@ -944,11 +947,11 @@ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "bullmq": ["bullmq@5.66.1", "", { "dependencies": { "cron-parser": "4.9.0", "ioredis": "5.8.2", "msgpackr": "1.11.5", "node-abort-controller": "3.1.1", "semver": "7.7.3", "tslib": "2.8.1", "uuid": "11.1.0" } }, "sha512-bsznO3V4zRSdoZ8dN2qc172AavKHuCdvPdV8zBmiikVZnlZ/XbPiu504d6yK8AOJpyPzTJEaKGKiMClM/7iWXg=="], + "bullmq": ["bullmq@5.66.7", "", { "dependencies": { "cron-parser": "4.9.0", "ioredis": "5.9.2", "msgpackr": "1.11.5", "node-abort-controller": "3.1.1", "semver": "7.7.3", "tslib": "2.8.1", "uuid": "11.1.0" } }, "sha512-X6YIjTXVN9fFjrMCKBppu74XZBnfWf0OgvwSVcpJE99irlszpGMKyyBcAOzd3126Lh9PwKygSfmHL4UfYrrIUQ=="], "bun-bagel": ["bun-bagel@1.2.0", "", { "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-c4S68dNddpnog9nxXp9PAhcep0alOy49jpRlC1yACoxplUvgX22NZxeQUIIov5TCJJDH/snT5R9bMyix7AG0KQ=="], - "bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="], + "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], @@ -964,13 +967,11 @@ "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], - "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - - "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="], + "cjs-module-lexer": ["cjs-module-lexer@2.2.0", "", {}, "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ=="], "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], - "cli-spinners": ["cli-spinners@3.3.0", "", {}, "sha512-/+40ljC3ONVnYIttjMWrlL51nItDAbBrq2upN8BPyvGU/2n5Oxw3tbNwORCaNuNqLJnxGqOfjUuhsv7l5Q4IsQ=="], + "cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="], "cli-width": ["cli-width@4.1.0", "", {}, "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ=="], @@ -990,7 +991,7 @@ "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + "confbox": ["confbox@0.2.4", "", {}, "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="], "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="], @@ -1002,8 +1003,6 @@ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - "crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="], - "cssfilter": ["cssfilter@0.0.10", "", {}, "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], @@ -1012,14 +1011,10 @@ "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], - "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], - "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], - "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], - "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], @@ -1034,19 +1029,17 @@ "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], - "drizzle-kit": ["drizzle-kit@0.31.8", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-O9EC/miwdnRDY10qRxM8P3Pg8hXe3LyU4ZipReKOgTwn4OqANmftj8XJz1UPUAS6NMHf0E2htjsbQujUTkncCg=="], + "drizzle-kit": ["drizzle-kit@0.31.9", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-GViD3IgsXn7trFyBUUHyTFBpH/FsHTxYJ66qdbVggxef4UBPHRYxQaRzYLTuekYnk9i5FIEL9pbBIwMqX/Uwrg=="], "drizzle-orm": ["drizzle-orm@0.45.1", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-Te0FOdKIistGNPMq2jscdqngBRfBpC8uMFVwqjf6gtTVJHIQ/dosgV/CLBU2N4ZJBsXL5savCba9b0YJskKdcA=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], - "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], - "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "emoji-regex-xs": ["emoji-regex-xs@1.0.0", "", {}, "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg=="], @@ -1078,19 +1071,25 @@ "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + "fast-string-truncated-width": ["fast-string-truncated-width@3.0.3", "", {}, "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g=="], + + "fast-string-width": ["fast-string-width@3.0.2", "", { "dependencies": { "fast-string-truncated-width": "^3.0.2" } }, "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg=="], + + "fast-wrap-ansi": ["fast-wrap-ansi@0.2.0", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w=="], + "fastest-levenshtein": ["fastest-levenshtein@1.0.16", "", {}, "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg=="], - "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], "feed": ["feed@5.1.0", "", { "dependencies": { "xml-js": "^1.6.11" } }, "sha512-qGNhgYygnefSkAHHrNHqC7p3R8J0/xQDS/cYUud8er/qD9EFGWyCdUDfULHTJQN1d3H3WprzVwMc9MfB4J50Wg=="], "figures": ["figures@5.0.0", "", { "dependencies": { "escape-string-regexp": "^5.0.0", "is-unicode-supported": "^1.2.0" } }, "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg=="], - "filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="], + "filelist": ["filelist@1.0.5", "", { "dependencies": { "minimatch": "^10.2.1" } }, "sha512-ct/ckWBV/9Dg3MlvCXsLcSUyoWwv9mCKqlhLNB2DAuXR/NZolSXlQqP5dyy6guWlPXBhodZyZ5lGPQcbQDxrEQ=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - "focus-trap": ["focus-trap@7.6.6", "", { "dependencies": { "tabbable": "^6.3.0" } }, "sha512-v/Z8bvMCajtx4mEXmOo7QEsIzlIOqRXTIwgUfsFOF9gEsespdbD0AkPIka1bSXZ8Y8oZ+2IVDQZePkTfEHZl7Q=="], + "focus-trap": ["focus-trap@7.8.0", "", { "dependencies": { "tabbable": "^6.4.0" } }, "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA=="], "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], @@ -1102,13 +1101,13 @@ "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + "get-east-asian-width": ["get-east-asian-width@1.5.0", "", {}, "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA=="], "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], + "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="], "glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="], @@ -1118,8 +1117,6 @@ "gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="], - "h3": ["h3@1.15.4", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.2", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ=="], - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], @@ -1128,11 +1125,11 @@ "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], - "hono": ["hono@4.11.1", "", {}, "sha512-KsFcH0xxHes0J4zaQgWbYwmz3UPOOskdqZmItstUG93+Wk1ePBLkLGwbP9zlmh1BFUiL8Qp+Xfu9P7feJWpGNg=="], + "hono": ["hono@4.11.10", "", {}, "sha512-kyWP5PAiMooEvGrA9jcD3IXF7ATu8+o7B3KCbPXid5se52NPqnOpM/r9qeW2heMnOekF4kqR1fXJqCYeCLKrZg=="], "hono-openapi": ["hono-openapi@1.1.2", "", { "peerDependencies": { "@hono/standard-validator": "^0.2.0", "@standard-community/standard-json": "^0.3.5", "@standard-community/standard-openapi": "^0.2.9", "@types/json-schema": "^7.0.15", "hono": "^4.8.3", "openapi-types": "^12.1.3" }, "optionalPeers": ["@hono/standard-validator", "hono"] }, "sha512-toUcO60MftRBxqcVyxsHNYs2m4vf4xkQaiARAucQx3TiBPDtMNNkoh+C4I1vAretQZiGyaLOZNWn1YxfSyUA5g=="], - "hono-rate-limiter": ["hono-rate-limiter@0.5.1", "", { "peerDependencies": { "hono": "^4.10.8", "unstorage": "^1.17.3" } }, "sha512-c3bUn6IRgFKjlouvRNBy+ZIPZ2CTyTt3fc0uat2bv3GiHmLM4jI0QJ6fHd3Tf4R6dO2sX2Uvl9Gtp+kny4KdXg=="], + "hono-rate-limiter": ["hono-rate-limiter@0.5.3", "", { "peerDependencies": { "hono": "^4.10.8", "unstorage": "^1.17.3" }, "optionalPeers": ["unstorage"] }, "sha512-M0DxbVMpPELEzLi0AJg1XyBHLGJXz7GySjsPoK+gc5YeeBsdGDGe+2RvVuCAv8ydINiwlbxqYMNxUEyYfRji/A=="], "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], @@ -1148,16 +1145,14 @@ "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], - "import-in-the-middle": ["import-in-the-middle@2.0.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^1.2.2", "module-details-from-path": "^1.0.3" } }, "sha512-yNZhyQYqXpkT0AKq3F3KLasUSK4fHvebNH5hOsKQw2dhGSALvQ4U0BqUc5suziKvydO5u5hgN2hy1RJaho8U5A=="], + "import-in-the-middle": ["import-in-the-middle@2.0.6", "", { "dependencies": { "acorn": "^8.15.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^2.2.0", "module-details-from-path": "^1.0.4" } }, "sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw=="], "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - "ioredis": ["ioredis@5.8.2", "", { "dependencies": { "@ioredis/commands": "1.4.0", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q=="], + "ioredis": ["ioredis@5.9.2", "", { "dependencies": { "@ioredis/commands": "1.5.0", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ=="], "ip-matching": ["ip-matching@2.1.2", "", {}, "sha512-/ok+VhKMasgR5gvTRViwRFQfc0qYt9Vdowg6TO4/pFlDCob5ZjGPkwuOoQVCd5OrMm20zqh+1vA8KLJZTeWudg=="], - "iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="], - "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], "is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], @@ -1180,11 +1175,11 @@ "iso-639-1": ["iso-639-1@3.1.5", "", {}, "sha512-gXkz5+KN7HrG0Q5UGqSMO2qB9AsbEeyLP54kF1YrMsIxmu+g4BdB7rflReZTSTZGpfj8wywu6pfPBCylPIzGQA=="], - "jackspeak": ["jackspeak@4.1.1", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ=="], + "jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="], "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], - "jose": ["jose@6.1.2", "", {}, "sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ=="], + "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], @@ -1196,7 +1191,7 @@ "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="], - "jws": ["jws@4.0.0", "", { "dependencies": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg=="], + "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="], "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], @@ -1218,7 +1213,7 @@ "lite-emit": ["lite-emit@4.0.0", "", {}, "sha512-8krVeIZLS7JbkXz4R9xYziqHcxga6UgmomVWb45g21aB4M8qzDwr7FTEW3PJa80PTUASXeqbfipveKCB5YZdug=="], - "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], @@ -1232,7 +1227,7 @@ "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], - "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="], "luxon": ["luxon@3.7.2", "", {}, "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew=="], @@ -1242,7 +1237,7 @@ "mark.js": ["mark.js@8.11.1", "", {}, "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ=="], - "markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="], + "markdown-it": ["markdown-it@14.1.1", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA=="], "markdown-it-anchor": ["markdown-it-anchor@9.2.0", "", { "peerDependencies": { "@types/markdown-it": "*", "markdown-it": "*" } }, "sha512-sa2ErMQ6kKOA4l31gLGYliFQrMKkqSO0ZJgGhDHKijPf0pNFM9vghjAh3gn26pS4JDRs7Iwa9S36gxm3vgZTzg=="], @@ -1258,7 +1253,7 @@ "mathxyjax3": ["mathxyjax3@0.8.3", "", {}, "sha512-eXjFaiyQsTdVOeTFoFaFJ/r1FITpB1f9c5MW4FETfcoVV/+xa5SD9pS05AwugzL/gNuDtWXrTOSmoD2e0Du+UA=="], - "mdast-util-to-hast": ["mdast-util-to-hast@13.2.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA=="], + "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="], "mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], @@ -1284,11 +1279,11 @@ "minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="], - "minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + "minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], "minisearch": ["minisearch@7.2.0", "", {}, "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg=="], @@ -1314,27 +1309,19 @@ "node-abort-controller": ["node-abort-controller@3.1.1", "", {}, "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ=="], - "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], - "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], - "node-mock-http": ["node-mock-http@1.0.4", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="], - - "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], - - "oauth4webapi": ["oauth4webapi@3.8.3", "", {}, "sha512-pQ5BsX3QRTgnt5HxgHwgunIRaDXBdkT23tf8dfzmtTIL2LTpdmxgbpbBm0VgFWAIDlezQvQCTgnVIUmHupXHxw=="], + "oauth4webapi": ["oauth4webapi@3.8.5", "", {}, "sha512-A8jmyUckVhRJj5lspguklcl90Ydqk61H3dcU0oLhH3Yv13KpAliKTt5hknpGGPZSSfOwGyraNEFmofDYH+1kSg=="], "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - "ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], - "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], "oniguruma-to-es": ["oniguruma-to-es@3.1.1", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ=="], "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], - "openid-client": ["openid-client@6.8.1", "", { "dependencies": { "jose": "^6.1.0", "oauth4webapi": "^3.8.2" } }, "sha512-VoYT6enBo6Vj2j3Q5Ec0AezS+9YGzQo1f5Xc42lreMGlfP4ljiXPKVDvCADh+XHCV/bqPu/wWSiCVXbJKvrODw=="], + "openid-client": ["openid-client@6.8.2", "", { "dependencies": { "jose": "^6.1.3", "oauth4webapi": "^3.8.4" } }, "sha512-uOvTCndr4udZsKihJ68H9bUICrriHdUVJ6Az+4Ns6cW55rwM5h0bjVIzDz2SxgOI84LKjFyjOFvERLzdTUROGA=="], "ora": ["ora@9.0.0", "", { "dependencies": { "chalk": "^5.6.2", "cli-cursor": "^5.0.0", "cli-spinners": "^3.2.0", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", "stdin-discarder": "^0.2.2", "string-width": "^8.1.0", "strip-ansi": "^7.1.2" } }, "sha512-m0pg2zscbYgWbqRR6ABga5c3sZdEon7bSgjnlXC64kxtxLOyjRcbbUkLj7HFyy/FTD+P2xdBWu8snGhYI0jc4A=="], @@ -1350,7 +1337,7 @@ "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - "path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="], + "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], @@ -1362,7 +1349,7 @@ "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], - "pg-protocol": ["pg-protocol@1.10.3", "", {}, "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ=="], + "pg-protocol": ["pg-protocol@1.11.0", "", {}, "sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g=="], "pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], @@ -1376,13 +1363,13 @@ "postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="], - "postgres-bytea": ["postgres-bytea@1.0.0", "", {}, "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w=="], + "postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="], "postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="], "postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], - "preact": ["preact@10.27.2", "", {}, "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg=="], + "preact": ["preact@10.28.4", "", {}, "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ=="], "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], @@ -1390,25 +1377,21 @@ "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], - "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], + "qs": ["qs@6.14.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q=="], - "qsu": ["qsu@1.10.4", "", {}, "sha512-v5RhwvHMkDdbXEaAxQh5re8q7DiG6EE70+CNwYVA6wZsa4gUrpur+D8lIO3PrzeCj3azc/S79X5v3BH8ILfr9A=="], + "qsu": ["qsu@1.11.1", "", {}, "sha512-96jlgUn3x/esZe9GUeEJlvP/ggoEkQ+aiijmJY3es6AbOa5tGwrmUrG4yKSz+eTX5MSLXceUtg9VeDT7kLLHJg=="], "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], - - "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - "redis-errors": ["redis-errors@1.2.0", "", {}, "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w=="], "redis-info": ["redis-info@3.1.0", "", { "dependencies": { "lodash": "^4.17.11" } }, "sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg=="], "redis-parser": ["redis-parser@3.0.0", "", { "dependencies": { "redis-errors": "^1.0.0" } }, "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A=="], - "regex": ["regex@6.0.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA=="], + "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], "regex-recursion": ["regex-recursion@6.0.2", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg=="], @@ -1430,7 +1413,7 @@ "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], - "rollup": ["rollup@4.53.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.53.3", "@rollup/rollup-android-arm64": "4.53.3", "@rollup/rollup-darwin-arm64": "4.53.3", "@rollup/rollup-darwin-x64": "4.53.3", "@rollup/rollup-freebsd-arm64": "4.53.3", "@rollup/rollup-freebsd-x64": "4.53.3", "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", "@rollup/rollup-linux-arm-musleabihf": "4.53.3", "@rollup/rollup-linux-arm64-gnu": "4.53.3", "@rollup/rollup-linux-arm64-musl": "4.53.3", "@rollup/rollup-linux-loong64-gnu": "4.53.3", "@rollup/rollup-linux-ppc64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-musl": "4.53.3", "@rollup/rollup-linux-s390x-gnu": "4.53.3", "@rollup/rollup-linux-x64-gnu": "4.53.3", "@rollup/rollup-linux-x64-musl": "4.53.3", "@rollup/rollup-openharmony-arm64": "4.53.3", "@rollup/rollup-win32-arm64-msvc": "4.53.3", "@rollup/rollup-win32-ia32-msvc": "4.53.3", "@rollup/rollup-win32-x64-gnu": "4.53.3", "@rollup/rollup-win32-x64-msvc": "4.53.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA=="], + "rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], @@ -1438,7 +1421,7 @@ "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - "sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], + "sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], "search-insights": ["search-insights@2.17.3", "", {}, "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ=="], @@ -1486,23 +1469,19 @@ "string-comparison": ["string-comparison@1.3.0", "", {}, "sha512-46aD+slEwybxAMPRII83ATbgMgTiz5P8mVd7Z6VJsCzSHFjdt1hkAVLeFxPIyEb11tc6ihpJTlIqoO0MCF6NPw=="], - "string-width": ["string-width@8.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg=="], - - "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "string-width": ["string-width@8.2.0", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw=="], "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], - "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "strip-bom-string": ["strip-bom-string@1.0.0", "", {}, "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="], - "superjson": ["superjson@2.2.5", "", { "dependencies": { "copy-anything": "^4" } }, "sha512-zWPTX96LVsA/eVYnqOM2+ofcdPqdS1dAF1LN4TS2/MWuUpfitd9ctTa87wt4xrYnZnkLtS69xpBdSxVBP5Rm6w=="], + "superjson": ["superjson@2.2.6", "", { "dependencies": { "copy-anything": "^4" } }, "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA=="], "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], - "tabbable": ["tabbable@6.3.0", "", {}, "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ=="], + "tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="], "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], @@ -1528,11 +1507,9 @@ "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], - "ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="], + "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], - "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="], - - "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], "unicode-emoji-json": ["unicode-emoji-json@0.8.0", "", {}, "sha512-3wDXXvp6YGoKGhS2O2H7+V+bYduOBydN1lnI0uVfr1cIdY02uFFiEH1i3kE5CCE4l6UqbLKVmEFW9USxTAMD1g=="], @@ -1542,13 +1519,11 @@ "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], - "unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="], + "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="], "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], - "unplugin": ["unplugin@2.3.10", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw=="], - - "unstorage": ["unstorage@1.17.3", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q=="], + "unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="], "uqr": ["uqr@0.1.2", "", {}, "sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA=="], @@ -1566,7 +1541,7 @@ "vitepress-sidebar": ["vitepress-sidebar@1.33.1", "", { "dependencies": { "glob": "11.1.0", "gray-matter": "4.0.3", "qsu": "^1.10.4" } }, "sha512-wPUbXezGakVldawixeRW5tKQTLKoMj2t4nWoThKfCltBM/9a38IE+wCXmmRNW22ZKC32SD/X/sG6NyCTK8QBRg=="], - "vue": ["vue@3.5.26", "", { "dependencies": { "@vue/compiler-dom": "3.5.26", "@vue/compiler-sfc": "3.5.26", "@vue/runtime-dom": "3.5.26", "@vue/server-renderer": "3.5.26", "@vue/shared": "3.5.26" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA=="], + "vue": ["vue@3.5.29", "", { "dependencies": { "@vue/compiler-dom": "3.5.29", "@vue/compiler-sfc": "3.5.29", "@vue/runtime-dom": "3.5.29", "@vue/server-renderer": "3.5.29", "@vue/shared": "3.5.29" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-BZqN4Ze6mDQVNAni0IHeMJ5mwr8VAJ3MQC9FmprRhcBYENw+wOAAjRj8jfmN6FLl0j96OXbR+CjWhmAmM+QGnA=="], "web-push": ["web-push@3.6.7", "", { "dependencies": { "asn1.js": "^5.3.0", "http_ece": "1.2.0", "https-proxy-agent": "^7.0.0", "jws": "^4.0.0", "minimist": "^1.2.5" }, "bin": { "web-push": "src/cli.js" } }, "sha512-OpiIUe8cuGjrj3mMBFWY+e4MMIkW3SVT+7vEIjvD9kejGUypv8GPDf84JdPWskK8zMRIJ6xYGm+Kxr8YkPyA0A=="], @@ -1574,9 +1549,7 @@ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], - - "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "xml-js": ["xml-js@1.6.11", "", { "dependencies": { "sax": "^1.2.4" }, "bin": { "xml-js": "./bin/cli.js" } }, "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g=="], @@ -1594,13 +1567,13 @@ "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], - "youch": ["youch@4.1.0-beta.13", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.5", "@speed-highlight/core": "^1.2.9", "cookie-es": "^2.0.0", "youch-core": "^0.3.3" } }, "sha512-3+AG1Xvt+R7M7PSDudhbfbwiyveW6B8PLBIwTyEC598biEYIjHhC89i6DBEvR0EZUjGY3uGSnC429HpIa2Z09g=="], + "youch": ["youch@4.1.0", "", { "dependencies": { "@poppinss/colors": "^4.1.6", "@poppinss/dumper": "^0.7.0", "@speed-highlight/core": "^1.2.14", "cookie-es": "^2.0.0", "youch-core": "^0.3.3" } }, "sha512-cYekNh2tUoU+voS11X0D0UQntVCSO6LQ1h10VriQGmfbpf0mnGTruwZICts23UUNiZCXm8H8hQBtRrdsbhuNNg=="], "youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="], "zod": ["zod@4.2.1", "", {}, "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw=="], - "zod-openapi": ["zod-openapi@5.4.5", "", { "peerDependencies": { "zod": "^3.25.74 || ^4.0.0" } }, "sha512-DVLBNsnggh8k/Yq7qp+NeQCH6JuLIyGzUQWA1wN5+7DpQJSwC7WYR/2lE6uQDmGcS/X6l4tUyYFpeG4nk3nOpA=="], + "zod-openapi": ["zod-openapi@5.4.6", "", { "peerDependencies": { "zod": "^3.25.74 || ^4.0.0" } }, "sha512-P2jsOOBAq/6hCwUsMCjUATZ8szkMsV5VAwZENfyxp2Hc/XPJQpVwAgevWZc65xZauCwWB9LAn7zYeiCJFAEL+A=="], "zod-validation-error": ["zod-validation-error@5.0.0", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-hmk+pkyKq7Q71PiWVSDUc3VfpzpvcRHZ3QPw9yEMVvmtCekaMeOHnbr3WbxfrgEnQTv6haGP4cmv0Ojmihzsxw=="], @@ -1608,91 +1581,71 @@ "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], - "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], - "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + "@opentelemetry/exporter-logs-otlp-http/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], - "@scalar/types/nanoid": ["nanoid@5.1.5", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="], + "@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], - "@scalar/types/type-fest": ["type-fest@5.0.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-GeJop7+u7BYlQ6yQCAY1nBQiRSHR+6OdCEtd8Bwp9a3NK3+fWAVjOaPKJDteB9f6cIJ0wt4IfnScjLG450EpXA=="], + "@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/resources": ["@opentelemetry/resources@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A=="], - "@sentry/node/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw=="], - "@ts-morph/common/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "@opentelemetry/instrumentation-http/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], - "@types/pg-pool/@types/pg": ["@types/pg@8.15.5", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ=="], + "@opentelemetry/otlp-exporter-base/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], - "@vue/compiler-core/@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="], + "@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], - "@vue/compiler-core/entities": ["entities@7.0.0", "", {}, "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ=="], + "@opentelemetry/otlp-transformer/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], + + "@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A=="], + + "@opentelemetry/otlp-transformer/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw=="], + + "@opentelemetry/sdk-logs/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], + + "@opentelemetry/sdk-logs/@opentelemetry/resources": ["@opentelemetry/resources@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A=="], + + "@opentelemetry/sdk-metrics/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], + + "@opentelemetry/sdk-metrics/@opentelemetry/resources": ["@opentelemetry/resources@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A=="], + + "@scalar/types/nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="], + + "@scalar/types/type-fest": ["type-fest@5.4.4", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw=="], + + "@scalar/types/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + + "@sentry/node/minimatch": ["minimatch@9.0.7", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-MOwgjc8tfrpn5QQEvjijjmDVtMw2oL88ugTevzxQnzRLm6l3fVEF2gzU0kYeYYKD8C66+IdGX6peJ4MyUlUnPg=="], + + "@ts-morph/common/minimatch": ["minimatch@3.1.4", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-twmL+S8+7yIsE9wsqgzU3E8/LumN3M3QELrBZ20OdmQ9jB2JvW5oZtBEmft84k/Gs5CG9mqtWc6Y9vW+JEzGxw=="], + + "@vue/compiler-core/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], "@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - "@vue/compiler-dom/@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="], - - "@vue/compiler-sfc/@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="], - "@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - "@vue/compiler-ssr/@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="], - - "@vue/reactivity/@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="], - - "@vue/runtime-core/@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="], - - "@vue/runtime-dom/@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="], - - "@vue/server-renderer/@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="], - - "@vueuse/core/vue": ["vue@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/compiler-sfc": "3.5.24", "@vue/runtime-dom": "3.5.24", "@vue/server-renderer": "3.5.24", "@vue/shared": "3.5.24" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg=="], - - "@vueuse/integrations/vue": ["vue@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/compiler-sfc": "3.5.24", "@vue/runtime-dom": "3.5.24", "@vue/server-renderer": "3.5.24", "@vue/shared": "3.5.24" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg=="], - - "@vueuse/shared/vue": ["vue@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/compiler-sfc": "3.5.24", "@vue/runtime-dom": "3.5.24", "@vue/server-renderer": "3.5.24", "@vue/shared": "3.5.24" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg=="], - - "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - "figures/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="], - "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], - - "h3/cookie-es": ["cookie-es@1.2.2", "", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="], - "js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "path-scurry/lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], - "pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], - "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], "vitepress/@types/markdown-it": ["@types/markdown-it@14.1.2", "", { "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog=="], - "vitepress/vue": ["vue@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/compiler-sfc": "3.5.24", "@vue/runtime-dom": "3.5.24", "@vue/server-renderer": "3.5.24", "@vue/shared": "3.5.24" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg=="], + "wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "vue/@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="], - - "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - - "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "xss/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], @@ -1742,42 +1695,10 @@ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], - "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - "@ts-morph/common/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - "@vueuse/core/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.24", "", { "dependencies": { "@vue/compiler-core": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw=="], - - "@vueuse/core/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/compiler-core": "3.5.24", "@vue/compiler-dom": "3.5.24", "@vue/compiler-ssr": "3.5.24", "@vue/shared": "3.5.24", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g=="], - - "@vueuse/core/vue/@vue/runtime-dom": ["@vue/runtime-dom@3.5.24", "", { "dependencies": { "@vue/reactivity": "3.5.24", "@vue/runtime-core": "3.5.24", "@vue/shared": "3.5.24", "csstype": "^3.1.3" } }, "sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw=="], - - "@vueuse/core/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.24", "", { "dependencies": { "@vue/compiler-ssr": "3.5.24", "@vue/shared": "3.5.24" }, "peerDependencies": { "vue": "3.5.24" } }, "sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w=="], - - "@vueuse/integrations/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.24", "", { "dependencies": { "@vue/compiler-core": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw=="], - - "@vueuse/integrations/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/compiler-core": "3.5.24", "@vue/compiler-dom": "3.5.24", "@vue/compiler-ssr": "3.5.24", "@vue/shared": "3.5.24", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g=="], - - "@vueuse/integrations/vue/@vue/runtime-dom": ["@vue/runtime-dom@3.5.24", "", { "dependencies": { "@vue/reactivity": "3.5.24", "@vue/runtime-core": "3.5.24", "@vue/shared": "3.5.24", "csstype": "^3.1.3" } }, "sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw=="], - - "@vueuse/integrations/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.24", "", { "dependencies": { "@vue/compiler-ssr": "3.5.24", "@vue/shared": "3.5.24" }, "peerDependencies": { "vue": "3.5.24" } }, "sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w=="], - - "@vueuse/shared/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.24", "", { "dependencies": { "@vue/compiler-core": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw=="], - - "@vueuse/shared/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/compiler-core": "3.5.24", "@vue/compiler-dom": "3.5.24", "@vue/compiler-ssr": "3.5.24", "@vue/shared": "3.5.24", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g=="], - - "@vueuse/shared/vue/@vue/runtime-dom": ["@vue/runtime-dom@3.5.24", "", { "dependencies": { "@vue/reactivity": "3.5.24", "@vue/runtime-core": "3.5.24", "@vue/shared": "3.5.24", "csstype": "^3.1.3" } }, "sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw=="], - - "@vueuse/shared/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.24", "", { "dependencies": { "@vue/compiler-ssr": "3.5.24", "@vue/shared": "3.5.24" }, "peerDependencies": { "vue": "3.5.24" } }, "sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w=="], - - "cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], @@ -1828,86 +1749,12 @@ "vitepress/@types/markdown-it/@types/mdurl": ["@types/mdurl@2.0.0", "", {}, "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="], - "vitepress/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.24", "", { "dependencies": { "@vue/compiler-core": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw=="], - - "vitepress/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/compiler-core": "3.5.24", "@vue/compiler-dom": "3.5.24", "@vue/compiler-ssr": "3.5.24", "@vue/shared": "3.5.24", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g=="], - - "vitepress/vue/@vue/runtime-dom": ["@vue/runtime-dom@3.5.24", "", { "dependencies": { "@vue/reactivity": "3.5.24", "@vue/runtime-core": "3.5.24", "@vue/shared": "3.5.24", "csstype": "^3.1.3" } }, "sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw=="], - - "vitepress/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.24", "", { "dependencies": { "@vue/compiler-ssr": "3.5.24", "@vue/shared": "3.5.24" }, "peerDependencies": { "vue": "3.5.24" } }, "sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w=="], - - "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.24", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig=="], - - "@vueuse/core/vue/@vue/compiler-sfc/@vue/compiler-core": ["@vue/compiler-core@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.24", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig=="], - - "@vueuse/core/vue/@vue/compiler-sfc/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg=="], - - "@vueuse/core/vue/@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "@vueuse/core/vue/@vue/runtime-dom/@vue/reactivity": ["@vue/reactivity@3.5.24", "", { "dependencies": { "@vue/shared": "3.5.24" } }, "sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg=="], - - "@vueuse/core/vue/@vue/runtime-dom/@vue/runtime-core": ["@vue/runtime-core@3.5.24", "", { "dependencies": { "@vue/reactivity": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ=="], - - "@vueuse/core/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg=="], - - "@vueuse/integrations/vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.24", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig=="], - - "@vueuse/integrations/vue/@vue/compiler-sfc/@vue/compiler-core": ["@vue/compiler-core@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.24", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig=="], - - "@vueuse/integrations/vue/@vue/compiler-sfc/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg=="], - - "@vueuse/integrations/vue/@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "@vueuse/integrations/vue/@vue/runtime-dom/@vue/reactivity": ["@vue/reactivity@3.5.24", "", { "dependencies": { "@vue/shared": "3.5.24" } }, "sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg=="], - - "@vueuse/integrations/vue/@vue/runtime-dom/@vue/runtime-core": ["@vue/runtime-core@3.5.24", "", { "dependencies": { "@vue/reactivity": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ=="], - - "@vueuse/integrations/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg=="], - - "@vueuse/shared/vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.24", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig=="], - - "@vueuse/shared/vue/@vue/compiler-sfc/@vue/compiler-core": ["@vue/compiler-core@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.24", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig=="], - - "@vueuse/shared/vue/@vue/compiler-sfc/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg=="], - - "@vueuse/shared/vue/@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "@vueuse/shared/vue/@vue/runtime-dom/@vue/reactivity": ["@vue/reactivity@3.5.24", "", { "dependencies": { "@vue/shared": "3.5.24" } }, "sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg=="], - - "@vueuse/shared/vue/@vue/runtime-dom/@vue/runtime-core": ["@vue/runtime-core@3.5.24", "", { "dependencies": { "@vue/reactivity": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ=="], - - "@vueuse/shared/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg=="], - - "vitepress/vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.24", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig=="], - - "vitepress/vue/@vue/compiler-sfc/@vue/compiler-core": ["@vue/compiler-core@3.5.24", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.24", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig=="], - - "vitepress/vue/@vue/compiler-sfc/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg=="], - - "vitepress/vue/@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "vitepress/vue/@vue/runtime-dom/@vue/reactivity": ["@vue/reactivity@3.5.24", "", { "dependencies": { "@vue/shared": "3.5.24" } }, "sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg=="], - - "vitepress/vue/@vue/runtime-dom/@vue/runtime-core": ["@vue/runtime-core@3.5.24", "", { "dependencies": { "@vue/reactivity": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ=="], - - "vitepress/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.24", "", { "dependencies": { "@vue/compiler-dom": "3.5.24", "@vue/shared": "3.5.24" } }, "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg=="], + "@ts-morph/common/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "@vueuse/integrations/vue/@vue/compiler-dom/@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "@vueuse/shared/vue/@vue/compiler-dom/@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "vitepress/vue/@vue/compiler-dom/@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], } } diff --git a/cli/user/refetch.ts b/cli/user/refetch.ts index 376fb9c9..e889fa88 100644 --- a/cli/user/refetch.ts +++ b/cli/user/refetch.ts @@ -28,10 +28,7 @@ export const refetchUserCommand = defineCommand( const spinner = ora("Refetching user").start(); try { - await User.fromVersia( - user.reference, - user.reference.domain as string, - ); + await User.fromVersia(user.reference); } catch (error) { spinner.fail( `Failed to refetch user ${chalk.gray(user.data.username)}`, diff --git a/flake.nix b/flake.nix index 8fb917da..bb1d10d4 100644 --- a/flake.nix +++ b/flake.nix @@ -48,6 +48,7 @@ default = pkgs.mkShell rec { libPath = with pkgs; lib.makeLibraryPath [ + vips stdenv.cc.cc.lib ]; @@ -55,7 +56,6 @@ buildInputs = with pkgs; [ bun - vips nodePackages.typescript nodePackages.typescript-language-server nix-ld diff --git a/package.json b/package.json index a5fa20bd..6793fe20 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "hono-openapi": "~1.1.2", "hono-rate-limiter": "~0.5.1", "html-to-text": "~9.0.5", - "ioredis": "~5.8.2", + "ioredis": "5.9.2", "ip-matching": "~2.1.2", "iso-639-1": "~3.1.5", "linkify-html": "~4.3.2", @@ -158,6 +158,7 @@ "dependencies": { "@bull-board/api": "catalog:", "@bull-board/hono": "catalog:", + "@clerc/core": "catalog:", "@clerc/plugin-completions": "catalog:", "@clerc/plugin-friendly-error": "catalog:", "@clerc/plugin-help": "catalog:", @@ -180,7 +181,6 @@ "blurhash": "catalog:", "bullmq": "catalog:", "chalk": "catalog:", - "@clerc/core": "catalog:", "confbox": "catalog:", "drizzle-orm": "catalog:", "feed": "catalog:", @@ -216,5 +216,8 @@ "zod": "catalog:", "zod-openapi": "catalog:", "zod-validation-error": "catalog:" + }, + "patchedDependencies": { + "bun-bagel@1.2.0": "patches/bun-bagel@1.2.0.patch" } } diff --git a/packages/api/routes/api/v1/accounts/[id]/refetch.ts b/packages/api/routes/api/v1/accounts/[id]/refetch.ts index 5f3d6577..6905c9e2 100644 --- a/packages/api/routes/api/v1/accounts/[id]/refetch.ts +++ b/packages/api/routes/api/v1/accounts/[id]/refetch.ts @@ -50,10 +50,7 @@ export default apiRoute((app) => throw new ApiError(400, "Cannot refetch a local user"); } - const newUser = await User.fromVersia( - otherUser.reference, - otherUser.reference.domain as string, - ); + const newUser = await User.fromVersia(otherUser.reference); return context.json(newUser.toApi(false), 200); }, diff --git a/packages/api/routes/api/v1/accounts/lookup/index.ts b/packages/api/routes/api/v1/accounts/lookup/index.ts index 3122e1b6..c5651dd9 100644 --- a/packages/api/routes/api/v1/accounts/lookup/index.ts +++ b/packages/api/routes/api/v1/accounts/lookup/index.ts @@ -106,10 +106,7 @@ export default apiRoute((app) => VersiaEntities.User, ); - const foundAccount = await User.fromVersia( - accountData, - instance.data.baseUrl, - ); + const foundAccount = await User.fromVersia(accountData, instance); return context.json(foundAccount.toApi(), 200); }, diff --git a/packages/api/routes/api/v1/accounts/search/index.ts b/packages/api/routes/api/v1/accounts/search/index.ts index ee787542..3fd465b8 100644 --- a/packages/api/routes/api/v1/accounts/search/index.ts +++ b/packages/api/routes/api/v1/accounts/search/index.ts @@ -101,7 +101,7 @@ export default apiRoute((app) => const foundAccount = await User.fromVersia( accountData, - instance.data.baseUrl, + instance, ); accounts.push(foundAccount); diff --git a/packages/api/routes/api/v2/search/index.ts b/packages/api/routes/api/v2/search/index.ts index 432e3faf..0724dc5b 100644 --- a/packages/api/routes/api/v2/search/index.ts +++ b/packages/api/routes/api/v2/search/index.ts @@ -200,7 +200,7 @@ export default apiRoute((app) => const newUser = await User.fromVersia( accountData, - instance.data.baseUrl, + instance, ); return context.json( diff --git a/packages/api/routes/oauth/sso/[issuer]/callback.ts b/packages/api/routes/oauth/sso/[issuer]/callback.ts index a45cc7f4..682e3f4a 100644 --- a/packages/api/routes/oauth/sso/[issuer]/callback.ts +++ b/packages/api/routes/oauth/sso/[issuer]/callback.ts @@ -65,6 +65,7 @@ export default apiRoute((app) => { const jwtPayload = (await verify(state, config.authentication.key, { iss: config.http.base_url.toString(), + alg: "HS256", })) as { flow: string; link?: boolean; diff --git a/packages/api/routes/versia/v0.6/inbox.test.ts b/packages/api/routes/versia/v0.6/inbox.test.ts index b9c12a80..bcf4d992 100644 --- a/packages/api/routes/versia/v0.6/inbox.test.ts +++ b/packages/api/routes/versia/v0.6/inbox.test.ts @@ -40,6 +40,17 @@ mock(new URL("/.well-known/versia", instanceUrl).href, { headers: { "Content-Type": "application/json", }, + data: { + versions: ["0.6.0"], + }, + }, +}); + +mock(new URL("/.versia/v0.6/instance", instanceUrl).href, { + response: { + headers: { + "Content-Type": "application/vnd.versia+json; charset=utf-8", + }, data: new VersiaEntities.InstanceMetadata({ type: "InstanceMetadata", name: "Versia", @@ -70,7 +81,7 @@ mock(new URL("/.well-known/versia", instanceUrl).href, { mock(new URL(`/.versia/v0.6/entities/User/${userId}`, instanceUrl).href, { response: { headers: { - "Content-Type": "application/json", + "Content-Type": "application/vnd.versia+json; charset=utf-8", }, data: new VersiaEntities.User({ id: userId, @@ -132,7 +143,7 @@ describe("Inbox Tests", () => { const signedRequest = await sign( instanceKeys.privateKey, - new URL(exampleNote.data.author), + instanceUrl, new Request(inboxUrl, { method: "POST", headers: { @@ -151,6 +162,8 @@ describe("Inbox Tests", () => { body: signedRequest.body, }); + console.log(await response.text()); + expect(response.status).toBe(200); await sleep(500); @@ -174,7 +187,7 @@ describe("Inbox Tests", () => { const signedRequest = await sign( instanceKeys.privateKey, - new URL(exampleRequest.data.author), + instanceUrl, new Request(inboxUrl, { method: "POST", headers: { @@ -227,7 +240,7 @@ describe("Inbox Tests", () => { const signedRequest = await sign( instanceKeys.privateKey, - new URL(exampleRequest.data.author), + instanceUrl, new Request(inboxUrl, { method: "POST", headers: { @@ -322,7 +335,7 @@ describe("Inbox Tests", () => { const signedRequest = await sign( instanceKeys.privateKey, - new URL(exampleRequest.data.author), + instanceUrl, new Request(inboxUrl, { method: "POST", headers: { @@ -402,7 +415,7 @@ describe("Inbox Tests", () => { const signedRequest = await sign( instanceKeys.privateKey, - new URL(exampleRequest.data.author), + instanceUrl, new Request(inboxUrl, { method: "POST", headers: { diff --git a/packages/api/routes/versia/v0.6/inbox.ts b/packages/api/routes/versia/v0.6/inbox.ts index c642b3d5..1ddcf458 100644 --- a/packages/api/routes/versia/v0.6/inbox.ts +++ b/packages/api/routes/versia/v0.6/inbox.ts @@ -4,7 +4,7 @@ import z from "zod"; import { InboxJobType, inboxQueue } from "~/packages/kit/queues/inbox/queue"; export default apiRoute((app) => - app.get( + app.post( "/.versia/v0.6/inbox", describeRoute({ summary: "Instance inbox endpoint", diff --git a/packages/kit/db/note.ts b/packages/kit/db/note.ts index 2c56f4c7..d115e482 100644 --- a/packages/kit/db/note.ts +++ b/packages/kit/db/note.ts @@ -941,20 +941,19 @@ export class Note extends BaseInterface { */ public static async resolve( reference: VersiaEntities.Reference, + defaultInstance?: Instance, ): Promise { // Check if note not already in database if ( - !reference.domain || + !(reference.domain || defaultInstance) || reference.domain === config.http.base_url.hostname ) { return await Note.fromId(reference.id); } - const instance = await Instance.resolve(reference.domain); - - if (!instance) { - return null; - } + const instance = reference.domain + ? await Instance.resolve(reference.domain) + : (defaultInstance as Instance); const foundNote = await Note.fromSql( and( @@ -963,7 +962,7 @@ export class Note extends BaseInterface { Notes.authorId, sql`( SELECT "Users".id FROM "Users" - WHERE "Users".instanceId = ${instance.id} + WHERE "Users"."instanceId" = ${instance.id} LIMIT 1 )`, ), @@ -974,7 +973,14 @@ export class Note extends BaseInterface { return foundNote; } - return Note.fromVersia(reference); + return Note.fromVersia( + reference.domain + ? reference + : new VersiaEntities.Reference( + reference.id, + instance.data.baseUrl, + ), + ); } /** @@ -983,28 +989,45 @@ export class Note extends BaseInterface { * If the note already exists, it will update it. * @param versiaNote - Reference or Versia Note representation */ + public static async fromVersia( + versiaNote: VersiaEntities.Note, + instance: Instance, + ): Promise; + + public static async fromVersia( + reference: VersiaEntities.Reference, + ): Promise; + public static async fromVersia( versiaNote: VersiaEntities.Note | VersiaEntities.Reference, + instance?: Instance, ): Promise { if (versiaNote instanceof VersiaEntities.Reference) { + if (!versiaNote.domain) { + throw new Error( + "Cannot fetch Versia note from reference without domain", + ); + } + // No bridge support for notes yet const note = await Instance.federationRequester.fetchEntity( versiaNote, VersiaEntities.Note, ); - return Note.fromVersia(note); + const instance = await Instance.resolve(versiaNote.domain); + + return Note.fromVersia(note, instance); + } + + if (!instance) { + throw new Error("Instance must be provided when fetching note"); } const { created_at, extensions, group, id, is_sensitive, subject } = versiaNote.data; - if (!versiaNote.author.domain) { - throw new Error("Entity author domain is missing"); - } - - const instance = await Instance.resolve(versiaNote.author.domain); - const author = await User.resolve(versiaNote.author); + const author = await User.resolve(versiaNote.author, instance); if (!author) { throw new Error("Entity author could not be resolved"); @@ -1041,7 +1064,7 @@ export class Note extends BaseInterface { const mentions = ( await Promise.all( - versiaNote.mentions.map((m) => User.resolve(m)) ?? [], + versiaNote.mentions.map((m) => User.resolve(m, instance)) ?? [], ) ).filter((m) => m !== null); @@ -1052,10 +1075,10 @@ export class Note extends BaseInterface { : (group as "public" | "followers" | "unlisted"); const reply = versiaNote.repliesTo - ? await Note.resolve(versiaNote.repliesTo) + ? await Note.resolve(versiaNote.repliesTo, instance) : null; const quote = versiaNote.quotes - ? await Note.resolve(versiaNote.quotes) + ? await Note.resolve(versiaNote.quotes, instance) : null; const spoiler = subject ? await sanitizedHtmlStrip(subject) : undefined; diff --git a/packages/kit/db/user.ts b/packages/kit/db/user.ts index 4d63a931..fadef644 100644 --- a/packages/kit/db/user.ts +++ b/packages/kit/db/user.ts @@ -672,9 +672,18 @@ export class User extends BaseInterface { * If the user already exists, it will update it. * @param versiaUser Reference or Versia User representation */ + public static async fromVersia( + versiaUser: VersiaEntities.User, + instance: Instance, + ): Promise; + + public static async fromVersia( + versiaUser: VersiaEntities.Reference, + ): Promise; + public static async fromVersia( versiaUser: VersiaEntities.User | VersiaEntities.Reference, - domain: string, + instance?: Instance, ): Promise { if (versiaUser instanceof VersiaEntities.Reference) { if (!versiaUser.domain) { @@ -688,7 +697,13 @@ export class User extends BaseInterface { VersiaEntities.User, ); - return User.fromVersia(user, versiaUser.domain); + const instance = await Instance.resolve(versiaUser.domain); + + return User.fromVersia(user, instance); + } + + if (!instance) { + throw new Error("Instance must be provided when fetching user"); } const { @@ -702,7 +717,6 @@ export class User extends BaseInterface { extensions, } = versiaUser.data; - const instance = await Instance.resolve(domain); const existingUser = await User.fromSql( and(eq(Users.instanceId, instance.id), eq(Users.remoteId, id)), ); @@ -788,10 +802,11 @@ export class User extends BaseInterface { public static async resolve( reference: VersiaEntities.Reference, + defaultInstance?: Instance, ): Promise { // Check if user not already in database if ( - !reference.domain || + !(reference.domain || defaultInstance) || reference.domain === config.http.base_url.hostname ) { const user = await User.fromId(reference.id); @@ -805,7 +820,9 @@ export class User extends BaseInterface { return user; } - const instance = await Instance.resolve(reference.domain); + const instance = reference.domain + ? await Instance.resolve(reference.domain) + : (defaultInstance as Instance); const foundUser = await User.fromSql( and( @@ -818,7 +835,14 @@ export class User extends BaseInterface { return foundUser; } - return User.fromVersia(reference, reference.domain); + return User.fromVersia( + reference.domain + ? reference + : new VersiaEntities.Reference( + reference.id, + instance.data.baseUrl, + ), + ); } /** diff --git a/packages/kit/inbox-processor.ts b/packages/kit/inbox-processor.ts index 7e704c88..1c3a805b 100644 --- a/packages/kit/inbox-processor.ts +++ b/packages/kit/inbox-processor.ts @@ -182,32 +182,36 @@ export class InboxProcessor { shouldCheckSignature && federationInboxLogger.debug`Signature is valid`; try { + // TODO: Rip out bridge code so this is never null + const instance = this.sender?.instance as Instance; + await new EntitySorter(this.body) - .on(VersiaEntities.Note, (n) => InboxProcessor.processNote(n)) + .on(VersiaEntities.Note, (n) => + InboxProcessor.processNote(n, instance), + ) .on(VersiaEntities.Follow, (f) => - InboxProcessor.processFollowRequest(f), + InboxProcessor.processFollowRequest(f, instance), ) .on(VersiaEntities.FollowAccept, (f) => - InboxProcessor.processFollowAccept(f), + InboxProcessor.processFollowAccept(f, instance), ) .on(VersiaEntities.FollowReject, (f) => - InboxProcessor.processFollowReject(f), + InboxProcessor.processFollowReject(f, instance), ) .on(VersiaEntities.Like, (l) => - InboxProcessor.processLikeRequest(l), + InboxProcessor.processLikeRequest(l, instance), ) .on(VersiaEntities.Delete, (d) => - InboxProcessor.processDelete(d), + InboxProcessor.processDelete(d, instance), ) .on(VersiaEntities.User, (u) => - InboxProcessor.processUser( - u, - this.sender?.instance.data.baseUrl ?? "", - ), + InboxProcessor.processUser(u, instance), + ) + .on(VersiaEntities.Share, (s) => + InboxProcessor.processShare(s, instance), ) - .on(VersiaEntities.Share, (s) => InboxProcessor.processShare(s)) .on(VersiaEntities.Reaction, (r) => - InboxProcessor.processReaction(r), + InboxProcessor.processReaction(r, instance), ) .sort(() => { throw new ApiError(400, "Unknown entity type"); @@ -225,9 +229,10 @@ export class InboxProcessor { */ private static async processReaction( reaction: VersiaEntities.Reaction, + sender: Instance, ): Promise { - const author = await User.resolve(reaction.author); - const note = await Note.resolve(reaction.object); + const author = await User.resolve(reaction.author, sender); + const note = await Note.resolve(reaction.object, sender); if (!author) { throw new ApiError(404, "Author not found"); @@ -246,7 +251,10 @@ export class InboxProcessor { * @param {VersiaNote} note - The Note entity to process. * @returns {Promise} */ - private static async processNote(note: VersiaEntities.Note): Promise { + private static async processNote( + note: VersiaEntities.Note, + sender: Instance, + ): Promise { // If note has a blocked word if ( Object.values(note.content?.data ?? {}) @@ -262,7 +270,7 @@ export class InboxProcessor { return; } - await Note.fromVersia(note); + await Note.fromVersia(note, sender); } /** @@ -274,7 +282,7 @@ export class InboxProcessor { */ private static async processUser( user: VersiaEntities.User, - domain: string, + sender: Instance, ): Promise { if ( config.validation.filters.username.some((filter) => @@ -303,7 +311,7 @@ export class InboxProcessor { return; } - await User.fromVersia(user, domain); + await User.fromVersia(user, sender); } /** @@ -314,9 +322,10 @@ export class InboxProcessor { */ private static async processFollowRequest( follow: VersiaEntities.Follow, + sender: Instance, ): Promise { - const author = await User.resolve(follow.author); - const followee = await User.resolve(follow.followee); + const author = await User.resolve(follow.author, sender); + const followee = await User.resolve(follow.followee, sender); if (!author) { throw new ApiError(404, "Author not found"); @@ -362,9 +371,10 @@ export class InboxProcessor { */ private static async processFollowAccept( followAccept: VersiaEntities.FollowAccept, + sender: Instance, ): Promise { - const author = await User.resolve(followAccept.author); - const follower = await User.resolve(followAccept.follower); + const author = await User.resolve(followAccept.author, sender); + const follower = await User.resolve(followAccept.follower, sender); if (!author) { throw new ApiError(404, "Author not found"); @@ -397,9 +407,10 @@ export class InboxProcessor { */ private static async processFollowReject( followReject: VersiaEntities.FollowReject, + sender: Instance, ): Promise { - const author = await User.resolve(followReject.author); - const follower = await User.resolve(followReject.follower); + const author = await User.resolve(followReject.author, sender); + const follower = await User.resolve(followReject.follower, sender); if (!author) { throw new ApiError(404, "Author not found"); @@ -432,9 +443,10 @@ export class InboxProcessor { */ private static async processShare( share: VersiaEntities.Share, + sender: Instance, ): Promise { - const author = await User.resolve(share.author); - const sharedNote = await Note.resolve(share.shared); + const author = await User.resolve(share.author, sender); + const sharedNote = await Note.resolve(share.shared, sender); if (!author) { throw new ApiError(404, "Author not found"); @@ -455,10 +467,11 @@ export class InboxProcessor { */ // JS doesn't allow the use of `delete` as a variable name public static async processDelete( delete_: VersiaEntities.Delete, + sender: Instance, ): Promise { const toDelete = delete_.deleted; - const author = await User.resolve(delete_.author); + const author = await User.resolve(delete_.author, sender); switch (delete_.data.deleted_type) { case "Note": { @@ -478,7 +491,7 @@ export class InboxProcessor { return; } case "User": { - const userToDelete = await User.resolve(toDelete); + const userToDelete = await User.resolve(toDelete, sender); if (!userToDelete) { throw new ApiError(404, "User to delete not found"); @@ -573,9 +586,10 @@ export class InboxProcessor { */ private static async processLikeRequest( like: VersiaEntities.Like, + sender: Instance, ): Promise { - const author = await User.resolve(like.author); - const likedNote = await Note.resolve(like.liked); + const author = await User.resolve(like.author, sender); + const likedNote = await Note.resolve(like.liked, sender); if (!author) { throw new ApiError(404, "Author not found"); diff --git a/packages/kit/parsers.ts b/packages/kit/parsers.ts index c02e0a21..c505de5b 100644 --- a/packages/kit/parsers.ts +++ b/packages/kit/parsers.ts @@ -87,7 +87,9 @@ export const parseMentionsFromText = async (text: string): Promise => { VersiaEntities.User, ); - const user = await User.fromVersia(userEntity, url.hostname); + const instance = await Instance.resolve(url.hostname); + + const user = await User.fromVersia(userEntity, instance); if (user) { finalList.push(user); diff --git a/packages/kit/tables/migrations/0054_good_madelyne_pryor.sql b/packages/kit/tables/migrations/0054_good_madelyne_pryor.sql new file mode 100644 index 00000000..9c66eff6 --- /dev/null +++ b/packages/kit/tables/migrations/0054_good_madelyne_pryor.sql @@ -0,0 +1,14 @@ +ALTER TABLE "Likes" DROP CONSTRAINT "Likes_uri_unique";--> statement-breakpoint +ALTER TABLE "Notes" DROP CONSTRAINT "Notes_uri_unique";--> statement-breakpoint +ALTER TABLE "Users" DROP CONSTRAINT "Users_uri_unique";--> statement-breakpoint +DROP INDEX "Users_uri_index";--> statement-breakpoint +ALTER TABLE "Likes" ADD COLUMN "remote_id" text;--> statement-breakpoint +ALTER TABLE "Notes" ADD COLUMN "remote_id" text;--> statement-breakpoint +ALTER TABLE "Reaction" ADD COLUMN "remote_id" text;--> statement-breakpoint +ALTER TABLE "Users" ADD COLUMN "remote_id" text;--> statement-breakpoint +ALTER TABLE "Likes" DROP COLUMN "uri";--> statement-breakpoint +ALTER TABLE "Notes" DROP COLUMN "uri";--> statement-breakpoint +ALTER TABLE "Users" DROP COLUMN "uri";--> statement-breakpoint +ALTER TABLE "Users" DROP COLUMN "endpoints";--> statement-breakpoint +ALTER TABLE "Users" DROP COLUMN "public_key";--> statement-breakpoint +ALTER TABLE "Users" DROP COLUMN "private_key"; \ No newline at end of file diff --git a/packages/kit/tables/migrations/meta/0054_snapshot.json b/packages/kit/tables/migrations/meta/0054_snapshot.json new file mode 100644 index 00000000..728db0f4 --- /dev/null +++ b/packages/kit/tables/migrations/meta/0054_snapshot.json @@ -0,0 +1,2394 @@ +{ + "id": "745b99d4-d429-47a6-b252-d1ae9f37e948", + "prevId": "5e2c1ea7-3a9a-4241-9f66-73ad8081371a", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.AuthorizationCodes": { + "name": "AuthorizationCodes", + "schema": "", + "columns": { + "code": { + "name": "code", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "code_challenge": { + "name": "code_challenge", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "code_challenge_method": { + "name": "code_challenge_method", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "clientId": { + "name": "clientId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "AuthorizationCodes_userId_Users_id_fk": { + "name": "AuthorizationCodes_userId_Users_id_fk", + "tableFrom": "AuthorizationCodes", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "AuthorizationCodes_clientId_Clients_client_id_fk": { + "name": "AuthorizationCodes_clientId_Clients_client_id_fk", + "tableFrom": "AuthorizationCodes", + "tableTo": "Clients", + "columnsFrom": ["clientId"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Challenges": { + "name": "Challenges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "challenge": { + "name": "challenge", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "NOW() + INTERVAL '5 minutes'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Clients": { + "name": "Clients", + "schema": "", + "columns": { + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "redirect_uris": { + "name": "redirect_uris", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.EmojiToNote": { + "name": "EmojiToNote", + "schema": "", + "columns": { + "emojiId": { + "name": "emojiId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "noteId": { + "name": "noteId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "EmojiToNote_emojiId_noteId_index": { + "name": "EmojiToNote_emojiId_noteId_index", + "columns": [ + { + "expression": "emojiId", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "noteId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "EmojiToNote_noteId_index": { + "name": "EmojiToNote_noteId_index", + "columns": [ + { + "expression": "noteId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "EmojiToNote_emojiId_Emojis_id_fk": { + "name": "EmojiToNote_emojiId_Emojis_id_fk", + "tableFrom": "EmojiToNote", + "tableTo": "Emojis", + "columnsFrom": ["emojiId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "EmojiToNote_noteId_Notes_id_fk": { + "name": "EmojiToNote_noteId_Notes_id_fk", + "tableFrom": "EmojiToNote", + "tableTo": "Notes", + "columnsFrom": ["noteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.EmojiToUser": { + "name": "EmojiToUser", + "schema": "", + "columns": { + "emojiId": { + "name": "emojiId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "EmojiToUser_emojiId_userId_index": { + "name": "EmojiToUser_emojiId_userId_index", + "columns": [ + { + "expression": "emojiId", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "EmojiToUser_userId_index": { + "name": "EmojiToUser_userId_index", + "columns": [ + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "EmojiToUser_emojiId_Emojis_id_fk": { + "name": "EmojiToUser_emojiId_Emojis_id_fk", + "tableFrom": "EmojiToUser", + "tableTo": "Emojis", + "columnsFrom": ["emojiId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "EmojiToUser_userId_Users_id_fk": { + "name": "EmojiToUser_userId_Users_id_fk", + "tableFrom": "EmojiToUser", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Emojis": { + "name": "Emojis", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "shortcode": { + "name": "shortcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mediaId": { + "name": "mediaId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "visible_in_picker": { + "name": "visible_in_picker", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "instanceId": { + "name": "instanceId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "ownerId": { + "name": "ownerId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "Emojis_mediaId_Medias_id_fk": { + "name": "Emojis_mediaId_Medias_id_fk", + "tableFrom": "Emojis", + "tableTo": "Medias", + "columnsFrom": ["mediaId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Emojis_instanceId_Instances_id_fk": { + "name": "Emojis_instanceId_Instances_id_fk", + "tableFrom": "Emojis", + "tableTo": "Instances", + "columnsFrom": ["instanceId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Emojis_ownerId_Users_id_fk": { + "name": "Emojis_ownerId_Users_id_fk", + "tableFrom": "Emojis", + "tableTo": "Users", + "columnsFrom": ["ownerId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.FilterKeywords": { + "name": "FilterKeywords", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "filterId": { + "name": "filterId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "whole_word": { + "name": "whole_word", + "type": "boolean", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "FilterKeywords_filterId_Filters_id_fk": { + "name": "FilterKeywords_filterId_Filters_id_fk", + "tableFrom": "FilterKeywords", + "tableTo": "Filters", + "columnsFrom": ["filterId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Filters": { + "name": "Filters", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "context": { + "name": "context", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filter_action": { + "name": "filter_action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "Filters_userId_Users_id_fk": { + "name": "Filters_userId_Users_id_fk", + "tableFrom": "Filters", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Flags": { + "name": "Flags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "flag_type": { + "name": "flag_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'other'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "noteId": { + "name": "noteId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "Flags_noteId_Notes_id_fk": { + "name": "Flags_noteId_Notes_id_fk", + "tableFrom": "Flags", + "tableTo": "Notes", + "columnsFrom": ["noteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Flags_userId_Users_id_fk": { + "name": "Flags_userId_Users_id_fk", + "tableFrom": "Flags", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Instances": { + "name": "Instances", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "base_url": { + "name": "base_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "disable_automoderation": { + "name": "disable_automoderation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "protocol": { + "name": "protocol", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'versia'" + }, + "inbox": { + "name": "inbox", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "public_key": { + "name": "public_key", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "extensions": { + "name": "extensions", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Likes": { + "name": "Likes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "remote_id": { + "name": "remote_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "likerId": { + "name": "likerId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "likedId": { + "name": "likedId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "Likes_likerId_Users_id_fk": { + "name": "Likes_likerId_Users_id_fk", + "tableFrom": "Likes", + "tableTo": "Users", + "columnsFrom": ["likerId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Likes_likedId_Notes_id_fk": { + "name": "Likes_likedId_Notes_id_fk", + "tableFrom": "Likes", + "tableTo": "Notes", + "columnsFrom": ["likedId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Markers": { + "name": "Markers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "noteId": { + "name": "noteId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notificationId": { + "name": "notificationId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "timeline": { + "name": "timeline", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "Markers_noteId_Notes_id_fk": { + "name": "Markers_noteId_Notes_id_fk", + "tableFrom": "Markers", + "tableTo": "Notes", + "columnsFrom": ["noteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Markers_notificationId_Notifications_id_fk": { + "name": "Markers_notificationId_Notifications_id_fk", + "tableFrom": "Markers", + "tableTo": "Notifications", + "columnsFrom": ["notificationId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Markers_userId_Users_id_fk": { + "name": "Markers_userId_Users_id_fk", + "tableFrom": "Markers", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Medias": { + "name": "Medias", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "original_content": { + "name": "original_content", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "thumbnail": { + "name": "thumbnail", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "blurhash": { + "name": "blurhash", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.MediasToNote": { + "name": "MediasToNote", + "schema": "", + "columns": { + "mediaId": { + "name": "mediaId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "noteId": { + "name": "noteId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "MediasToNote_mediaId_index": { + "name": "MediasToNote_mediaId_index", + "columns": [ + { + "expression": "mediaId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "MediasToNote_noteId_index": { + "name": "MediasToNote_noteId_index", + "columns": [ + { + "expression": "noteId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "MediasToNote_mediaId_Medias_id_fk": { + "name": "MediasToNote_mediaId_Medias_id_fk", + "tableFrom": "MediasToNote", + "tableTo": "Medias", + "columnsFrom": ["mediaId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "MediasToNote_noteId_Notes_id_fk": { + "name": "MediasToNote_noteId_Notes_id_fk", + "tableFrom": "MediasToNote", + "tableTo": "Notes", + "columnsFrom": ["noteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ModNotes": { + "name": "ModNotes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "noteId": { + "name": "noteId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "modId": { + "name": "modId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "ModNotes_noteId_Notes_id_fk": { + "name": "ModNotes_noteId_Notes_id_fk", + "tableFrom": "ModNotes", + "tableTo": "Notes", + "columnsFrom": ["noteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "ModNotes_userId_Users_id_fk": { + "name": "ModNotes_userId_Users_id_fk", + "tableFrom": "ModNotes", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "ModNotes_modId_Users_id_fk": { + "name": "ModNotes_modId_Users_id_fk", + "tableFrom": "ModNotes", + "tableTo": "Users", + "columnsFrom": ["modId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ModTags": { + "name": "ModTags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "noteId": { + "name": "noteId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "modId": { + "name": "modId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "tag": { + "name": "tag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "ModTags_noteId_Notes_id_fk": { + "name": "ModTags_noteId_Notes_id_fk", + "tableFrom": "ModTags", + "tableTo": "Notes", + "columnsFrom": ["noteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "ModTags_userId_Users_id_fk": { + "name": "ModTags_userId_Users_id_fk", + "tableFrom": "ModTags", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "ModTags_modId_Users_id_fk": { + "name": "ModTags_modId_Users_id_fk", + "tableFrom": "ModTags", + "tableTo": "Users", + "columnsFrom": ["modId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.NoteToMentions": { + "name": "NoteToMentions", + "schema": "", + "columns": { + "noteId": { + "name": "noteId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "NoteToMentions_noteId_userId_index": { + "name": "NoteToMentions_noteId_userId_index", + "columns": [ + { + "expression": "noteId", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "NoteToMentions_userId_index": { + "name": "NoteToMentions_userId_index", + "columns": [ + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "NoteToMentions_noteId_Notes_id_fk": { + "name": "NoteToMentions_noteId_Notes_id_fk", + "tableFrom": "NoteToMentions", + "tableTo": "Notes", + "columnsFrom": ["noteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "NoteToMentions_userId_Users_id_fk": { + "name": "NoteToMentions_userId_Users_id_fk", + "tableFrom": "NoteToMentions", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Notes": { + "name": "Notes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "remote_id": { + "name": "remote_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "authorId": { + "name": "authorId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "reblogId": { + "name": "reblogId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text/plain'" + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reblog_count": { + "name": "reblog_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "like_count": { + "name": "like_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "reply_count": { + "name": "reply_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "replyId": { + "name": "replyId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "quoteId": { + "name": "quoteId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "spoiler_text": { + "name": "spoiler_text", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "clientId": { + "name": "clientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_source": { + "name": "content_source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "Notes_authorId_Users_id_fk": { + "name": "Notes_authorId_Users_id_fk", + "tableFrom": "Notes", + "tableTo": "Users", + "columnsFrom": ["authorId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Notes_reblogId_Notes_id_fk": { + "name": "Notes_reblogId_Notes_id_fk", + "tableFrom": "Notes", + "tableTo": "Notes", + "columnsFrom": ["reblogId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Notes_replyId_Notes_id_fk": { + "name": "Notes_replyId_Notes_id_fk", + "tableFrom": "Notes", + "tableTo": "Notes", + "columnsFrom": ["replyId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Notes_quoteId_Notes_id_fk": { + "name": "Notes_quoteId_Notes_id_fk", + "tableFrom": "Notes", + "tableTo": "Notes", + "columnsFrom": ["quoteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Notes_clientId_Clients_client_id_fk": { + "name": "Notes_clientId_Clients_client_id_fk", + "tableFrom": "Notes", + "tableTo": "Clients", + "columnsFrom": ["clientId"], + "columnsTo": ["client_id"], + "onDelete": "set null", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Notifications": { + "name": "Notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "notifiedId": { + "name": "notifiedId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "accountId": { + "name": "accountId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "noteId": { + "name": "noteId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "dismissed": { + "name": "dismissed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "Notifications_notifiedId_Users_id_fk": { + "name": "Notifications_notifiedId_Users_id_fk", + "tableFrom": "Notifications", + "tableTo": "Users", + "columnsFrom": ["notifiedId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Notifications_accountId_Users_id_fk": { + "name": "Notifications_accountId_Users_id_fk", + "tableFrom": "Notifications", + "tableTo": "Users", + "columnsFrom": ["accountId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Notifications_noteId_Notes_id_fk": { + "name": "Notifications_noteId_Notes_id_fk", + "tableFrom": "Notifications", + "tableTo": "Notes", + "columnsFrom": ["noteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.OpenIdAccounts": { + "name": "OpenIdAccounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "server_id": { + "name": "server_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "issuer_id": { + "name": "issuer_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "OpenIdAccounts_userId_Users_id_fk": { + "name": "OpenIdAccounts_userId_Users_id_fk", + "tableFrom": "OpenIdAccounts", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.OpenIdLoginFlows": { + "name": "OpenIdLoginFlows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "code_verifier": { + "name": "code_verifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_state": { + "name": "client_state", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_redirect_uri": { + "name": "client_redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_scopes": { + "name": "client_scopes", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "clientId": { + "name": "clientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "issuer_id": { + "name": "issuer_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "OpenIdLoginFlows_clientId_Clients_client_id_fk": { + "name": "OpenIdLoginFlows_clientId_Clients_client_id_fk", + "tableFrom": "OpenIdLoginFlows", + "tableTo": "Clients", + "columnsFrom": ["clientId"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.PushSubscriptions": { + "name": "PushSubscriptions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auth_secret": { + "name": "auth_secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "alerts": { + "name": "alerts", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "policy": { + "name": "policy", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "tokenId": { + "name": "tokenId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "PushSubscriptions_tokenId_Tokens_id_fk": { + "name": "PushSubscriptions_tokenId_Tokens_id_fk", + "tableFrom": "PushSubscriptions", + "tableTo": "Tokens", + "columnsFrom": ["tokenId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "PushSubscriptions_tokenId_unique": { + "name": "PushSubscriptions_tokenId_unique", + "nullsNotDistinct": false, + "columns": ["tokenId"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Reaction": { + "name": "Reaction", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "uri": { + "name": "uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "remote_id": { + "name": "remote_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "emojiId": { + "name": "emojiId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "emoji_text": { + "name": "emoji_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "noteId": { + "name": "noteId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "authorId": { + "name": "authorId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "Reaction_emojiId_Emojis_id_fk": { + "name": "Reaction_emojiId_Emojis_id_fk", + "tableFrom": "Reaction", + "tableTo": "Emojis", + "columnsFrom": ["emojiId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Reaction_noteId_Notes_id_fk": { + "name": "Reaction_noteId_Notes_id_fk", + "tableFrom": "Reaction", + "tableTo": "Notes", + "columnsFrom": ["noteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Reaction_authorId_Users_id_fk": { + "name": "Reaction_authorId_Users_id_fk", + "tableFrom": "Reaction", + "tableTo": "Users", + "columnsFrom": ["authorId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "Reaction_uri_unique": { + "name": "Reaction_uri_unique", + "nullsNotDistinct": false, + "columns": ["uri"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Relationships": { + "name": "Relationships", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "ownerId": { + "name": "ownerId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "subjectId": { + "name": "subjectId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "following": { + "name": "following", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "showing_reblogs": { + "name": "showing_reblogs", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "notifying": { + "name": "notifying", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "blocking": { + "name": "blocking", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "muting": { + "name": "muting", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "muting_notifications": { + "name": "muting_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "requested": { + "name": "requested", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "domain_blocking": { + "name": "domain_blocking", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "endorsed": { + "name": "endorsed", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "languages": { + "name": "languages", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "Relationships_ownerId_Users_id_fk": { + "name": "Relationships_ownerId_Users_id_fk", + "tableFrom": "Relationships", + "tableTo": "Users", + "columnsFrom": ["ownerId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Relationships_subjectId_Users_id_fk": { + "name": "Relationships_subjectId_Users_id_fk", + "tableFrom": "Relationships", + "tableTo": "Users", + "columnsFrom": ["subjectId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.RoleToUsers": { + "name": "RoleToUsers", + "schema": "", + "columns": { + "roleId": { + "name": "roleId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "RoleToUsers_roleId_Roles_id_fk": { + "name": "RoleToUsers_roleId_Roles_id_fk", + "tableFrom": "RoleToUsers", + "tableTo": "Roles", + "columnsFrom": ["roleId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "RoleToUsers_userId_Users_id_fk": { + "name": "RoleToUsers_userId_Users_id_fk", + "tableFrom": "RoleToUsers", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Roles": { + "name": "Roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permissions": { + "name": "permissions", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "visible": { + "name": "visible", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Tokens": { + "name": "Tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "clientId": { + "name": "clientId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "Tokens_userId_Users_id_fk": { + "name": "Tokens_userId_Users_id_fk", + "tableFrom": "Tokens", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Tokens_clientId_Clients_client_id_fk": { + "name": "Tokens_clientId_Clients_client_id_fk", + "tableFrom": "Tokens", + "tableTo": "Clients", + "columnsFrom": ["clientId"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.UserToPinnedNotes": { + "name": "UserToPinnedNotes", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "noteId": { + "name": "noteId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "UserToPinnedNotes_userId_noteId_index": { + "name": "UserToPinnedNotes_userId_noteId_index", + "columns": [ + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "noteId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "UserToPinnedNotes_noteId_index": { + "name": "UserToPinnedNotes_noteId_index", + "columns": [ + { + "expression": "noteId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "UserToPinnedNotes_userId_Users_id_fk": { + "name": "UserToPinnedNotes_userId_Users_id_fk", + "tableFrom": "UserToPinnedNotes", + "tableTo": "Users", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "UserToPinnedNotes_noteId_Notes_id_fk": { + "name": "UserToPinnedNotes_noteId_Notes_id_fk", + "tableFrom": "UserToPinnedNotes", + "tableTo": "Notes", + "columnsFrom": ["noteId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Users": { + "name": "Users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "remote_id": { + "name": "remote_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "is_admin": { + "name": "is_admin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "email_verification_token": { + "name": "email_verification_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password_reset_token": { + "name": "password_reset_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "fields": { + "name": "fields", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "source": { + "name": "source", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "avatarId": { + "name": "avatarId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "headerId": { + "name": "headerId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "follower_count": { + "name": "follower_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "following_count": { + "name": "following_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status_count": { + "name": "status_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_bot": { + "name": "is_bot", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_locked": { + "name": "is_locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_discoverable": { + "name": "is_discoverable", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_hiding_collections": { + "name": "is_hiding_collections", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_indexable": { + "name": "is_indexable", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "sanctions": { + "name": "sanctions", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "instanceId": { + "name": "instanceId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "disable_automoderation": { + "name": "disable_automoderation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "Users_username_index": { + "name": "Users_username_index", + "columns": [ + { + "expression": "username", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "Users_email_index": { + "name": "Users_email_index", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "Users_avatarId_Medias_id_fk": { + "name": "Users_avatarId_Medias_id_fk", + "tableFrom": "Users", + "tableTo": "Medias", + "columnsFrom": ["avatarId"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "cascade" + }, + "Users_headerId_Medias_id_fk": { + "name": "Users_headerId_Medias_id_fk", + "tableFrom": "Users", + "tableTo": "Medias", + "columnsFrom": ["headerId"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "cascade" + }, + "Users_instanceId_Instances_id_fk": { + "name": "Users_instanceId_Instances_id_fk", + "tableFrom": "Users", + "tableTo": "Instances", + "columnsFrom": ["instanceId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/packages/kit/tables/migrations/meta/_journal.json b/packages/kit/tables/migrations/meta/_journal.json index c59d2e59..4575a640 100644 --- a/packages/kit/tables/migrations/meta/_journal.json +++ b/packages/kit/tables/migrations/meta/_journal.json @@ -379,6 +379,13 @@ "when": 1765422160004, "tag": "0053_lively_hellfire_club", "breakpoints": true + }, + { + "idx": 54, + "version": "7", + "when": 1771983340896, + "tag": "0054_good_madelyne_pryor", + "breakpoints": true } ] } diff --git a/patches/bun-bagel@1.2.0.patch b/patches/bun-bagel@1.2.0.patch new file mode 100644 index 00000000..fd4c1ce6 --- /dev/null +++ b/patches/bun-bagel@1.2.0.patch @@ -0,0 +1,11 @@ +diff --git a/dist/index.js b/dist/index.js +index 801380e3811704fc199b80f884ec3ff87d5116f1..381de429cae24d254609c097dad8b52d8865c2cb 100644 +--- a/dist/index.js ++++ b/dist/index.js +@@ -1,5 +1,5 @@ + // @bun +-var $={method:"GET",data:null,headers:new Headers,response:{data:null,headers:new Headers,status:200}};function Q(z){let X=`${z.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,"[\\s\\S]*")}$`;return new RegExp(X)}var f=(z)=>(W)=>{let[J,X]=z,[V,Y]=W;if(!(J.toString()===V.toString()||J.match(V)))return!1;let x=X?.method||"GET",H=Y?.method||"GET";if(x.toLowerCase()!==H.toLowerCase())return!1;let G=new Headers(X?.headers),b=new Headers(Y?.headers),K=[...G.keys(),...b.keys()];for(let y of K){let N=G.get(y),g=b.get(y);if(N!==g)return!1}return!0},v=(z,W=$)=>{let{headers:J,data:X,response:V}=W,Y=V?.data??X,w=V?.headers??J,x=Y instanceof Blob||Y instanceof FormData?Y:new Blob([JSON.stringify(Y)]);return new Response(x,{headers:w,status:z})};var Z,P=!1,j=new Map,m=(z,W=$)=>{let J=z instanceof Request?z.url:z,X=J instanceof RegExp?J:new RegExp(Q(J.toString())),V=[...j.entries()].find(f([X.toString(),W]));if(process.env.VERBOSE){if(!V)console.debug("\x1B[1mRegistered mocked request\x1B[0m");else console.debug("\x1B[1mRequest already mocked\x1B[0m \x1B[2mupdated\x1B[0m");console.debug("\x1B[2mURL\x1B[0m",J),console.debug("\x1B[2mPath Pattern\x1B[0m",X),console.debug("\x1B[2mStatus\x1B[0m",W.response?.status||200),console.debug("\x1B[2mMethod\x1B[0m",W.method||"GET"),console.debug(` ++var $={method:"GET",data:null,headers:new Headers,response:{data:null,headers:new Headers,status:200}};function Q(z){let X=`${z.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,"[\\s\\S]*")}$`;return new RegExp(X)}var f=(z)=>(W)=>{let[J,X]=z,[V,Y]=W;if(!(J.toString()===V.toString()||J.match(V)))return!1;let x=X?.method||"GET",H=Y?.method||"GET";if(x.toLowerCase()!==H.toLowerCase())return!1;let G=new Headers(X?.headers),b=new Headers(Y?.headers),K=[...G.keys(),...b.keys()];for(let y of K){let N=G.get(y),g=b.get(y);if(g&&N!==g)return!1}return!0},v=(z,W=$)=>{let{headers:J,data:X,response:V}=W,Y=V?.data??X,w=V?.headers??J,x=Y instanceof Blob||Y instanceof FormData?Y:new Blob([JSON.stringify(Y)]);return new Response(x,{headers:w,status:z})};var Z,P=!1,j=new Map,m=(z,W=$)=>{let J=z instanceof Request?z.url:z,X=J instanceof RegExp?J:new RegExp(Q(J.toString())),V=[...j.entries()].find(f([X.toString(),W]));if(process.env.VERBOSE){if(!V)console.debug("\x1B[1mRegistered mocked request\x1B[0m");else console.debug("\x1B[1mRequest already mocked\x1B[0m \x1B[2mupdated\x1B[0m");console.debug("\x1B[2mURL\x1B[0m",J),console.debug("\x1B[2mPath Pattern\x1B[0m",X),console.debug("\x1B[2mStatus\x1B[0m",W.response?.status||200),console.debug("\x1B[2mMethod\x1B[0m",W.method||"GET"),console.debug(` + `)}if(!V)j.set(X,W);else return;if(!Z)Z=globalThis.fetch,globalThis.fetch=F;return!0},h=()=>{if(j.clear(),Z)globalThis.fetch=Z.bind({}),Z=void 0},F=async(z,W)=>{let J=z instanceof Request?z.url:z.toString(),X=z instanceof Request?z:new Request(J),V=[...j.entries()].find(f([J,W]));if(!V){if(P)return Promise.reject(v(404));return await Z(X,W)}if(process.env.VERBOSE)console.debug("\x1B[2mMocked fetch called\x1B[0m",J);if(V[1].throw)throw V[1].throw;let Y=V[1].response?.status||200;return v(Y,V[1])},I=()=>{P=!1},O=()=>{P=!0};export{m as mock,I as enableRealRequests,O as disableRealRequests,h as clearMocks}; + + //# debugId=6C205C9DF1DC0DBE64756E2164756E21 diff --git a/utils/bull-board.ts b/utils/bull-board.ts index aaf950fe..14254ccc 100644 --- a/utils/bull-board.ts +++ b/utils/bull-board.ts @@ -57,7 +57,12 @@ export const applyToHono = (app: Hono): void => { throw new ApiError(401, "Missing JWT cookie"); } - const result = await verify(jwtCookie, config.authentication.key); + const result = await verify(jwtCookie, config.authentication.key, { + alg: "HS256", + iss: config.http.base_url.toString(), + }).catch(() => { + throw new ApiError(401, "Invalid JWT"); + }); const { sub } = result; From db7b1f60b44c4ccc25452eebf9b25d4b98640c15 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 31 Mar 2026 04:16:26 +0200 Subject: [PATCH 3/3] fix(packages/sdk): Fix broken JSR build --- packages/sdk/jsr.jsonc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk/jsr.jsonc b/packages/sdk/jsr.jsonc index 2f401862..d4c436e2 100644 --- a/packages/sdk/jsr.jsonc +++ b/packages/sdk/jsr.jsonc @@ -7,7 +7,7 @@ ".": "./inbox-processor.ts", "./http": "./http.ts", "./crypto": "./crypto.ts", - "./entities": "./entities.ts", - "./schemas": "./schemas.ts" + "./entities": "./entities/index.ts", + "./schemas": "./schemas/index.ts" } }