import { z } from 'zod'; import { FmStatus } from './enums.js'; import { PaginationQuery } from './pagination.js'; // Host lookup accepts either a uuid `hostId` or a string `assetId` — exactly one. const hostSelector = { hostId: z.string().uuid().optional(), assetId: z.string().trim().min(1).max(128).optional(), }; function hostSelectorRefine( v: T, ctx: z.RefinementCtx, ) { const has = [v.hostId, v.assetId].filter((x) => x !== undefined && x !== '').length; if (has !== 1) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Provide exactly one of hostId or assetId', path: ['hostId'], }); } } export const CreateFmRequest = z .object({ ...hostSelector, problem: z.string().trim().min(1, 'Problem is required').max(2000), problemPartIds: z.array(z.string().uuid()).max(100).optional(), }) .superRefine(hostSelectorRefine); export type CreateFmRequest = z.infer; export const UpdateFmRequest = z .object({ status: FmStatus.optional(), problem: z.string().trim().min(1).max(2000).optional(), problemPartIds: z.array(z.string().uuid()).max(100).optional(), }) .refine((v) => Object.keys(v).length > 0, { message: 'At least one field required' }); export type UpdateFmRequest = z.infer; export const FmListQuery = PaginationQuery.extend({ status: FmStatus.optional(), hostId: z.string().uuid().optional(), problemPartId: z.string().uuid().optional(), openOnly: z .union([z.literal('true'), z.literal('false'), z.boolean()]) .transform((v) => v === true || v === 'true') .optional(), }); export type FmListQuery = z.infer;