diff --git a/package.json b/package.json index 4540a8e..0f4e866 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,8 @@ }, "dependencies": { "@hono/swagger-ui": "^0.5.1", - "@hono/zod-openapi": "^0.19.5", - "@hono/zod-validator": "^0.2.2", + "@hono/zod-openapi": "^1.1.6", + "@hono/zod-validator": "^0.7.6", "drizzle-orm": "^0.44.7", "gql.tada": "^1.8.10", "graphql": "^16.12.0", @@ -27,7 +27,7 @@ "jose": "^5.10.0", "lodash.mapkeys": "^4.6.0", "luxon": "^3.6.1", - "zod": "^3.24.3" + "zod": "^4.2.1" }, "devDependencies": { "@cloudflare/vitest-pool-workers": "^0.10.15", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6767999..cad53ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,11 +11,11 @@ importers: specifier: ^0.5.1 version: 0.5.2(hono@4.10.8) "@hono/zod-openapi": - specifier: ^0.19.5 - version: 0.19.10(hono@4.10.8)(zod@3.25.76) + specifier: ^1.1.6 + version: 1.1.6(hono@4.10.8)(zod@4.2.1) "@hono/zod-validator": - specifier: ^0.2.2 - version: 0.2.2(hono@4.10.8)(zod@3.25.76) + specifier: ^0.7.6 + version: 0.7.6(hono@4.10.8)(zod@4.2.1) drizzle-orm: specifier: ^0.44.7 version: 0.44.7 @@ -41,8 +41,8 @@ importers: specifier: ^3.6.1 version: 3.7.2 zod: - specifier: ^3.24.3 - version: 3.25.76 + specifier: ^4.2.1 + version: 4.2.1 devDependencies: "@cloudflare/vitest-pool-workers": specifier: ^0.10.15 @@ -138,13 +138,13 @@ packages: graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 typescript: ^5.0.0 - "@asteasolutions/zod-to-openapi@7.3.4": + "@asteasolutions/zod-to-openapi@8.2.0": resolution: { - integrity: sha512-/2rThQ5zPi9OzVwes6U7lK1+Yvug0iXu25olp7S0XsYmOqnyMfxH7gdSQjn/+DSOHRg7wnotwGJSyL+fBKdnEA==, + integrity: sha512-u05zNUirlukJAf9oEHmxSF31L1XQhz9XdpVILt7+xhrz65oQqBpiOWFkGvRWL0IpjOUJ878idKoNmYPxrFnkeg==, } peerDependencies: - zod: ^3.20.2 + zod: ^4.0.0 "@babel/code-frame@7.27.1": resolution: @@ -1411,29 +1411,20 @@ packages: peerDependencies: hono: "*" - "@hono/zod-openapi@0.19.10": + "@hono/zod-openapi@1.1.6": resolution: { - integrity: sha512-dpoS6DenvoJyvxtQ7Kd633FRZ/Qf74+4+o9s+zZI8pEqnbjdF/DtxIib08WDpCaWabMEJOL5TXpMgNEZvb7hpA==, + integrity: sha512-wEdG1MlCWAnngRVPKZJ/dv5P/b5UL3di/+SLX0Cuuc8hJ6Gf8L3vDMXcXywSYAwxK8iiatF7HoTxJ96gtckLpQ==, } engines: { node: ">=16.0.0" } peerDependencies: hono: ">=4.3.6" - zod: ">=3.0.0" + zod: ^4.0.0 - "@hono/zod-validator@0.2.2": + "@hono/zod-validator@0.7.6": resolution: { - integrity: sha512-dSDxaPV70Py8wuIU2QNpoVEIOSzSXZ/6/B/h4xA7eOMz7+AarKTSGV8E6QwrdcCbBLkpqfJ4Q2TmBO0eP1tCBQ==, - } - peerDependencies: - hono: ">=3.9.0" - zod: ^3.19.1 - - "@hono/zod-validator@0.7.5": - resolution: - { - integrity: sha512-n4l4hutkfYU07PzRUHBOVzUEn38VSfrh+UVE5d0w4lyfWDOEhzxIupqo5iakRiJL44c3vTuFJBvcmUl8b9agIA==, + integrity: sha512-Io1B6d011Gj1KknV4rXYz4le5+5EubcWEU/speUjuw9XMMIaP3n78yXLhjd2A3PXaXaUwEAluOiAyLqhBEJgsw==, } peerDependencies: hono: ">=3.9.0" @@ -4137,6 +4128,12 @@ packages: integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==, } + zod@4.2.1: + resolution: + { + integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==, + } + zx@8.1.5: resolution: { @@ -4156,10 +4153,10 @@ snapshots: graphql: 16.12.0 typescript: 5.9.3 - "@asteasolutions/zod-to-openapi@7.3.4(zod@3.25.76)": + "@asteasolutions/zod-to-openapi@8.2.0(zod@4.2.1)": dependencies: openapi3-ts: 4.5.0 - zod: 3.25.76 + zod: 4.2.1 "@babel/code-frame@7.27.1": dependencies: @@ -4705,23 +4702,18 @@ snapshots: dependencies: hono: 4.10.8 - "@hono/zod-openapi@0.19.10(hono@4.10.8)(zod@3.25.76)": + "@hono/zod-openapi@1.1.6(hono@4.10.8)(zod@4.2.1)": dependencies: - "@asteasolutions/zod-to-openapi": 7.3.4(zod@3.25.76) - "@hono/zod-validator": 0.7.5(hono@4.10.8)(zod@3.25.76) + "@asteasolutions/zod-to-openapi": 8.2.0(zod@4.2.1) + "@hono/zod-validator": 0.7.6(hono@4.10.8)(zod@4.2.1) hono: 4.10.8 openapi3-ts: 4.5.0 - zod: 3.25.76 + zod: 4.2.1 - "@hono/zod-validator@0.2.2(hono@4.10.8)(zod@3.25.76)": + "@hono/zod-validator@0.7.6(hono@4.10.8)(zod@4.2.1)": dependencies: hono: 4.10.8 - zod: 3.25.76 - - "@hono/zod-validator@0.7.5(hono@4.10.8)(zod@3.25.76)": - dependencies: - hono: 4.10.8 - zod: 3.25.76 + zod: 4.2.1 "@img/sharp-darwin-arm64@0.33.5": optionalDependencies: @@ -6301,6 +6293,8 @@ snapshots: zod@3.25.76: {} + zod@4.2.1: {} + zx@8.1.5: optionalDependencies: "@types/fs-extra": 11.0.4 diff --git a/src/controllers/auth/anilist/index.ts b/src/controllers/auth/anilist/index.ts index c8f0ec6..02e82cc 100644 --- a/src/controllers/auth/anilist/index.ts +++ b/src/controllers/auth/anilist/index.ts @@ -20,8 +20,8 @@ const UserSchema = z.object({ }), statistics: z.object({ minutesWatched: z.number().openapi({ type: "integer", format: "int64" }), - episodesWatched: z.number().int(), - count: z.number().int(), + episodesWatched: z.int(), + count: z.int(), meanScore: z.number().openapi({ type: "number", format: "float" }), }), }); diff --git a/src/controllers/popular/browse/index.ts b/src/controllers/popular/browse/index.ts index 56f8684..816c81e 100644 --- a/src/controllers/popular/browse/index.ts +++ b/src/controllers/popular/browse/index.ts @@ -23,8 +23,8 @@ const route = createRoute({ path: "/", request: { query: z.object({ - limit: z - .number({ coerce: true }) + limit: z.coerce + .number() .int() .default(10) .describe("The number of titles to return"), diff --git a/src/controllers/popular/category/index.ts b/src/controllers/popular/category/index.ts index b8b449a..daaf6a5 100644 --- a/src/controllers/popular/category/index.ts +++ b/src/controllers/popular/category/index.ts @@ -22,12 +22,12 @@ const route = createRoute({ path: "/{category}", request: { query: z.object({ - limit: z - .number({ coerce: true }) + limit: z.coerce + .number() .int() - .default(10) + .prefault(10) .describe("The number of titles to return"), - page: z.number({ coerce: true }).int().min(1).default(1), + page: z.coerce.number().int().min(1).prefault(1), }), params: z.object({ category: PopularCategory }), }, diff --git a/src/controllers/search/index.ts b/src/controllers/search/index.ts index 8a53634..e7c6e78 100644 --- a/src/controllers/search/index.ts +++ b/src/controllers/search/index.ts @@ -17,8 +17,8 @@ const route = createRoute({ request: { query: z.object({ query: z.string(), - page: z.number({ coerce: true }).int().min(1).default(1), - limit: z.number({ coerce: true }).int().default(10), + page: z.coerce.number().int().min(1).prefault(1), + limit: z.coerce.number().int().prefault(10), }), }, responses: { diff --git a/src/libs/anilist/anilist-do.ts b/src/libs/anilist/anilist-do.ts index 32aee3a..28cb796 100644 --- a/src/libs/anilist/anilist-do.ts +++ b/src/libs/anilist/anilist-do.ts @@ -24,9 +24,9 @@ import type { Title } from "~/types/title"; const nextAiringEpisodeSchema = z.nullable( z.object({ - episode: z.number().int(), - airingAt: z.number().int(), - timeUntilAiring: z.number().int(), + episode: z.int(), + airingAt: z.int(), + timeUntilAiring: z.int(), }), ); diff --git a/src/types/episode/fetch-url-response.ts b/src/types/episode/fetch-url-response.ts index b15d336..c046f4b 100644 --- a/src/types/episode/fetch-url-response.ts +++ b/src/types/episode/fetch-url-response.ts @@ -9,7 +9,7 @@ export const FetchUrlResponseSchema = z.object({ audio: z.array(z.object({ url: z.string(), lang: z.string() })), intro: SkippableSchema, outro: SkippableSchema, - headers: z.record(z.string()).optional(), + headers: z.record(z.string(), z.string()).optional(), }); export type FetchUrlResponse = z.infer & { diff --git a/src/types/episode/index.ts b/src/types/episode/index.ts index 7c1c6c2..255fb13 100644 --- a/src/types/episode/index.ts +++ b/src/types/episode/index.ts @@ -9,8 +9,8 @@ export const Episode = z.object({ title: z.string().nullish(), img: z.string().nullish(), description: z.string().nullish(), - rating: z.number().int().nullish(), - updatedAt: z.number().int().default(0).openapi({ format: "int64" }), + rating: z.int().nullish(), + updatedAt: z.int().prefault(0).openapi({ format: "int64" }), }); export type EpisodesResponse = z.infer; diff --git a/src/types/schema.ts b/src/types/schema.ts index 90eed54..93e53c4 100644 --- a/src/types/schema.ts +++ b/src/types/schema.ts @@ -24,9 +24,9 @@ export const ErrorResponseSchema = z.object({ success: z.literal(false).openapi({ type: "boolean" }), }); -export const NullableNumberSchema = z.number().int().nullable(); +export const NullableNumberSchema = z.int().nullable(); -export const AniListIdSchema = z.number().int().openapi({ format: "int64" }); +export const AniListIdSchema = z.int().openapi({ format: "int64" }); export const AniListIdQuerySchema = z .string() .openapi({ type: "integer", format: "int64" }); diff --git a/src/types/title/index.ts b/src/types/title/index.ts index af6388e..200e943 100644 --- a/src/types/title/index.ts +++ b/src/types/title/index.ts @@ -8,17 +8,17 @@ export type Title = z.infer; export const Title = z.object({ nextAiringEpisode: z.nullable( z.object({ - episode: z.number().int(), - airingAt: z.number().int().openapi({ format: "int64" }), - timeUntilAiring: z.number().int().openapi({ format: "int64" }), + episode: z.int(), + airingAt: z.int().openapi({ format: "int64" }), + timeUntilAiring: z.int().openapi({ format: "int64" }), }), ), mediaListEntry: z.nullable( z.object({ status: z.nullable(WatchStatus), progress: NullableNumberSchema, - id: z.number().int(), - updatedAt: z.number().int().openapi({ format: "int64" }).optional(), + id: z.int(), + updatedAt: z.int().openapi({ format: "int64" }).optional(), }), ), countryOfOrigin: countryCodeSchema, @@ -50,5 +50,5 @@ export const Title = z.object({ }), ), idMal: NullableNumberSchema, - id: z.number().int().openapi({ format: "int64" }), + id: z.int().openapi({ format: "int64" }), }); diff --git a/src/types/user.ts b/src/types/user.ts index 9168aca..2a7cf74 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -14,7 +14,7 @@ export const UserProfile = z.object({ statistics: z.object({ minutesWatched: z.number().openapi({ type: "integer", format: "int64" }), episodesWatched: z.number().openapi({ type: "integer", format: "int64" }), - count: z.number().int(), + count: z.int(), meanScore: z.number().openapi({ type: "number", format: "float" }), }), id: z.number().openapi({ type: "integer", format: "int64" }),