/** * @file SearchParamBuilder.ts * Type-safe builder for constructing search parameter strings * Pure function, no side effects */ import { SearchParamValidators } from './SearchParamValidators'; export class SearchParamBuilder { private params: URLSearchParams; constructor() { this.params = new URLSearchParams(); } // Auth params returnTo(value: string | null): this { if (value !== null) { const validation = SearchParamValidators.validateReturnTo(value); if (!validation.isValid) { throw new Error(`Invalid returnTo: ${validation.errors.join(', ')}`); } this.params.set('returnTo', value); } return this; } token(value: string | null): this { if (value !== null) { const validation = SearchParamValidators.validateToken(value); if (!validation.isValid) { throw new Error(`Invalid token: ${validation.errors.join(', ')}`); } this.params.set('token', value); } return this; } email(value: string | null): this { if (value !== null) { const validation = SearchParamValidators.validateEmail(value); if (!validation.isValid) { throw new Error(`Invalid email: ${validation.errors.join(', ')}`); } this.params.set('email', value); } return this; } error(value: string | null): this { if (value !== null) { this.params.set('error', value); } return this; } message(value: string | null): this { if (value !== null) { this.params.set('message', value); } return this; } // Sponsor params campaignType(value: string | null): this { if (value !== null) { const validation = SearchParamValidators.validateCampaignType(value); if (!validation.isValid) { throw new Error(`Invalid campaign type: ${validation.errors.join(', ')}`); } this.params.set('type', value); } return this; } campaignId(value: string | null): this { if (value !== null) { this.params.set('campaignId', value); } return this; } // Pagination params page(value: number | null): this { if (value !== null) { const validation = SearchParamValidators.validatePage(value.toString()); if (!validation.isValid) { throw new Error(`Invalid page: ${validation.errors.join(', ')}`); } this.params.set('page', value.toString()); } return this; } limit(value: number | null): this { if (value !== null) { const validation = SearchParamValidators.validateLimit(value.toString()); if (!validation.isValid) { throw new Error(`Invalid limit: ${validation.errors.join(', ')}`); } this.params.set('limit', value.toString()); } return this; } offset(value: number | null): this { if (value !== null) { this.params.set('offset', value.toString()); } return this; } // Sorting params sortBy(value: string | null): this { if (value !== null) { this.params.set('sortBy', value); } return this; } order(value: string | null): this { if (value !== null) { const validation = SearchParamValidators.validateOrder(value); if (!validation.isValid) { throw new Error(`Invalid order: ${validation.errors.join(', ')}`); } this.params.set('order', value); } return this; } // Filtering params status(value: string | null): this { if (value !== null) { this.params.set('status', value); } return this; } role(value: string | null): this { if (value !== null) { this.params.set('role', value); } return this; } tier(value: string | null): this { if (value !== null) { this.params.set('tier', value); } return this; } // Wizard params step(value: string | null): this { if (value !== null) { this.params.set('step', value); } return this; } // Generic setter set(key: string, value: string | null): this { if (value !== null) { this.params.set(key, value); } return this; } // Build the query string build(): string { const queryString = this.params.toString(); return queryString ? `?${queryString}` : ''; } // Static factory methods for common scenarios static auth(returnTo?: string | null, token?: string | null, email?: string | null): string { const builder = new SearchParamBuilder(); if (returnTo !== undefined) builder.returnTo(returnTo); if (token !== undefined) builder.token(token); if (email !== undefined) builder.email(email); return builder.build(); } static pagination(page?: number | null, limit?: number | null): string { const builder = new SearchParamBuilder(); if (page !== undefined) builder.page(page); if (limit !== undefined) builder.limit(limit); return builder.build(); } static sorting(sortBy?: string | null, order?: string | null): string { const builder = new SearchParamBuilder(); if (sortBy !== undefined) builder.sortBy(sortBy); if (order !== undefined) builder.order(order); return builder.build(); } static sponsorCampaign(type?: string | null, campaignId?: string | null): string { const builder = new SearchParamBuilder(); if (type !== undefined) builder.campaignType(type); if (campaignId !== undefined) builder.campaignId(campaignId); return builder.build(); } }