fix(deps): upgrade zod to v4 and fix breaking changes (#3461)
* fix(deps): update dependency drizzle-zod to ^0.8.2 * chore: update zod to v4 import * fix: path is no longer available in transform context * fix: AnyZodObject does no longer exist * fix: auth env.ts using wrong createEnv and remove unused file env-validation.ts * fix: required_error no longer exists on z.string * fix: zod error map is deprecated and replaced with config * fix: default requires callback now * fix: migrate zod resolver for mantine * fix: remove unused form translation file * fix: wrong enum type * fix: record now requires two arguments * fix: add-confirm-password-refinement type issues * fix: add missing first record argument for entityStateSchema * fix: migrate superrefine to check * fix(deps): upgrade zod-form-data to v3 * fix: migrate superRefine to check for mediaUploadSchema * fix: authProvidersSchema default is array * fix: use stringbool instead of custom implementation * fix: record requires first argument * fix: migrate superRefine to check for certificate router * fix: confirm pasword refinement is overwriting types * fix: email optional not working * fix: migrate intersection to object converter * fix: safe parse return value rename * fix: easier access for min and max number value * fix: migrate superRefine to check for oldmarr import file * fix: inference of enum shape for old-import board-size wrong * fix: errors renamed to issues * chore: address pull request feedback * fix: zod form requires object * fix: inference for use-zod-form not working * fix: remove unnecessary convertion * fix(deps): upgrade trpc-to-openapi to v3 * fix: build error * fix: migrate missing zod imports to v4 * fix: migrate zod records to v4 * fix: missing core package dependency in api module * fix: unable to convert custom zod schema to openapi schema * fix(deps): upgrade zod to v4 * chore(renovate): enable zod dependency updates * test: add simple unit test for convertIntersectionToZodObject --------- Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
This commit is contained in:
4
.github/renovate.json5
vendored
4
.github/renovate.json5
vendored
@@ -6,10 +6,6 @@
|
||||
matchPackagePatterns: ["^@homarr/"],
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
matchPackagePatterns: ["^zod$", "^drizzle-zod$", "^zod-form-data$"],
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
matchUpdateTypes: ["minor", "patch", "pin", "digest"],
|
||||
automerge: true,
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
"superjson": "2.2.2",
|
||||
"swagger-ui-react": "^5.27.1",
|
||||
"use-deep-compare-effect": "^1.8.1",
|
||||
"zod": "^3.25.76"
|
||||
"zod": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Button, PasswordInput, Stack, TextInput } from "@mantine/core";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { Anchor, Button, Card, Code, Collapse, Divider, PasswordInput, Stack, Text, TextInput } from "@mantine/core";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { signIn } from "@homarr/auth/client";
|
||||
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { Button, Card, Stack, TextInput } from "@mantine/core";
|
||||
import { IconArrowRight } from "@tabler/icons-react";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { startTransition } from "react";
|
||||
import { Button, Card, Group, Stack, Switch, Text } from "@mantine/core";
|
||||
import { IconArrowRight } from "@tabler/icons-react";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Button, PasswordInput, Stack, TextInput } from "@mantine/core";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { signIn } from "@homarr/auth/client";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { ActionIcon, ActionIconGroup, Anchor, Avatar, Card, Group, Stack, Text, Title } from "@mantine/core";
|
||||
import { IconBox, IconPencil } from "@tabler/icons-react";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { api } from "@homarr/api/server";
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Button, Fieldset, Group, Stack, TextInput } from "@mantine/core";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
TextInput,
|
||||
} from "@mantine/core";
|
||||
import { IconInfoCircle } from "@tabler/icons-react";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { Container, Group, Stack, Title } from "@mantine/core";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { auth } from "@homarr/auth/next";
|
||||
import type { IntegrationKind } from "@homarr/definitions";
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
Tooltip,
|
||||
} from "@mantine/core";
|
||||
import { IconExternalLink } from "@tabler/icons-react";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { api } from "@homarr/api/server";
|
||||
|
||||
@@ -4,7 +4,7 @@ import Link from "next/link";
|
||||
import type { SegmentedControlItem } from "@mantine/core";
|
||||
import { Button, Fieldset, Grid, Group, SegmentedControl, Stack, Textarea, TextInput } from "@mantine/core";
|
||||
import { WidgetIntegrationSelect } from "node_modules/@homarr/widgets/src/widget-integration-select";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { searchEngineTypes } from "@homarr/definitions";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { ActionIcon, ActionIconGroup, Anchor, Avatar, Card, Group, Stack, Text, Title } from "@mantine/core";
|
||||
import { IconPencil, IconSearch } from "@tabler/icons-react";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { api } from "@homarr/api/server";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Button, Group, Stack } from "@mantine/core";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Button, Group, Select, Stack, Switch } from "@mantine/core";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Button, Group, Radio, Stack } from "@mantine/core";
|
||||
import type { DayOfWeek } from "@mantine/dates";
|
||||
import dayjs from "dayjs";
|
||||
import localeData from "dayjs/plugin/localeData";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Button, Group, Stack, Switch } from "@mantine/core";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from "@mantine/core";
|
||||
import { useListState } from "@mantine/hooks";
|
||||
import { IconPlus, IconUserCheck } from "@tabler/icons-react";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { everyoneGroup, groupPermissions } from "@homarr/definitions";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useRef } from "react";
|
||||
import { Button, Grid, Group, NumberInput, Stack } from "@mantine/core";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import type { GridStack } from "@homarr/gridstack";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Button, Group, Stack, TextInput } from "@mantine/core";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Button, Group, Stack, TextInput } from "@mantine/core";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import { createModal } from "@homarr/modals";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback } from "react";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { useUpdateBoard } from "@homarr/boards/updater";
|
||||
import type { dynamicSectionOptionsSchema } from "@homarr/validation/shared";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Button, CloseButton, ColorInput, Group, Stack, TextInput, useMantineTheme } from "@mantine/core";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import { createModal } from "@homarr/modals";
|
||||
|
||||
@@ -74,14 +74,14 @@
|
||||
"overrides": {
|
||||
"proxmox-api>undici": "7.13.0"
|
||||
},
|
||||
"patchedDependencies": {
|
||||
"@types/node-unifi": "patches/@types__node-unifi.patch"
|
||||
},
|
||||
"allowUnusedPatches": true,
|
||||
"ignoredBuiltDependencies": [
|
||||
"@scarf/scarf",
|
||||
"core-js-pure",
|
||||
"protobufjs"
|
||||
],
|
||||
"patchedDependencies": {
|
||||
"@types/node-unifi": "patches/@types__node-unifi.patch"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"@homarr/auth": "workspace:^0.1.0",
|
||||
"@homarr/certificates": "workspace:^0.1.0",
|
||||
"@homarr/common": "workspace:^0.1.0",
|
||||
"@homarr/core": "workspace:^0.1.0",
|
||||
"@homarr/cron-job-api": "workspace:^0.1.0",
|
||||
"@homarr/cron-job-status": "workspace:^0.1.0",
|
||||
"@homarr/cron-jobs": "workspace:^0.1.0",
|
||||
@@ -51,8 +52,8 @@
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"superjson": "2.2.2",
|
||||
"trpc-to-openapi": "^2.4.0",
|
||||
"zod": "^3.25.76"
|
||||
"trpc-to-openapi": "^3.0.0",
|
||||
"zod": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { createEnv } from "@t3-oss/env-nextjs";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { shouldSkipEnvValidation } from "@homarr/common/env-validation";
|
||||
import { createEnv } from "@homarr/core/infrastructure/env";
|
||||
|
||||
export const env = createEnv({
|
||||
server: {
|
||||
@@ -10,6 +9,4 @@ export const env = createEnv({
|
||||
runtimeEnv: {
|
||||
KUBERNETES_SERVICE_ACCOUNT_NAME: process.env.KUBERNETES_SERVICE_ACCOUNT_NAME,
|
||||
},
|
||||
skipValidation: shouldSkipEnvValidation(),
|
||||
emptyStringAsUndefined: true,
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import type { Session } from "@homarr/auth";
|
||||
import { hasQueryAccessToIntegrationsAsync } from "@homarr/auth/server";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { and, eq } from "@homarr/db";
|
||||
import { items } from "@homarr/db/schema";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createSaltAsync, hashPasswordAsync } from "@homarr/auth";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import { asc, eq, inArray, like } from "@homarr/db";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import superjson from "superjson";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { constructBoardPermissions } from "@homarr/auth/shared";
|
||||
import { createId } from "@homarr/common";
|
||||
@@ -1623,7 +1623,7 @@ const getFullBoardWithWhereAsync = async (db: Database, where: SQL<unknown>, use
|
||||
const forKind = <T extends WidgetKind>(kind: T) =>
|
||||
z.object({
|
||||
kind: z.literal(kind),
|
||||
options: z.record(z.unknown()),
|
||||
options: z.record(z.string(), z.unknown()),
|
||||
});
|
||||
|
||||
const outputItemSchema = zodUnionFromArray(widgetKinds.map((kind) => forKind(kind))).and(sharedItemSchema);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { X509Certificate } from "node:crypto";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { zfd } from "zod-form-data";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { addCustomRootCertificateAsync, removeCustomRootCertificateAsync } from "@homarr/certificates/server";
|
||||
import { and, eq } from "@homarr/db";
|
||||
import { trustedCertificateHostnames } from "@homarr/db/schema";
|
||||
import { logger } from "@homarr/log";
|
||||
import { certificateValidFileNameSchema, superRefineCertificateFile } from "@homarr/validation/certificates";
|
||||
import { certificateValidFileNameSchema, checkCertificateFile } from "@homarr/validation/certificates";
|
||||
|
||||
import { createTRPCRouter, permissionRequiredProcedure } from "../../trpc";
|
||||
|
||||
@@ -16,7 +16,7 @@ export const certificateRouter = createTRPCRouter({
|
||||
.requiresPermission("admin")
|
||||
.input(
|
||||
zfd.formData({
|
||||
file: zfd.file().superRefine(superRefineCertificateFile),
|
||||
file: zfd.file().check(checkCertificateFile),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import type { Container, ContainerState, Docker, Port } from "@homarr/docker";
|
||||
import { DockerSingleton } from "@homarr/docker";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import type { Database } from "@homarr/db";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { analyseOldmarrImportForRouterAsync, analyseOldmarrImportInputSchema } from "@homarr/old-import/analyse";
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import z from "zod";
|
||||
import z from "zod/v4";
|
||||
|
||||
import packageJson from "../../../../package.json";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createId, objectEntries } from "@homarr/common";
|
||||
import { decryptSecret, encryptSecret } from "@homarr/common/server";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { randomBytes } from "crypto";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import { asc, eq } from "@homarr/db";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { fetchWithTimeout } from "@homarr/common";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import z from "zod";
|
||||
import z from "zod/v4";
|
||||
|
||||
import { logger } from "@homarr/log";
|
||||
import { logLevels } from "@homarr/log/constants";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import type { InferInsertModel } from "@homarr/db";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { onboarding } from "@homarr/db/schema";
|
||||
import { onboardingSteps } from "@homarr/definitions";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import { asc, eq, like } from "@homarr/db";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { and, eq } from "@homarr/db";
|
||||
import { sectionCollapseStates, sections } from "@homarr/db/schema";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { getServerSettingByKeyAsync, getServerSettingsAsync, updateServerSettingByKeyAsync } from "@homarr/db/queries";
|
||||
import type { ServerSettings } from "@homarr/server-settings";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createSaltAsync, hashPasswordAsync } from "@homarr/auth";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import type { Session } from "@homarr/auth";
|
||||
import type { Modify } from "@homarr/common/types";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { sendPingRequestAsync } from "@homarr/ping";
|
||||
import { pingChannel, pingUrlChannel } from "@homarr/redis";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||
import { radarrReleaseTypes } from "@homarr/integrations/types";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import type { Modify } from "@homarr/common/types";
|
||||
import type { Integration } from "@homarr/db/schema";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import type { Modify } from "@homarr/common/types";
|
||||
import type { Integration } from "@homarr/db/schema";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||
import { createIntegrationAsync } from "@homarr/integrations";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||
import type { StreamSession } from "@homarr/integrations";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import type { MinecraftServerStatus } from "@homarr/request-handler/minecraft-server-status";
|
||||
import { minecraftServerStatusRequestHandler } from "@homarr/request-handler/minecraft-server-status";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import SuperJSON from "superjson";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { eq } from "@homarr/db";
|
||||
import { boards, items } from "@homarr/db/schema";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { escapeForRegEx } from "@tiptap/react";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||
import { releasesRequestHandler } from "@homarr/request-handler/releases";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { rssFeedsRequestHandler } from "@homarr/request-handler/rss-feeds";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||
import { createIntegrationAsync } from "@homarr/integrations";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { fetchStockPriceHandler } from "@homarr/request-handler/stock-price";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { fetchWithTimeout } from "@homarr/common";
|
||||
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import { z } from "zod";
|
||||
import type { AnyZodObject, ZodIntersection, ZodObject } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
import type { ZodIntersection, ZodObject } from "zod/v4";
|
||||
|
||||
export function convertIntersectionToZodObject<TIntersection extends ZodIntersection<AnyZodObject, AnyZodObject>>(
|
||||
export function convertIntersectionToZodObject<TIntersection extends ZodIntersection<ZodObject, ZodObject>>(
|
||||
intersection: TIntersection,
|
||||
) {
|
||||
const { _def } = intersection;
|
||||
const left = intersection.def.left;
|
||||
const right = intersection.def.right;
|
||||
|
||||
// Merge the shapes
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const mergedShape = { ..._def.left.shape, ..._def.right.shape };
|
||||
const mergedShape = { ...left.def.shape, ...right.def.shape };
|
||||
|
||||
// Return a new ZodObject
|
||||
return z.object(mergedShape) as unknown as TIntersection extends ZodIntersection<infer TLeft, infer TRight>
|
||||
? TLeft extends AnyZodObject
|
||||
? TRight extends AnyZodObject
|
||||
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
ZodObject<TLeft["shape"] & TRight["shape"], any, any, z.infer<TLeft> & z.infer<TRight>>
|
||||
? TLeft extends ZodObject
|
||||
? TRight extends ZodObject
|
||||
? ZodObject<TLeft["shape"] & TRight["shape"]>
|
||||
: never
|
||||
: never
|
||||
: never;
|
||||
|
||||
23
packages/api/src/test/schema-merger.spec.ts
Normal file
23
packages/api/src/test/schema-merger.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import z from "zod/v4";
|
||||
|
||||
import { convertIntersectionToZodObject } from "../schema-merger";
|
||||
|
||||
describe("convertIntersectionToZodObject should convert zod intersection to zod object", () => {
|
||||
test("should merge two ZodObjects with different properties", () => {
|
||||
const objectA = z.object({
|
||||
id: z.string(),
|
||||
});
|
||||
const objectB = z.object({
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
const intersection = objectA.and(objectB);
|
||||
|
||||
const result = convertIntersectionToZodObject(intersection);
|
||||
|
||||
expect(result.def.type).toBe("object");
|
||||
expect(result.shape).toHaveProperty("id");
|
||||
expect(result.shape).toHaveProperty("name");
|
||||
});
|
||||
});
|
||||
@@ -9,7 +9,7 @@
|
||||
import { initTRPC, TRPCError } from "@trpc/server";
|
||||
import superjson from "superjson";
|
||||
import type { OpenApiMeta } from "trpc-to-openapi";
|
||||
import { ZodError } from "zod";
|
||||
import { ZodError } from "zod/v4";
|
||||
|
||||
import type { Session } from "@homarr/auth";
|
||||
import { FlattenError } from "@homarr/common";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createBooleanSchema, createDurationSchema, createEnv } from "@homarr/core/infrastructure/env";
|
||||
import { supportedAuthProviders } from "@homarr/definitions";
|
||||
@@ -19,7 +19,7 @@ const authProvidersSchema = z
|
||||
return false;
|
||||
}),
|
||||
)
|
||||
.default("credentials");
|
||||
.default(["credentials"]);
|
||||
|
||||
const authProviders = authProvidersSchema.safeParse(process.env.AUTH_PROVIDERS).data ?? [];
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"next-auth": "5.0.0-beta.29",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"zod": "^3.25.76"
|
||||
"zod": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import bcrypt from "bcrypt";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import type { Database } from "@homarr/db";
|
||||
import { and, eq } from "@homarr/db";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CredentialsSignin } from "@auth/core/errors";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createId, extractErrorMessage } from "@homarr/common";
|
||||
import type { Database, InferInsertModel } from "@homarr/db";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { expireDateAfter, generateSessionToken } from "../session";
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export const recreateAdmin = command({
|
||||
|
||||
if (!result.success) {
|
||||
console.error("Invalid username:");
|
||||
console.error(result.error.errors.map((error) => `- ${error.message}`).join("\n"));
|
||||
console.error(result.error.issues.map((error) => `- ${error.message}`).join("\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { randomBytes } from "crypto";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createEnv } from "@homarr/core/infrastructure/env";
|
||||
|
||||
@@ -12,7 +12,7 @@ export const env = createEnv({
|
||||
server: {
|
||||
SECRET_ENCRYPTION_KEY: z
|
||||
.string({
|
||||
required_error: `SECRET_ENCRYPTION_KEY is required${errorSuffix}`,
|
||||
error: `SECRET_ENCRYPTION_KEY is required${errorSuffix}`,
|
||||
})
|
||||
.min(64, {
|
||||
message: `SECRET_ENCRYPTION_KEY has to be 64 characters${errorSuffix}`,
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
"./types": "./src/types.ts",
|
||||
"./server": "./src/server.ts",
|
||||
"./client": "./src/client.ts",
|
||||
"./env": "./env.ts",
|
||||
"./env-validation": "./src/env-validation.ts"
|
||||
"./env": "./env.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
@@ -35,7 +34,7 @@
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"undici": "7.13.0",
|
||||
"zod": "^3.25.76",
|
||||
"zod": "^4.0.14",
|
||||
"zod-validation-error": "^3.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const trueStrings = ["1", "yes", "t", "true"];
|
||||
const falseStrings = ["0", "no", "f", "false"];
|
||||
|
||||
export const createBooleanSchema = (defaultValue: boolean) =>
|
||||
z
|
||||
.string()
|
||||
.default(defaultValue.toString())
|
||||
.transform((value, ctx) => {
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (trueStrings.includes(normalized)) return true;
|
||||
if (falseStrings.includes(normalized)) return false;
|
||||
|
||||
throw new Error(`Invalid boolean value for ${ctx.path.join(".")}`);
|
||||
});
|
||||
|
||||
export const createDurationSchema = (defaultValue: `${number}${"s" | "m" | "h" | "d"}`) =>
|
||||
z
|
||||
.string()
|
||||
.regex(/^\d+[smhd]?$/)
|
||||
.default(defaultValue)
|
||||
.transform((duration) => {
|
||||
const lastChar = duration[duration.length - 1] as "s" | "m" | "h" | "d";
|
||||
if (!isNaN(Number(lastChar))) {
|
||||
return Number(defaultValue);
|
||||
}
|
||||
|
||||
const multipliers = {
|
||||
s: 1,
|
||||
m: 60,
|
||||
h: 60 * 60,
|
||||
d: 60 * 60 * 24,
|
||||
};
|
||||
const numberDuration = Number(duration.slice(0, -1));
|
||||
const multiplier = multipliers[lastChar];
|
||||
|
||||
return numberDuration * multiplier;
|
||||
});
|
||||
|
||||
export const shouldSkipEnvValidation = () =>
|
||||
Boolean(process.env.CI) || Boolean(process.env.SKIP_ENV_VALIDATION) || process.env.npm_lifecycle_event === "lint";
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ZodError } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { ZodError } from "zod/v4";
|
||||
|
||||
import { logger } from "@homarr/log";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
export type MaybePromise<T> = T | Promise<T>;
|
||||
|
||||
@@ -19,7 +19,7 @@ export type Inverse<T extends Invertible> = {
|
||||
|
||||
type Invertible = Record<PropertyKey, PropertyKey>;
|
||||
|
||||
export type inferSearchParamsFromSchema<TSchema extends z.AnyZodObject> = inferSearchParamsFromSchemaInner<
|
||||
export type inferSearchParamsFromSchema<TSchema extends z.ZodObject> = inferSearchParamsFromSchemaInner<
|
||||
z.infer<TSchema>
|
||||
>;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"dependencies": {
|
||||
"@t3-oss/env-nextjs": "^0.13.8",
|
||||
"ioredis": "5.7.0",
|
||||
"zod": "^3.25.76"
|
||||
"zod": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
17
packages/core/src/infrastructure/env/schemas.ts
vendored
17
packages/core/src/infrastructure/env/schemas.ts
vendored
@@ -1,19 +1,16 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
const trueStrings = ["1", "yes", "t", "true"];
|
||||
const falseStrings = ["0", "no", "f", "false"];
|
||||
|
||||
export const createBooleanSchema = (defaultValue: boolean) =>
|
||||
z
|
||||
.string()
|
||||
.default(defaultValue.toString())
|
||||
.transform((value, ctx) => {
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (trueStrings.includes(normalized)) return true;
|
||||
if (falseStrings.includes(normalized)) return false;
|
||||
|
||||
throw new Error(`Invalid boolean value for ${ctx.path.join(".")}`);
|
||||
});
|
||||
.stringbool({
|
||||
truthy: trueStrings,
|
||||
falsy: falseStrings,
|
||||
case: "insensitive",
|
||||
})
|
||||
.default(defaultValue);
|
||||
|
||||
export const createDurationSchema = (defaultValue: `${number}${"s" | "m" | "h" | "d"}`) =>
|
||||
z
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"@trpc/tanstack-react-query": "^11.4.4",
|
||||
"node-cron": "^4.2.1",
|
||||
"react": "19.1.1",
|
||||
"zod": "^3.25.76"
|
||||
"zod": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { env as commonEnv } from "@homarr/common/env";
|
||||
import { createEnv } from "@homarr/core/infrastructure/env";
|
||||
@@ -42,7 +42,7 @@ export const env = createEnv({
|
||||
.regex(/\d+/)
|
||||
.transform(Number)
|
||||
.refine((number) => number >= 1)
|
||||
.default("3306"),
|
||||
.default(3306),
|
||||
DB_USER: z.string(),
|
||||
DB_PASSWORD: z.string(),
|
||||
DB_NAME: z.string(),
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
"dotenv": "^17.2.1",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"drizzle-orm": "^0.44.4",
|
||||
"drizzle-zod": "^0.7.1",
|
||||
"drizzle-zod": "^0.8.2",
|
||||
"mysql2": "3.14.3",
|
||||
"superjson": "2.2.2"
|
||||
},
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"dependencies": {
|
||||
"@homarr/common": "workspace:^0.1.0",
|
||||
"fast-xml-parser": "^5.2.5",
|
||||
"zod": "^3.25.76"
|
||||
"zod": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from "node:fs/promises";
|
||||
import path, { dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { XMLParser } from "fast-xml-parser";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createDocumentationLink } from "./index";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createBooleanSchema, createEnv } from "@homarr/core/infrastructure/env";
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"@homarr/translation": "workspace:^0.1.0",
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
"@mantine/form": "^8.2.4",
|
||||
"zod": "^3.25.76"
|
||||
"mantine-form-zod-resolver": "^1.2.1",
|
||||
"zod": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
@@ -1,29 +1,39 @@
|
||||
import { useForm, zodResolver } from "@mantine/form";
|
||||
import { z } from "zod";
|
||||
import type { AnyZodObject, ZodDiscriminatedUnion, ZodEffects, ZodIntersection } from "zod";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { zod4Resolver } from "mantine-form-zod-resolver";
|
||||
import type { ZodDiscriminatedUnion, ZodIntersection, ZodObject, ZodPipe } from "zod/v4";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import { zodErrorMap } from "@homarr/validation/form/i18n";
|
||||
|
||||
type inferPossibleSchema<
|
||||
TSchema extends
|
||||
| ZodObject
|
||||
| ZodPipe<ZodObject>
|
||||
| ZodIntersection<ZodObject | ZodDiscriminatedUnion<ZodObject[]>, ZodObject>,
|
||||
> = z.infer<TSchema> extends Record<string, unknown> ? z.infer<TSchema> : never;
|
||||
|
||||
export const useZodForm = <
|
||||
TSchema extends
|
||||
| AnyZodObject
|
||||
| ZodEffects<AnyZodObject>
|
||||
| ZodIntersection<AnyZodObject | ZodDiscriminatedUnion<string, AnyZodObject[]>, AnyZodObject>,
|
||||
| ZodObject
|
||||
| ZodPipe<ZodObject>
|
||||
| ZodIntersection<ZodObject | ZodDiscriminatedUnion<ZodObject[]>, ZodObject>,
|
||||
>(
|
||||
schema: TSchema,
|
||||
options: Omit<
|
||||
Exclude<Parameters<typeof useForm<z.infer<TSchema>>>[0], undefined>,
|
||||
Exclude<Parameters<typeof useForm<inferPossibleSchema<TSchema>>>[0], undefined>,
|
||||
"validate" | "validateInputOnBlur" | "validateInputOnChange"
|
||||
>,
|
||||
) => {
|
||||
const t = useI18n();
|
||||
|
||||
z.setErrorMap(zodErrorMap(t));
|
||||
return useForm<z.infer<TSchema>>({
|
||||
z.config({
|
||||
customError: zodErrorMap(t),
|
||||
});
|
||||
return useForm<inferPossibleSchema<TSchema>>({
|
||||
...options,
|
||||
validateInputOnBlur: true,
|
||||
validateInputOnChange: true,
|
||||
validate: zodResolver(schema),
|
||||
validate: zod4Resolver(schema),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import type { ErrorMapCtx, z, ZodTooBigIssue, ZodTooSmallIssue } from "zod";
|
||||
import { ZodIssueCode } from "zod";
|
||||
|
||||
import type { TranslationObject } from "@homarr/translation";
|
||||
|
||||
const handleStringError = (issue: z.ZodInvalidStringIssue) => {
|
||||
if (typeof issue.validation === "object") {
|
||||
// Check if object contains startsWith / endsWith key to determine the error type. If not, it's an includes error. (see type of issue.validation)
|
||||
if ("startsWith" in issue.validation) {
|
||||
return {
|
||||
key: "errors.string.startsWith",
|
||||
params: {
|
||||
startsWith: issue.validation.startsWith,
|
||||
},
|
||||
} as const;
|
||||
} else if ("endsWith" in issue.validation) {
|
||||
return {
|
||||
key: "errors.string.endsWith",
|
||||
params: {
|
||||
endsWith: issue.validation.endsWith,
|
||||
},
|
||||
} as const;
|
||||
}
|
||||
|
||||
return {
|
||||
key: "errors.invalid_string.includes",
|
||||
params: {
|
||||
includes: issue.validation.includes,
|
||||
},
|
||||
} as const;
|
||||
}
|
||||
|
||||
return {
|
||||
message: issue.message,
|
||||
};
|
||||
};
|
||||
|
||||
const handleTooSmallError = (issue: ZodTooSmallIssue) => {
|
||||
if (issue.type !== "string" && issue.type !== "number") {
|
||||
return {
|
||||
message: issue.message,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
key: `errors.tooSmall.${issue.type}`,
|
||||
params: {
|
||||
minimum: issue.minimum,
|
||||
count: issue.minimum,
|
||||
},
|
||||
} as const;
|
||||
};
|
||||
|
||||
const handleTooBigError = (issue: ZodTooBigIssue) => {
|
||||
if (issue.type !== "string" && issue.type !== "number") {
|
||||
return {
|
||||
message: issue.message,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
key: `errors.tooBig.${issue.type}`,
|
||||
params: {
|
||||
maximum: issue.maximum,
|
||||
count: issue.maximum,
|
||||
},
|
||||
} as const;
|
||||
};
|
||||
|
||||
export const handleZodError = (issue: z.ZodIssueOptionalMessage, ctx: ErrorMapCtx) => {
|
||||
if (ctx.defaultError === "Required") {
|
||||
return {
|
||||
key: "errors.required",
|
||||
params: {},
|
||||
} as const;
|
||||
}
|
||||
if (issue.code === ZodIssueCode.invalid_string) {
|
||||
return handleStringError(issue);
|
||||
}
|
||||
if (issue.code === ZodIssueCode.too_small) {
|
||||
return handleTooSmallError(issue);
|
||||
}
|
||||
if (issue.code === ZodIssueCode.too_big) {
|
||||
return handleTooBigError(issue);
|
||||
}
|
||||
if (issue.code === ZodIssueCode.custom && issue.params?.i18n) {
|
||||
const { i18n } = issue.params as CustomErrorParams;
|
||||
return {
|
||||
key: `errors.custom.${i18n.key}`,
|
||||
} as const;
|
||||
}
|
||||
|
||||
return {
|
||||
message: issue.message,
|
||||
};
|
||||
};
|
||||
|
||||
export interface CustomErrorParams {
|
||||
i18n: {
|
||||
key: keyof TranslationObject["common"]["zod"]["errors"]["custom"];
|
||||
params?: Record<string, unknown>;
|
||||
};
|
||||
}
|
||||
@@ -31,7 +31,7 @@
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
"@mantine/core": "^8.2.4",
|
||||
"react": "19.1.1",
|
||||
"zod": "^3.25.76"
|
||||
"zod": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useEffect, useRef } from "react";
|
||||
import Link from "next/link";
|
||||
import { Button, Checkbox, Collapse, Group, Stack, Textarea, TextInput } from "@mantine/core";
|
||||
import { useDebouncedValue, useDisclosure } from "@mantine/hooks";
|
||||
import type { z } from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"tsdav": "^2.1.5",
|
||||
"undici": "7.13.0",
|
||||
"xml2js": "^0.6.2",
|
||||
"zod": "^3.25.76"
|
||||
"zod": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const statsResponseSchema = z.object({
|
||||
time_units: z.enum(["hours", "days"]),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const releasesResponseSchema = z.array(
|
||||
z.object({
|
||||
|
||||
@@ -3,7 +3,7 @@ import { humanFileSize } from "@homarr/common";
|
||||
import "@homarr/redis";
|
||||
|
||||
import dayjs from "dayjs";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const accessTokenResponseSchema = z.object({
|
||||
access_token: z.string(),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const queueSchema = z.object({
|
||||
queue: z.object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BaseItemKind } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server";
|
||||
import { ResponseError } from "@homarr/common/server";
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const entityStateSchema = z.object({
|
||||
attributes: z.record(
|
||||
z.string(),
|
||||
z.union([z.string(), z.number(), z.boolean(), z.null(), z.array(z.union([z.string(), z.number()]))]),
|
||||
),
|
||||
entity_id: z.string(),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user