import { ContainerManager } from '@/lib/di/container'; export interface FetchResult { data: T | null; errors: Record; hasErrors: boolean; } export class PageDataFetcher { /** * Fetch data using DI container * Use for: Simple SSR pages with single service * WARNING: Container is singleton - avoid stateful services */ static async fetch( ServiceToken: string | symbol, method: TMethod, ...args: TService[TMethod] extends (...params: infer P) => Promise ? P : never ): Promise<(TService[TMethod] extends (...params: any[]) => Promise ? R : never) | null> { try { const container = ContainerManager.getInstance().getContainer(); const service = container.get(ServiceToken); const result = await (service[method] as Function)(...args); return result; } catch (error) { console.error(`Failed to fetch: ${String(ServiceToken)}.${String(method)}`, error); return null; } } /** * Fetch using manual service instantiation * Use for: Multiple dependencies, request-scoped services, or auth context * RECOMMENDED for SSR over fetch() with DI */ 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 any).data; } else { errors[key] = (result as any).error; } } }); return { data: results, errors, hasErrors: Object.keys(errors).length > 0 }; } }