/** * @file SearchParamParser.ts * Type-safe parser for search parameters from URL * Returns Result type for clean error handling */ import { Result } from '@/lib/contracts/Result'; import { SearchParamValidators } from './SearchParamValidators'; export interface ParsedAuthParams { returnTo?: string | null; token?: string | null; email?: string | null; error?: string | null; message?: string | null; } export interface ParsedSponsorParams { type?: string | null; campaignId?: string | null; } export interface ParsedPaginationParams { page?: number; limit?: number; offset?: number; } export interface ParsedSortingParams { sortBy?: string | null; order?: 'asc' | 'desc'; } export interface ParsedFilterParams { status?: string | null; role?: string | null; tier?: string | null; } export class SearchParamParser { // Parse auth parameters static parseAuth(params: URLSearchParams): Result { const errors: string[] = []; const returnTo = params.get('returnTo'); if (returnTo !== null) { const validation = SearchParamValidators.validateReturnTo(returnTo); if (!validation.isValid) { errors.push(...validation.errors); } } const token = params.get('token'); if (token !== null) { const validation = SearchParamValidators.validateToken(token); if (!validation.isValid) { errors.push(...validation.errors); } } const email = params.get('email'); if (email !== null) { const validation = SearchParamValidators.validateEmail(email); if (!validation.isValid) { errors.push(...validation.errors); } } if (errors.length > 0) { return Result.err(errors.join(', ')); } return Result.ok({ returnTo: params.get('returnTo'), token: params.get('token'), email: params.get('email'), error: params.get('error'), message: params.get('message'), }); } // Parse sponsor parameters static parseSponsor(params: URLSearchParams): Result { const errors: string[] = []; const type = params.get('type'); if (type !== null) { const validation = SearchParamValidators.validateCampaignType(type); if (!validation.isValid) { errors.push(...validation.errors); } } if (errors.length > 0) { return Result.err(errors.join(', ')); } return Result.ok({ type: params.get('type'), campaignId: params.get('campaignId'), }); } // Parse pagination parameters static parsePagination(params: URLSearchParams): Result { const result: ParsedPaginationParams = {}; const errors: string[] = []; const page = params.get('page'); if (page !== null) { const validation = SearchParamValidators.validatePage(page); if (!validation.isValid) { errors.push(...validation.errors); } else { result.page = parseInt(page); } } const limit = params.get('limit'); if (limit !== null) { const validation = SearchParamValidators.validateLimit(limit); if (!validation.isValid) { errors.push(...validation.errors); } else { result.limit = parseInt(limit); } } const offset = params.get('offset'); if (offset !== null) { const num = parseInt(offset); if (!isNaN(num)) { result.offset = num; } } if (errors.length > 0) { return Result.err(errors.join(', ')); } return Result.ok(result); } // Parse sorting parameters static parseSorting(params: URLSearchParams): Result { const errors: string[] = []; const order = params.get('order'); if (order !== null) { const validation = SearchParamValidators.validateOrder(order); if (!validation.isValid) { errors.push(...validation.errors); } } if (errors.length > 0) { return Result.err(errors.join(', ')); } return Result.ok({ sortBy: params.get('sortBy'), order: (params.get('order') as 'asc' | 'desc') || undefined, }); } // Parse filter parameters static parseFilters(params: URLSearchParams): Result { return Result.ok({ status: params.get('status'), role: params.get('role'), tier: params.get('tier'), }); } // Parse all parameters at once static parseAll(params: URLSearchParams): Result< { auth: ParsedAuthParams; sponsor: ParsedSponsorParams; pagination: ParsedPaginationParams; sorting: ParsedSortingParams; filters: ParsedFilterParams; }, string > { const authResult = this.parseAuth(params); if (authResult.isErr()) return Result.err(authResult.getError()); const sponsorResult = this.parseSponsor(params); if (sponsorResult.isErr()) return Result.err(sponsorResult.getError()); const paginationResult = this.parsePagination(params); if (paginationResult.isErr()) return Result.err(paginationResult.getError()); const sortingResult = this.parseSorting(params); if (sortingResult.isErr()) return Result.err(sortingResult.getError()); const filtersResult = this.parseFilters(params); return Result.ok({ auth: authResult.unwrap(), sponsor: sponsorResult.unwrap(), pagination: paginationResult.unwrap(), sorting: sortingResult.unwrap(), filters: filtersResult.unwrap(), }); } }