UNPKG

@dbs-portal/core-api

Version:

HTTP client and API utilities for DBS Portal

279 lines 8.17 kB
/** * Query utilities and helpers */ const { VITE_NODE_ENV: NODE_ENV } = import.meta.env; /** * Error handling utilities */ export const queryErrorUtils = { /** * Check if error is a network error */ isNetworkError: (error) => { return error instanceof Error && error.message.includes('fetch'); }, /** * Check if error is an API error with status */ isApiError: (error) => { return (typeof error === 'object' && error !== null && 'status' in error && typeof error.status === 'number'); }, /** * Check if error is a client error (4xx) */ isClientError: (error) => { if (!queryErrorUtils.isApiError(error)) return false; const status = error.response?.status; return typeof status === 'number' && status >= 400 && status < 500; }, /** * Check if error is a server error (5xx) */ isServerError: (error) => { if (!queryErrorUtils.isApiError(error)) return false; const status = error.response?.status; return typeof status === 'number' && status >= 500; }, /** * Check if error is unauthorized (401) */ isUnauthorized: (error) => { if (!queryErrorUtils.isApiError(error)) return false; return error.response?.status === 401; }, /** * Check if error is forbidden (403) */ isForbidden: (error) => { if (!queryErrorUtils.isApiError(error)) return false; return error.response?.status === 403; }, /** * Check if error is not found (404) */ isNotFound: (error) => { if (!queryErrorUtils.isApiError(error)) return false; return error.response?.status === 404; }, /** * Get error message from various error types */ getErrorMessage: (error) => { if (queryErrorUtils.isApiError(error)) { const status = error.response?.status; return error.message || `API Error: ${status || 'Unknown'}`; } if (error instanceof Error) { return error.message; } if (typeof error === 'string') { return error; } return 'An unknown error occurred'; }, }; /** * Cache management utilities */ export const cacheUtils = { /** * Invalidate all queries matching a pattern */ invalidateByPattern: (queryClient, pattern) => { return queryClient.invalidateQueries({ queryKey: pattern, exact: false, }); }, /** * Remove all queries matching a pattern */ removeByPattern: (queryClient, pattern) => { return queryClient.removeQueries({ queryKey: pattern, exact: false, }); }, /** * Prefetch multiple queries */ prefetchMultiple: async (queryClient, queries) => { const promises = queries.map(({ queryKey, queryFn, staleTime }) => queryClient.prefetchQuery({ queryKey, queryFn, ...(staleTime !== undefined && { staleTime }), })); return Promise.allSettled(promises); }, /** * Get cache statistics */ getCacheStats: (queryClient) => { const cache = queryClient.getQueryCache(); const queries = cache.getAll(); const stats = { totalQueries: queries.length, activeQueries: queries.filter(q => q.getObserversCount() > 0).length, staleQueries: queries.filter(q => q.isStale()).length, errorQueries: queries.filter(q => q.state.status === 'error').length, loadingQueries: queries.filter(q => q.state.status === 'pending').length, successQueries: queries.filter(q => q.state.status === 'success').length, }; return stats; }, /** * Clear all cache data */ clearAll: (queryClient) => { queryClient.clear(); }, /** * Reset all queries to initial state */ resetAll: (queryClient) => { return queryClient.resetQueries(); }, }; /** * Query key utilities */ export const keyUtils = { /** * Create a hierarchical query key */ createHierarchical: (...segments) => { return segments.filter(segment => segment !== undefined && segment !== null); }, /** * Match query keys by pattern */ matchesPattern: (queryKey, pattern) => { if (pattern.length > queryKey.length) return false; return pattern.every((segment, index) => { const keySegment = queryKey[index]; // Exact match if (segment === keySegment) return true; // Object match (partial) if (typeof segment === 'object' && typeof keySegment === 'object' && segment !== null && keySegment !== null) { return Object.entries(segment).every(([key, value]) => { return keySegment[key] === value; }); } return false; }); }, /** * Extract parameters from query key */ extractParams: (queryKey, paramIndex) => { const param = queryKey[paramIndex]; if (typeof param === 'object' && param !== null) { return param; } return null; }, }; /** * Retry utilities */ export const retryUtils = { /** * Exponential backoff with jitter */ exponentialBackoff: (attemptIndex, baseDelay = 1000) => { const delay = baseDelay * Math.pow(2, attemptIndex); const jitter = Math.random() * 0.1 * delay; return Math.min(delay + jitter, 30000); // Max 30 seconds }, /** * Linear backoff */ linearBackoff: (attemptIndex, baseDelay = 1000) => { return Math.min(baseDelay * (attemptIndex + 1), 10000); // Max 10 seconds }, /** * Fixed delay */ fixedDelay: (delay = 1000) => { return delay; }, /** * Should retry based on error type */ shouldRetry: (failureCount, error, maxRetries = 3) => { // Don't retry if max attempts reached if (failureCount >= maxRetries) return false; // Don't retry client errors (4xx) if (queryErrorUtils.isClientError(error)) return false; // Don't retry unauthorized/forbidden if (queryErrorUtils.isUnauthorized(error) || queryErrorUtils.isForbidden(error)) { return false; } // Retry server errors and network errors return queryErrorUtils.isServerError(error) || queryErrorUtils.isNetworkError(error); }, }; /** * Performance utilities */ export const performanceUtils = { /** * Measure query performance */ measureQuery: (queryFn, queryKey) => { const startTime = performance.now(); return queryFn().then(data => { const endTime = performance.now(); const duration = endTime - startTime; // Log slow queries in development if (NODE_ENV === 'development' && duration > 1000) { console.warn(`Slow query detected (${duration.toFixed(2)}ms):`, queryKey); } return { data, duration }; }); }, /** * Create a debounced query function */ debounce: (fn, delay) => { let timeoutId; return ((...args) => { clearTimeout(timeoutId); return new Promise(resolve => { timeoutId = setTimeout(() => { resolve(fn(...args)); }, delay); }); }); }, /** * Create a throttled query function */ throttle: (fn, delay) => { let lastCall = 0; return ((...args) => { const now = Date.now(); if (now - lastCall >= delay) { lastCall = now; return fn(...args); } return Promise.resolve(); }); }, }; //# sourceMappingURL=utils.js.map