import { z } from 'zod'; import { PaginationQuery } from './pagination.js'; // Repair = a physical part-swap log entry. Tech enters host + broken serial/mpn + replacement serial. // If the broken part isn't in the catalog yet it gets auto-ingested (requires mpn + manufacturer). export const LogRepairRequest = z .object({ hostId: z.string().uuid().optional(), assetId: z.string().trim().min(1).max(128).optional(), brokenSerial: z.string().trim().min(1).max(128), // When the broken serial isn't in Vector yet we ingest it. Provide either a known PartModel // (brokenPartModelId) or the manufacturer + mpn pair to auto-create it. brokenPartModelId: z.string().uuid().optional(), brokenMpn: z.string().trim().min(1).max(128).optional(), brokenManufacturerId: z.string().uuid().optional(), replacementSerial: z.string().trim().min(1).max(128), fmId: z.string().uuid().optional(), }) .superRefine((v, ctx) => { const hostHas = [v.hostId, v.assetId].filter((x) => x !== undefined && x !== '').length; if (hostHas !== 1) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Provide exactly one of hostId or assetId', path: ['hostId'], }); } // Model fields are only required when the broken serial isn't already in Vector. The // server resolves the serial before demanding them — see services/repairs.ts. }); export type LogRepairRequest = z.infer; export const RepairListQuery = PaginationQuery.extend({ hostId: z.string().uuid().optional(), performedById: z.string().uuid().optional(), fmId: z.string().uuid().optional(), since: z.string().datetime().optional(), }); export type RepairListQuery = z.infer;