import { IsEmail, IsISO8601, IsOptional, IsString, Matches, MaxLength } from 'class-validator' // IANA timezone sanity check (Area/Location, optionally a third segment). Not a // full tz-database membership test — Luxon rejects unknown zones downstream. const TZ = /^[A-Za-z]+\/[A-Za-z0-9_+-]+(\/[A-Za-z0-9_+-]+)?$/ export class SlotsQueryDto { @IsISO8601() from!: string @IsISO8601() to!: string @IsString() @MaxLength(64) @Matches(TZ, { message: 'timezone must be an IANA zone like Europe/Copenhagen' }) timezone!: string } export class CreateHoldDto { @IsISO8601() startUtc!: string // Optional captcha token (e.g. Cloudflare Turnstile). Enforced server-side // only when a captcha provider is configured; ignored otherwise. @IsOptional() @IsString() @MaxLength(4096) captchaToken?: string } export class CreateBookingDto { @IsISO8601() startUtc!: string @IsString() @MaxLength(120) attendeeName!: string @IsEmail() @MaxLength(254) attendeeEmail!: string @IsString() @MaxLength(64) @Matches(TZ, { message: 'attendeeTimezone must be an IANA zone like Europe/Copenhagen' }) attendeeTimezone!: string @IsOptional() @IsString() @MaxLength(2000) attendeeNotes?: string @IsOptional() @IsString() @MaxLength(64) holdId?: string // Optional captcha token (e.g. Cloudflare Turnstile). Enforced server-side // only when a captcha provider is configured; ignored otherwise. @IsOptional() @IsString() @MaxLength(4096) captchaToken?: string } export class CancelBookingDto { @IsOptional() @IsString() @MaxLength(500) reason?: string } export class RescheduleBookingDto { @IsISO8601() startUtc!: string }