- Use path aliases instead of relative paths - Fixes module resolution errors when importing from other files - Ensures fallback to Fontshare API works correctly
13 KiB
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
- Missing
gcTimeparameter in TanStack Query configuration - No response validation when proxy API returns invalid/missing data
- 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:
private getOptions(params = this.params): QueryObserverOptions<UnifiedFont[], Error> {
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:
protected async fetchFn(params: ProxyFontsParams): Promise<UnifiedFont[]> {
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:
/**
* 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<ProxyFontsResponse> {
// 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<ProxyFontsResponse>(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<ProxyFontsResponse> {
// 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:
<script lang="ts" generics="T extends ({ id: string } | [{ id: string }, { id: string; }])">
After:
<script lang="ts" generics="T extends { id: string }">
Also simplified the font registration logic:
Before:
const slugs = visibleItems.map(item => {
if (Array.isArray(item)) {
return item.map(font => font.id);
}
return item.id;
}).flat();
After:
const slugs = visibleItems.map(item => item.id);
Impact:
- Fixed TypeScript errors
- Simplified code
- Proper type safety
How It Works
Normal Flow (Proxy API Available)
- Request: Component requests fonts → Filter manager maps to params →
unifiedFontStore.setParams() - Fetch:
unifiedFontStore.fetchFn()callsfetchProxyFonts() - Proxy API: Request sent to
https://api.glyphdiff.com/api/v1/fonts - Validation: Response validated to ensure
fontsarray exists - Cache: TanStack Query caches response for 5 minutes
- Render: Components render
unifiedFontStore.fonts
Fallback Flow (Proxy API Unavailable)
- Request: Same as normal flow
- Fetch:
fetchProxyFonts()attempts proxy API - Error: Proxy API returns network error (404, 500, connection failed)
- Detection: Error caught and classified as network error
- Fallback:
fetchFontshareFallback()called automatically - Fontshare API: Request sent to Fontshare API
- Normalization: Fontshare response normalized to
UnifiedFontformat - Render: Components render fonts seamlessly
Debug Flow (Enable Proxy API)
With USE_PROXY_API = true, console will show:
[fetchProxyFonts] Fetching from proxy API { params: {...}, url: "https://api.glyphdiff.com/api/v1/fonts?..." }
[fetchProxyFonts] Proxy API success { count: 50 }
Debug Flow (Disable Proxy API)
With USE_PROXY_API = false, console will show:
[fetchProxyFonts] Using Fontshare API (proxy disabled)
Debug Flow (Proxy API Fails)
When proxy API fails, console will show:
[fetchProxyFonts] Fetching from proxy API { params: {...}, url: "https://api.glyphdiff.com/api/v1/fonts?..." }
[fetchProxyFonts] Proxy API failed, using fallback Error: ...
[fetchProxyFonts] Using Fontshare API as fallback
Testing the Fix
1. With Proxy API Working
Prerequisites:
- Your proxy API is running at
https://api.glyphdiff.com/api/v1/fonts - Proxy API returns correct response structure
Test:
# Start dev server
yarn dev
# Open browser console
# Should see: "[fetchProxyFonts] Fetching from proxy API"
# Should see: "[fetchProxyFonts] Proxy API success { count: N }"
# Should see fonts loading correctly
Expected Behavior:
- Fonts load from proxy API
- Console shows successful fetch
- No errors in console
- All features working
2. With Proxy API Down
Prerequisites:
- Proxy API not running or returning errors
Test:
# Start dev server
yarn dev
# Open browser console
# Should see: "[fetchProxyFonts] Proxy API failed, using fallback"
# Should see: "[fetchProxyFonts] Using Fontshare API as fallback"
# Should see fonts loading from Fontshare
Expected Behavior:
- App falls back to Fontshare API automatically
- Console shows fallback messages
- Fonts load from Fontshare
- All features working (no user-facing errors)
3. Disable Proxy API Manually
File: src/entities/Font/api/proxy/proxyFonts.ts
const USE_PROXY_API = false;
Test:
# Start dev server
yarn dev
# Open browser console
# Should see: "[fetchProxyFonts] Using Fontshare API (proxy disabled)"
# Should see fonts loading from Fontshare
Expected Behavior:
- App uses Fontshare API directly
- Console shows proxy disabled message
- All features working
Next Steps
To Enable Proxy API (When Ready)
-
Verify Proxy API:
curl "https://api.glyphdiff.com/api/v1/fonts?limit=5" -
Check Response Format:
{ "fonts": [...], "total": N, "limit": 5, "offset": 0 } -
Ensure Each Font Has Required Fields:
id,name,providercategory,subsetsvariants,stylesmetadata,features
-
Test in App:
- Open browser console
- Check for success messages
- Verify fonts load correctly
To Remove Fallback (When Proxy API is Stable)
Once proxy API is proven stable, you can:
-
Remove Fallback Function:
// Delete fetchFontshareFallback() function -
Remove Dynamic Imports:
// No longer need dynamic imports const { fetchFontshareFonts } = await import('../fontshare/fontshare'); const { normalizeFontshareFonts } = await import('../../lib/normalize/normalize'); -
Remove Old API Exports:
// Remove Fontshare API exports from index.ts // Remove normalization function exports
Troubleshooting
Issue: Still Seeing "Query data cannot be undefined"
Cause: Proxy API returns invalid response
Solutions:
- Check console for validation errors
- Verify proxy API response structure
- Check network tab in DevTools for actual response
- Set
USE_PROXY_API = falseto use fallback
Issue: Fonts Not Loading At All
Cause: Both proxy and Fontshare APIs failing
Solutions:
- Check console for error messages
- Verify network connectivity
- Check CORS settings on proxy API
- Check API endpoint URL is correct
Issue: Fallback Not Triggering
Cause: Error type not recognized as network error
Solutions:
- Add additional error message checks
- Check console for actual error message
- Manually set
USE_PROXY_API = false
Files Modified
src/entities/Font/model/store/baseFontStore.svelte.ts- Added gcTime parametersrc/entities/Font/model/store/unifiedFontStore.svelte.ts- Added response validationsrc/entities/Font/api/proxy/proxyFonts.ts- Added fallback logicsrc/entities/Font/ui/FontVirtualList/FontVirtualList.svelte- Fixed generic type
Commit
commit 471e186
fix: Fix undefined query data and add fallback to Fontshare API
- Add gcTime parameter to TanStack Query config
- Add response validation in fetchFn with detailed logging
- Add fallback to Fontshare API when proxy fails
- Add USE_PROXY_API flag for easy switching
- Fix FontVirtualList generic type constraint
- Simplify font registration logic
- Add comprehensive console logging for debugging
Fixes: Query data cannot be undefined error
Documentation
See PROXY_API_FIXES.md for detailed technical documentation on all changes.
Last Updated: January 29, 2026 Status: ✅ Fixed and Committed