Files
musicshare/packages/shared/src/schemas.ts
T
chrisandClaude Opus 5.5 0122a93212 Trim emails before validating them
Zod ran the email format check before trim, so an address with a trailing
space was rejected as invalid. iOS keyboards commonly add one after
autocomplete.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
2026-10-03 11:28:17 -04:00

50 lines
1.7 KiB
TypeScript

import { z } from 'zod';
import { STREAMING_SERVICES } from './services';
export const usernameSchema = z
.string()
.trim()
.toLowerCase()
.regex(/^[a-z0-9_]{3,32}$/, 'Username must be 3-32 characters: letters, numbers, underscores');
// Trim before validating: iOS keyboards often append a space after autocompleting an email.
const emailSchema = z.string().trim().toLowerCase().pipe(z.email());
export const registerSchema = z.object({
username: usernameSchema,
email: emailSchema,
password: z.string().min(8, 'Password must be at least 8 characters').max(200),
});
export const loginSchema = z.object({
email: emailSchema,
password: z.string().min(1).max(200),
});
export const updateMeSchema = z.object({
displayName: z.string().trim().max(64).nullable().optional(),
bio: z.string().trim().max(280).nullable().optional(),
avatarUrl: z.url().max(500).nullable().optional(),
preferredService: z.enum(STREAMING_SERVICES).nullable().optional(),
});
export const setFeaturedSchema = z.union([
z.object({ deezerId: z.string().regex(/^\d+$/), comment: z.string().trim().max(280).nullable().optional() }),
z.object({ trackId: z.uuid(), comment: z.string().trim().max(280).nullable().optional() }),
]);
export const connectUsernameSchema = z.object({
username: z.string().trim().min(1).max(64),
});
export type RegisterInput = z.infer<typeof registerSchema>;
export type LoginInput = z.infer<typeof loginSchema>;
export type UpdateMeInput = z.infer<typeof updateMeSchema>;
export type SetFeaturedInput = z.infer<typeof setFeaturedSchema>;
export const jellyfinConnectSchema = z.object({
serverUrl: z.string().trim().min(1).max(500),
username: z.string().trim().min(1).max(128),
password: z.string().max(256).default(''),
});