From c06aad1a8a78ab0cbbf683e248ae9050f40fc995 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Thu, 29 Jan 2026 15:23:59 +0300 Subject: [PATCH] fix: Correct dynamic import paths in fallback function - Use path aliases instead of relative paths - Fixes module resolution errors when importing from other files - Ensures fallback to Fontshare API works correctly --- FIX_SUMMARY.md | 480 ++++++++++++++++++++++ src/entities/Font/api/proxy/proxyFonts.ts | 4 +- test-import.mjs | 2 + 3 files changed, 484 insertions(+), 2 deletions(-) create mode 100644 FIX_SUMMARY.md create mode 100644 test-import.mjs diff --git a/FIX_SUMMARY.md b/FIX_SUMMARY.md new file mode 100644 index 0000000..d3cd971 --- /dev/null +++ b/FIX_SUMMARY.md @@ -0,0 +1,480 @@ +# Fix Applied: Query Data Cannot Be Undefined + +## Summary + +Successfully fixed the TanStack Query error: **"Query data cannot be undefined. Please make sure to return a value other than undefined from your query function."** + +## Root Causes + +1. **Missing `gcTime` parameter** in TanStack Query configuration +2. **No response validation** when proxy API returns invalid/missing data +3. **Incorrect generic type constraint** in `FontVirtualList.svelte` + +## Changes Applied + +### 1. Fixed TanStack Query Configuration + +**File**: `src/entities/Font/model/store/baseFontStore.svelte.ts` + +Added `gcTime` parameter to properly manage cached data lifecycle: + +```typescript +private getOptions(params = this.params): QueryObserverOptions { + return { + queryKey: this.getQueryKey(params), + queryFn: () => this.fetchFn(params), + staleTime:5 * 60 *1000, // 5 minutes + gcTime: 10 * 60 * 1000, // 10 minutes ✅ ADDED + }; +} +``` + +**Impact**: + +- Prevents stale data from persisting too long +- Explicit control over garbage collection timing +- Better memory management + +### 2. Added Response Validation + +**File**: `src/entities/Font/model/store/unifiedFontStore.svelte.ts` + +Added comprehensive validation in `fetchFn`: + +```typescript +protected async fetchFn(params: ProxyFontsParams): Promise { + const response = await fetchProxyFonts(params); + + // Validate response exists + if (!response) { + console.error('[UnifiedFontStore] fetchProxyFonts returned undefined', { params }); + throw new Error('Proxy API returned undefined response'); + } + + // Validate fonts array exists + if (!response.fonts) { + console.error('[UnifiedFontStore] response.fonts is undefined', { response }); + throw new Error('Proxy API response missing fonts array'); + } + + // Validate fonts is an array + if (!Array.isArray(response.fonts)) { + console.error('[UnifiedFontStore] response.fonts is not an array', { fonts: response.fonts }); + throw new Error('Proxy API fonts is not an array'); + } + + // Store pagination metadata separately for derived values + this.#paginationMetadata = { + total: response.total ?? 0, + limit: response.limit ?? this.params.limit ?? 50, + offset: response.offset ?? this.params.offset ?? 0, + }; + + return response.fonts; +} +``` + +**Impact**: + +- Early detection of invalid API responses +- Detailed error logging for debugging +- Prevents undefined data from being cached +- Fallback to default values for pagination metadata + +### 3. Added Fallback to Fontshare API + +**File**: `src/entities/Font/api/proxy/proxyFonts.ts` + +Implemented automatic fallback to Fontshare API when proxy fails: + +```typescript +/** + * Whether to use proxy API (true) or fallback (false) + * + * Set to true when your proxy API is ready: + * const USE_PROXY_API = true; + * + * Set to false to use Fontshare API as fallback during development: + * const USE_PROXY_API = false; + * + * The app will automatically fall back to Fontshare API if the proxy fails. + */ +const USE_PROXY_API = true; + +export async function fetchProxyFonts( + params: ProxyFontsParams = {}, +): Promise { + // Try proxy API first if enabled + if (USE_PROXY_API) { + try { + const queryString = buildQueryString(params); + const url = `${PROXY_API_URL}${queryString}`; + + console.log('[fetchProxyFonts] Fetching from proxy API', { params, url }); + + const response = await api.get(url); + + // Validate response has fonts array + if (!response.data || !Array.isArray(response.data.fonts)) { + console.error('[fetchProxyFonts] Invalid response from proxy API', response.data); + throw new Error('Proxy API returned invalid response'); + } + + console.log('[fetchProxyFonts] Proxy API success', { + count: response.data.fonts.length, + }); + return response.data; + } catch (error) { + console.warn('[fetchProxyFonts] Proxy API failed, using fallback', error); + + // Check if it's a network error or proxy not available + const isNetworkError = error instanceof Error + && (error.message.includes('Failed to fetch') + || error.message.includes('Network') + || error.message.includes('404') + || error.message.includes('500')); + + if (isNetworkError) { + // Fall back to Fontshare API + console.log('[fetchProxyFonts] Using Fontshare API as fallback'); + return await fetchFontshareFallback(params); + } + + // Re-throw other errors + if (error instanceof Error) { + throw error; + } + throw new Error(`Failed to fetch fonts from proxy API: ${String(error)}`); + } + } + + // Use Fontshare API directly + console.log('[fetchProxyFonts] Using Fontshare API (proxy disabled)'); + return await fetchFontshareFallback(params); +} + +/** + * Fallback to Fontshare API when proxy is unavailable + */ +async function fetchFontshareFallback( + params: ProxyFontsParams, +): Promise { + // Import dynamically to avoid circular dependency + const { fetchFontshareFonts } = await import('../fontshare/fontshare'); + const { normalizeFontshareFonts } = await import('../../lib/normalize/normalize'); + + // Map proxy params to Fontshare params + const fontshareParams = { + q: params.q, + categories: params.category ? [params.category] : undefined, + page: params.offset ? Math.floor(params.offset / (params.limit || 50)) + 1 : undefined, + limit: params.limit, + }; + + const response = await fetchFontshareFonts(fontshareParams); + const normalizedFonts = normalizeFontshareFonts(response.fonts); + + return { + fonts: normalizedFonts, + total: response.count_total, + limit: params.limit || response.count, + offset: params.offset || 0, + }; +} +``` + +**Impact**: + +- App continues working even if proxy API is down +- Allows development without breaking functionality +- Automatic detection of network errors +- Seamless fallback with console logging + +### 4. Fixed Type Constraints + +**File**: `src/entities/Font/ui/FontVirtualList/FontVirtualList.svelte` + +Fixed incorrect generic type constraint: + +**Before**: + +```typescript +