UNPKG

@dbs-portal/core-api

Version:

HTTP client and API utilities for DBS Portal

197 lines 6.59 kB
/** * TanStack Query client configuration and setup */ import { QueryClient } from '@tanstack/react-query'; const { VITE_NODE_ENV: NODE_ENV } = import.meta.env; /** * Default query client configuration */ const defaultQueryConfig = { defaultOptions: { queries: { // Cache data for 5 minutes by default staleTime: 5 * 60 * 1000, // Keep data in cache for 10 minutes gcTime: 10 * 60 * 1000, // Retry failed requests 3 times retry: (failureCount, error) => { // Don't retry on 4xx errors (client errors) if (error && typeof error === 'object' && 'status' in error) { const status = error.status; if (typeof status === 'number' && status >= 400 && status < 500) { return false; } } return failureCount < 3; }, // Retry with exponential backoff retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000), // Refetch on window focus in production refetchOnWindowFocus: NODE_ENV === 'production', // Don't refetch on reconnect by default refetchOnReconnect: false, // Network mode networkMode: 'online', }, mutations: { // Retry mutations once retry: 1, // Retry delay for mutations retryDelay: 1000, // Network mode for mutations networkMode: 'online', }, }, }; /** * Create a configured QueryClient instance */ export function createQueryClient(apiClient, config = {}) { const mergedConfig = { ...defaultQueryConfig, ...config, defaultOptions: { ...defaultQueryConfig.defaultOptions, ...config.defaultOptions, queries: { ...defaultQueryConfig.defaultOptions?.queries, ...config.defaultOptions?.queries, // Add global error handling throwOnError: error => { // Log errors in development if (NODE_ENV === 'development') { console.error('Query error:', error); } // Always throw errors so they can be handled by the UI return true; }, }, mutations: { ...defaultQueryConfig.defaultOptions?.mutations, ...config.defaultOptions?.mutations, // Add global mutation error handling throwOnError: error => { // Log mutation errors in development if (NODE_ENV === 'development') { console.error('Mutation error:', error); } // Always throw mutation errors so they can be handled by the UI return true; }, }, }, }; const queryClient = new QueryClient(mergedConfig); // Add global error handler queryClient.setMutationDefaults(['default'], { mutationFn: async (variables) => { if (!apiClient) { throw new Error('API client not configured'); } return variables; }, }); return queryClient; } /** * Default query client instance */ export const queryClient = createQueryClient(); /** * Query key factory for consistent key generation */ export const queryKeys = { // Base keys all: ['api'], // Resource-based keys users: () => [...queryKeys.all, 'users'], user: (id) => [...queryKeys.users(), id], userProfile: (id) => [...queryKeys.user(id), 'profile'], posts: () => [...queryKeys.all, 'posts'], post: (id) => [...queryKeys.posts(), id], postComments: (id) => [...queryKeys.post(id), 'comments'], // Search and filters search: (query) => [...queryKeys.all, 'search', query], filtered: (resource, filters) => [...queryKeys.all, resource, 'filtered', filters], // Paginated queries paginated: (resource, page, limit) => [...queryKeys.all, resource, 'paginated', { page, limit }], // Infinite queries infinite: (resource, filters) => [...queryKeys.all, resource, 'infinite', filters], // Custom query key generator custom: (key, ...params) => [...queryKeys.all, key, ...params], }; /** * Query options factory for common patterns */ export const queryOptions = { // Standard fetch with caching standard: (key, fetcher) => ({ queryKey: key, queryFn: fetcher, staleTime: 5 * 60 * 1000, // 5 minutes gcTime: 10 * 60 * 1000, // 10 minutes }), // Real-time data (short cache) realtime: (key, fetcher) => ({ queryKey: key, queryFn: fetcher, staleTime: 30 * 1000, // 30 seconds gcTime: 2 * 60 * 1000, // 2 minutes refetchInterval: 30 * 1000, // Refetch every 30 seconds }), // Static data (long cache) static: (key, fetcher) => ({ queryKey: key, queryFn: fetcher, staleTime: 60 * 60 * 1000, // 1 hour gcTime: 24 * 60 * 60 * 1000, // 24 hours }), // User-specific data user: (key, fetcher) => ({ queryKey: key, queryFn: fetcher, staleTime: 2 * 60 * 1000, // 2 minutes gcTime: 5 * 60 * 1000, // 5 minutes }), // Background sync background: (key, fetcher) => ({ queryKey: key, queryFn: fetcher, staleTime: 0, // Always stale gcTime: 5 * 60 * 1000, // 5 minutes refetchOnWindowFocus: true, refetchOnReconnect: true, }), }; /** * Mutation options factory */ export const mutationOptions = { // Standard mutation standard: (mutationFn) => ({ mutationFn, retry: 1, retryDelay: 1000, }), // Optimistic mutation optimistic: (mutationFn, optimisticUpdate) => ({ mutationFn, retry: 1, retryDelay: 1000, ...(optimisticUpdate && { onMutate: optimisticUpdate, }), }), // Critical mutation (no retry on client errors) critical: (mutationFn) => ({ mutationFn, retry: (failureCount, error) => { if (error?.status >= 400 && error?.status < 500) { return false; } return failureCount < 2; }, retryDelay: 2000, }), }; //# sourceMappingURL=query-client.js.map