133 lines
3.8 KiB
TypeScript
133 lines
3.8 KiB
TypeScript
export function sanitizeString(
|
|
input: string | null | undefined,
|
|
maxLength: number = 1000
|
|
): string | null {
|
|
if (input === null || input === undefined) {
|
|
return null;
|
|
}
|
|
const trimmed = input.trim();
|
|
if (trimmed.length > maxLength) {
|
|
throw new Error(`Input exceeds maximum length of ${maxLength}`);
|
|
}
|
|
return trimmed;
|
|
}
|
|
|
|
export function sanitizeUrl(url: string | null | undefined): string | null {
|
|
if (!url) {
|
|
return null;
|
|
}
|
|
return url.trim();
|
|
}
|
|
|
|
export function sanitizeText(
|
|
input: string | null | undefined,
|
|
maxLength: number = 10000
|
|
): string | null {
|
|
if (input === null || input === undefined) {
|
|
return null;
|
|
}
|
|
const trimmed = input.trim();
|
|
if (trimmed.length > maxLength) {
|
|
throw new Error(`Text exceeds maximum length of ${maxLength}`);
|
|
}
|
|
return trimmed;
|
|
}
|
|
|
|
export function sanitizePrice(price: string | null | undefined): number | null {
|
|
if (!price) {
|
|
return null;
|
|
}
|
|
const parsed = parseFloat(price.trim());
|
|
if (isNaN(parsed)) {
|
|
throw new Error('Invalid price format');
|
|
}
|
|
if (parsed < 0) {
|
|
throw new Error('Price cannot be negative');
|
|
}
|
|
return parsed;
|
|
}
|
|
|
|
export function sanitizeColor(color: string | null | undefined): string | null {
|
|
if (!color) {
|
|
return null;
|
|
}
|
|
return color.trim();
|
|
}
|
|
|
|
export function sanitizeCurrency(currency: string | null | undefined): string {
|
|
if (!currency) {
|
|
return 'DKK';
|
|
}
|
|
return currency.trim().toUpperCase();
|
|
}
|
|
|
|
export function sanitizeUsername(username: string): string {
|
|
const trimmed = username.trim().toLowerCase();
|
|
if (trimmed.length < 3 || trimmed.length > 50) {
|
|
throw new Error('Username must be between 3 and 50 characters');
|
|
}
|
|
return trimmed;
|
|
}
|
|
|
|
export function sanitizeId(id: string | null | undefined): string {
|
|
if (!id) {
|
|
throw new Error('ID is required');
|
|
}
|
|
const trimmed = id.trim();
|
|
if (trimmed.length === 0 || trimmed.length > 100) {
|
|
throw new Error('Invalid ID');
|
|
}
|
|
return trimmed;
|
|
}
|
|
|
|
export function sanitizeToken(token: string | null | undefined): string {
|
|
if (!token) {
|
|
throw new Error('Token is required');
|
|
}
|
|
const trimmed = token.trim();
|
|
if (trimmed.length === 0 || trimmed.length > 100) {
|
|
throw new Error('Invalid token');
|
|
}
|
|
return trimmed;
|
|
}
|
|
|
|
// Zod schemas for type-safe form validation
|
|
import { z } from 'zod';
|
|
import { CURRENCIES } from '$lib/utils/currency';
|
|
|
|
export const currencySchema = z.enum(CURRENCIES);
|
|
|
|
export const itemSchema = z.object({
|
|
title: z.string().min(1, 'Title is required').max(255),
|
|
description: z.preprocess(val => (val === '' ? null : val), z.string().max(2000).optional().nullable()),
|
|
link: z.preprocess(val => (val === '' ? null : val), z.string().url('Invalid URL').optional().nullable()),
|
|
imageUrl: z.preprocess(val => (val === '' ? null : val), z.string().url('Invalid image URL').optional().nullable()),
|
|
price: z.coerce.number().nonnegative().optional().nullable(),
|
|
currency: currencySchema.default('DKK'),
|
|
color: z.preprocess(val => (val === '' ? null : val), z.string().optional().nullable()),
|
|
order: z.coerce.number().int().nonnegative().optional()
|
|
});
|
|
|
|
export const updateItemSchema = itemSchema.extend({
|
|
itemId: z.string().min(1, 'Item ID is required')
|
|
});
|
|
|
|
export const wishlistSchema = z.object({
|
|
title: z.string().min(1, 'Title is required').max(255),
|
|
description: z.string().max(2000).optional().nullable(),
|
|
color: z.string().optional().nullable(),
|
|
theme: z.string().optional().nullable().transform((val) => val || 'none'),
|
|
endDate: z.coerce.date().optional().nullable()
|
|
});
|
|
|
|
export const reorderSchema = z.array(
|
|
z.object({
|
|
id: z.string(),
|
|
order: z.number().int().nonnegative()
|
|
})
|
|
);
|
|
|
|
export type ItemFormData = z.infer<typeof itemSchema>;
|
|
export type UpdateItemFormData = z.infer<typeof updateItemSchema>;
|
|
export type WishlistFormData = z.infer<typeof wishlistSchema>;
|