Files
cardy/shared/src/schemas.ts
T
2026-09-29 15:55:25 +03:00

51 lines
1.5 KiB
TypeScript

import { z } from 'zod';
import { CODE_TYPES } from './codeTypes.js';
import { ROLES } from './models.js';
export const colorSchema = z.string().regex(/^#[0-9a-fA-F]{6}$/, 'Color must be #RRGGBB');
export const cardFieldsSchema = z.object({
name: z.string().trim().min(1, 'Name is required').max(200),
color: colorSchema,
code: z.string().min(1, 'Code is required').max(4000),
codeType: z.enum(CODE_TYPES),
// Free text, may be multiline. No default: partial updates must not clear it.
// Multipart forms send CRLF line breaks: store plain LF.
comment: z
.string()
.transform((s) => s.replace(/\r\n?/g, '\n').trim())
.pipe(z.string().max(2000, 'Comment is too long (max 2000 characters)'))
.optional(),
});
export type CardFields = z.infer<typeof cardFieldsSchema>;
export const cardPatchSchema = cardFieldsSchema.partial().extend({
deleted: z.boolean().optional(),
});
export type CardPatch = z.infer<typeof cardPatchSchema>;
export const emailSchema = z.string().trim().toLowerCase().pipe(z.email());
export const groupInputSchema = z.object({
name: z.string().trim().min(1, 'Name is required').max(100),
});
export const userCreateSchema = z.object({
email: emailSchema,
role: z.enum(ROLES).default('user'),
groupId: z.string().optional(),
});
export const userPatchSchema = z.object({
role: z.enum(ROLES).optional(),
groupId: z.string().optional(),
});
export const keyCreateSchema = z.object({
label: z.string().trim().max(100).optional(),
});
export const currentGroupSchema = z.object({
groupId: z.string().min(1),
});