mirror of
https://github.com/versia-pub/server.git
synced 2026-03-13 05:49:16 +01:00
refactor: ⬆️ Upgrade to Zod v4 and hono-openapi 0.5.0
This commit is contained in:
parent
add2429606
commit
24d4150da4
209 changed files with 1331 additions and 1622 deletions
|
|
@ -1,8 +1,8 @@
|
|||
import type { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import type { JSONObject } from "hono/utils/types";
|
||||
import type { DescribeRouteOptions } from "hono-openapi";
|
||||
import { resolver } from "hono-openapi/zod";
|
||||
import { z } from "zod";
|
||||
import { resolver } from "hono-openapi";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
/**
|
||||
* API Error
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { Hook } from "@hono/zod-validator";
|
||||
import type { Hook } from "@hono/standard-validator";
|
||||
import type { RolePermission } from "@versia/client/schemas";
|
||||
import { config } from "@versia-server/config";
|
||||
import { serverLogger } from "@versia-server/logging";
|
||||
|
|
@ -8,9 +8,9 @@ import { eq, type SQL } from "drizzle-orm";
|
|||
import type { Context, Hono, MiddlewareHandler, ValidationTargets } from "hono";
|
||||
import { every } from "hono/combine";
|
||||
import { createMiddleware } from "hono/factory";
|
||||
import { validator } from "hono-openapi/zod";
|
||||
import { validator } from "hono-openapi";
|
||||
import { type ParsedQs, parse } from "qs";
|
||||
import { type ZodAny, type ZodError, z } from "zod";
|
||||
import { type ZodAny, ZodError, z } from "zod/v4";
|
||||
import { fromZodError } from "zod-validation-error";
|
||||
import type { AuthData, HonoEnv } from "~/types/api";
|
||||
import { ApiError } from "./api-error.ts";
|
||||
|
|
@ -31,9 +31,11 @@ export const handleZodError: Hook<
|
|||
keyof ValidationTargets
|
||||
> = (result, context): Response | undefined => {
|
||||
if (!result.success) {
|
||||
const issues = result.error as z.core.$ZodIssue[];
|
||||
|
||||
return context.json(
|
||||
{
|
||||
error: fromZodError(result.error as ZodError).message,
|
||||
error: fromZodError(new ZodError(issues)).message,
|
||||
},
|
||||
422,
|
||||
);
|
||||
|
|
@ -204,7 +206,7 @@ type WithIdParam = {
|
|||
* @returns MiddlewareHandler
|
||||
*/
|
||||
export const withNoteParam = every(
|
||||
validator("param", z.object({ id: z.string().uuid() }), handleZodError),
|
||||
validator("param", z.object({ id: z.uuid() }), handleZodError),
|
||||
createMiddleware<
|
||||
HonoEnv & {
|
||||
Variables: {
|
||||
|
|
@ -242,7 +244,7 @@ export const withNoteParam = every(
|
|||
* @returns MiddlewareHandler
|
||||
*/
|
||||
export const withUserParam = every(
|
||||
validator("param", z.object({ id: z.string().uuid() }), handleZodError),
|
||||
validator("param", z.object({ id: z.uuid() }), handleZodError),
|
||||
createMiddleware<
|
||||
HonoEnv & {
|
||||
Variables: {
|
||||
|
|
@ -278,7 +280,7 @@ export const withUserParam = every(
|
|||
* @returns
|
||||
*/
|
||||
export const withEmojiParam = every(
|
||||
validator("param", z.object({ id: z.string().uuid() }), handleZodError),
|
||||
validator("param", z.object({ id: z.uuid() }), handleZodError),
|
||||
createMiddleware<
|
||||
HonoEnv & {
|
||||
Variables: {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import { db } from "../tables/db.ts";
|
||||
import { Applications } from "../tables/schema.ts";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import {
|
|||
isNull,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import { db } from "../tables/db.ts";
|
||||
import { Emojis, type Instances, type Medias } from "../tables/schema.ts";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
|
@ -194,7 +194,7 @@ export class Emoji extends BaseInterface<typeof Emojis, EmojiType> {
|
|||
global: this.data.ownerId === null,
|
||||
description:
|
||||
this.media.data.content[this.media.getPreferredMimeType()]
|
||||
.description ?? null,
|
||||
?.description ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import {
|
|||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import sharp from "sharp";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import { mimeLookup } from "@/content_types.ts";
|
||||
import { getMediaHash } from "../../../classes/media/media-hasher.ts";
|
||||
import { ApiError } from "../api-error.ts";
|
||||
|
|
@ -297,7 +297,7 @@ export class Media extends BaseInterface<typeof Medias> {
|
|||
const content = await Media.fileToContentFormat(file, url, {
|
||||
description:
|
||||
this.data.content[Object.keys(this.data.content)[0]]
|
||||
.description || undefined,
|
||||
?.description || undefined,
|
||||
});
|
||||
|
||||
await this.update({
|
||||
|
|
@ -319,7 +319,7 @@ export class Media extends BaseInterface<typeof Medias> {
|
|||
remote: true,
|
||||
description:
|
||||
this.data.content[Object.keys(this.data.content)[0]]
|
||||
.description || undefined,
|
||||
?.description || undefined,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -363,7 +363,7 @@ export class Media extends BaseInterface<typeof Medias> {
|
|||
content[type] = {
|
||||
...content[type],
|
||||
...metadata,
|
||||
};
|
||||
} as (typeof content)[keyof typeof content];
|
||||
}
|
||||
|
||||
await this.update({
|
||||
|
|
@ -490,6 +490,14 @@ export class Media extends BaseInterface<typeof Medias> {
|
|||
public toApiMeta(): z.infer<typeof AttachmentSchema.shape.meta> {
|
||||
const type = this.getPreferredMimeType();
|
||||
const data = this.data.content[type];
|
||||
|
||||
if (!data) {
|
||||
throw new ApiError(
|
||||
500,
|
||||
`No content for type ${type} in attachment ${this.id}`,
|
||||
);
|
||||
}
|
||||
|
||||
const size =
|
||||
data.width && data.height
|
||||
? `${data.width}x${data.height}`
|
||||
|
|
@ -533,7 +541,7 @@ export class Media extends BaseInterface<typeof Medias> {
|
|||
? new ProxiableUrl(thumbnailData.content).proxied
|
||||
: null,
|
||||
meta: this.toApiMeta(),
|
||||
description: data.description || null,
|
||||
description: data?.description || null,
|
||||
blurhash: this.data.blurhash,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
} from "drizzle-orm";
|
||||
import { htmlToText } from "html-to-text";
|
||||
import { createRegExp, exactly, global } from "magic-regexp";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import { mergeAndDeduplicate } from "@/lib.ts";
|
||||
import { sanitizedHtmlStrip } from "@/sanitization";
|
||||
import { versiaTextToHtml } from "../parsers.ts";
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import { db } from "../tables/db.ts";
|
||||
import { Notifications } from "../tables/schema.ts";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
|
@ -189,6 +189,7 @@ export class Notification extends BaseInterface<
|
|||
created_at: new Date(this.data.createdAt).toISOString(),
|
||||
id: this.data.id,
|
||||
type: this.data.type,
|
||||
event: undefined,
|
||||
status: this.data.status
|
||||
? await new Note(this.data.status).toApi(account)
|
||||
: undefined,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import { db } from "../tables/db.ts";
|
||||
import { PushSubscriptions, Tokens } from "../tables/schema.ts";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
type SQL,
|
||||
sql,
|
||||
} from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
import { db } from "../tables/db.ts";
|
||||
import { Relationships, Users } from "../tables/schema.ts";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import { db } from "../tables/db.ts";
|
||||
import { Roles, RoleToUsers } from "../tables/schema.ts";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import { db } from "../tables/db.ts";
|
||||
import { Tokens } from "../tables/schema.ts";
|
||||
import type { Application } from "./application.ts";
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import {
|
|||
sql,
|
||||
} from "drizzle-orm";
|
||||
import { htmlToText } from "html-to-text";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import { getBestContentType } from "@/content_types";
|
||||
import { randomString } from "@/math";
|
||||
import type { HttpVerb, KnownEntity } from "~/types/api.ts";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
import { Hooks } from "./hooks.ts";
|
||||
import { Plugin } from "./plugin.ts";
|
||||
|
||||
|
|
|
|||
|
|
@ -245,7 +245,8 @@ export class InboxProcessor {
|
|||
// If note has a blocked word
|
||||
if (
|
||||
Object.values(note.content?.data ?? {})
|
||||
.flatMap((c) => c.content)
|
||||
.flatMap((c) => c?.content)
|
||||
.filter((content) => content !== undefined)
|
||||
.some((content) =>
|
||||
config.validation.filters.note_content.some((filter) =>
|
||||
filter.test(content),
|
||||
|
|
@ -281,7 +282,8 @@ export class InboxProcessor {
|
|||
|
||||
if (
|
||||
Object.values(user.bio?.data ?? {})
|
||||
.flatMap((c) => c.content)
|
||||
.flatMap((c) => c?.content)
|
||||
.filter((content) => content !== undefined)
|
||||
.some((content) =>
|
||||
config.validation.filters.bio.some((filter) =>
|
||||
filter.test(content),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { zodToJsonSchema } from "zod-to-json-schema";
|
||||
import * as z from "zod/v4";
|
||||
import { manifestSchema } from "./schema.ts";
|
||||
|
||||
const jsonSchema = zodToJsonSchema(manifestSchema);
|
||||
const jsonSchema = z.toJSONSchema(manifestSchema);
|
||||
|
||||
console.write(`${JSON.stringify(jsonSchema, null, 4)}\n`);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@
|
|||
"hono": "catalog:",
|
||||
"mitt": "catalog:",
|
||||
"zod": "catalog:",
|
||||
"zod-to-json-schema": "catalog:",
|
||||
"zod-validation-error": "catalog:",
|
||||
"chalk": "catalog:",
|
||||
"@versia/client": "workspace:*",
|
||||
|
|
@ -52,7 +51,7 @@
|
|||
"altcha-lib": "catalog:",
|
||||
"hono-openapi": "catalog:",
|
||||
"qs": "catalog:",
|
||||
"@hono/zod-validator": "catalog:",
|
||||
"@hono/standard-validator": "catalog:",
|
||||
"ioredis": "catalog:",
|
||||
"linkify-html": "catalog:",
|
||||
"markdown-it": "catalog:",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Hono, MiddlewareHandler } from "hono";
|
||||
import { createMiddleware } from "hono/factory";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import { fromZodError, type ZodError } from "zod-validation-error";
|
||||
import type { HonoEnv } from "~/types/api";
|
||||
import type { ServerHooks } from "./hooks.ts";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const manifestSchema = z.object({
|
||||
// biome-ignore lint/style/useNamingConvention: JSON schema requires this to be $schema
|
||||
|
|
@ -15,8 +15,8 @@ export const manifestSchema = z.object({
|
|||
.array(
|
||||
z.object({
|
||||
name: z.string().min(1).max(100),
|
||||
email: z.string().email().optional(),
|
||||
url: z.string().url().optional(),
|
||||
email: z.email().optional(),
|
||||
url: z.url().optional(),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
|
|
@ -47,7 +47,7 @@ export const manifestSchema = z.object({
|
|||
"other",
|
||||
])
|
||||
.optional(),
|
||||
url: z.string().url().optional(),
|
||||
url: z.url().optional(),
|
||||
})
|
||||
.optional(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import {
|
|||
uniqueIndex,
|
||||
uuid,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
const createdAt = () =>
|
||||
timestamp("created_at", { precision: 3, mode: "string" })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue