export interface FetchResult { data: T | null; errors: Record; hasErrors: boolean; } export class PageDataFetcher { /** * Fetch using manual service instantiation * Use for: Multiple dependencies, request-scoped services, or auth context * RECOMMENDED for SSR */ static async fetchManual( serviceFactory: () => Promise | TData ): Promise { try { const result = await serviceFactory(); return result; } catch (error) { console.error('Failed to fetch manual:', error); return null; } } /** * Fetch multiple datasets in parallel with error aggregation * Use for: Pages needing multiple service calls * UPDATED: Returns both data and errors for proper handling */ static async fetchMultiple>( queries: T ): Promise> { const results = {} as { [K in keyof T]: T[K] }; const errors = {} as Record; const entries = await Promise.all( Object.entries(queries).map(async ([key, query]) => { try { const result = await query(); return [key, { success: true, data: result }] as const; } catch (error) { console.error(`Failed to fetch ${key}:`, error); return [key, { success: false, error: error instanceof Error ? error : new Error(String(error)) }] as const; } }) ); entries.forEach(([key, result]) => { if (typeof result === 'object' && result !== null && 'success' in result) { if (result.success) { results[key as keyof T] = (result as { data: T[keyof T] }).data; } else { errors[key] = (result as { error: Error }).error; } } }); return { data: results, errors, hasErrors: Object.keys(errors).length > 0 }; } }