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
50 lines
1.7 KiB
TypeScript
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(''),
|
|
});
|