import { InputJsonValue } from "@prisma/client/runtime/library"; import { z } from "zod/v4"; // to be used for Prisma JSON type // @see: https://github.com/colinhacks/zod#json-type // For root-level literals where null is not allowed const rootLiteralSchema = z.union([z.string(), z.number(), z.boolean()]); // For nested literals where null is allowed const nestedLiteralSchema = z.union([ z.string(), z.number(), z.boolean(), z.null(), ]); type Root = z.infer; type Literal = z.infer; export type JsonNested = Literal | { [key: string]: JsonNested } | JsonNested[]; type Json = Root | { [key: string]: JsonNested } | JsonNested[]; // Here, you define the schema recursively export const jsonSchemaNullable: z.ZodType = z.lazy(() => z.union([ z.array(jsonSchemaNullable), z.record(z.string(), jsonSchemaNullable), nestedLiteralSchema, ]), ); // Root schema that does not allow nulls at the root level export const jsonSchema: z.ZodType = z.lazy(() => z.union([ z.array(jsonSchemaNullable), z.record(z.string(), jsonSchemaNullable), rootLiteralSchema, ]), ); export const paginationZod = { page: z.preprocess( (x) => (x === "" ? undefined : x), z.coerce.number().nonnegative().default(1), ), limit: z.preprocess( (x) => (x === "" ? undefined : x), z.coerce.number().nonnegative().lte(100).default(50), ), }; export const publicApiPaginationZod = { page: z.preprocess( (x) => (x === "" ? undefined : x), z.coerce.number().gt(0).default(1), ), limit: z.preprocess( (x) => (x === "" ? undefined : x), z.coerce.number().lte(100).default(50), ), }; export const optionalPaginationZod = { page: z .preprocess((x) => (x === "" ? undefined : x), z.coerce.number()) .optional(), limit: z .preprocess((x) => (x === "" ? undefined : x), z.coerce.number()) .optional(), }; export const queryStringZod = z .string() .transform((val) => decodeURIComponent(val)); export const paginationMetaResponseZod = z.object({ page: z.number().int().positive(), limit: z.number().int().positive(), totalItems: z.number().int().nonnegative(), totalPages: z.number().int().nonnegative(), }); export const urlRegex = /https?:\/\/[^\s/$.?#].[^\s]*/i; export const noUrlCheck = (value: string) => !urlRegex.test(value); export const NonEmptyString = z.string().min(1); export const htmlRegex = /<[^>]*>/; export const StringNoHTML = z.string().refine((val) => !htmlRegex.test(val), { message: "Text cannot contain HTML tags", }); export const StringNoHTMLNonEmpty = z .string() .min(1, "Text cannot be empty") .refine((val) => !htmlRegex.test(val), { message: "Text cannot contain HTML tags", }); /** * Validates an object against a Zod schema and helps with IDE type warnings. * * @param schema - The Zod schema to validate against. * @param object - The object to be validated. * @returns The parsed object if validation is successful. */ export const validateZodSchema = ( schema: T, object: z.infer, ): z.infer => { return schema.parse(object); }; // JSON Schema validation export const JSONPrimitiveValueSchema = z.union([ z.string(), z.number().finite(), z.boolean(), ]); export const JSONValueSchema: z.ZodType = z.lazy(() => z.union([ JSONPrimitiveValueSchema, z.array(JSONValueSchema), z.record(z.string(), JSONValueSchema), ]), ); export const JSONObjectSchema = z.record(z.string(), JSONValueSchema); export const JSONArraySchema = z.array(JSONValueSchema); export type JSONPrimitiveValue = z.infer; export type JSONValue = z.infer; export type JSONObject = z.infer; export type JSONArray = z.infer;