Files
frontend-svelte/src/shared/api/queryClient.ts
T

78 lines
2.4 KiB
TypeScript
Raw Normal View History

2026-01-13 19:49:51 +03:00
import { QueryClient } from '@tanstack/query-core';
/**
* Marker base class for errors that retrying will never fix — schema-validation
* failures, unauthorized responses, contract violations, etc.
*
* The queryClient retry handler short-circuits when it sees this; without it,
* a non-transient backend bug pins the UI through the full retry budget
* (default 3× exponential backoff ≈ 7s).
*/
export class NonRetryableError extends Error {}
/**
* Data remains fresh for this long after fetch. Stores that override
* staleness (e.g. filtered queries) can use 0 to bypass.
*/
export const DEFAULT_QUERY_STALE_TIME_MS = 5 * 60 * 1000;
/**
* Unused cache entries are garbage collected after this long.
*/
export const DEFAULT_QUERY_GC_TIME_MS = 10 * 60 * 1000;
/**
* How many times a failed query is retried before surfacing the error.
*/
export const QUERY_RETRY_COUNT = 3;
/**
* Base delay for exponential retry backoff.
*/
export const QUERY_RETRY_BASE_DELAY_MS = 1000;
/**
* Upper bound on retry delay regardless of attempt index.
*/
export const QUERY_RETRY_MAX_DELAY_MS = 30000;
2026-01-13 19:49:51 +03:00
/**
* TanStack Query client instance
*
* Configured for optimal caching and refetching behavior.
* Used by all font stores for data fetching and caching.
*
* Cache behavior:
* - Data stays fresh for 5 minutes (staleTime)
* - Unused data is garbage collected after 10 minutes (gcTime)
* - No refetch on window focus (reduces unnecessary network requests)
* - 3 retries with exponential backoff on failure
2026-01-13 19:49:51 +03:00
*/
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: DEFAULT_QUERY_STALE_TIME_MS,
gcTime: DEFAULT_QUERY_GC_TIME_MS,
2026-04-17 12:14:55 +03:00
/**
* Don't refetch when window regains focus
*/
2026-01-13 19:49:51 +03:00
refetchOnWindowFocus: false,
2026-04-17 12:14:55 +03:00
/**
* Refetch on mount if data is stale
*/
2026-01-13 19:49:51 +03:00
refetchOnMount: true,
retry: (failureCount, error) => {
if (error instanceof NonRetryableError) {
return false;
}
return failureCount < QUERY_RETRY_COUNT;
},
2026-04-17 12:14:55 +03:00
/**
* Exponential backoff: 1s, 2s, 4s, 8s... capped at 30s
2026-01-13 19:49:51 +03:00
*/
retryDelay: attemptIndex =>
Math.min(QUERY_RETRY_BASE_DELAY_MS * 2 ** attemptIndex, QUERY_RETRY_MAX_DELAY_MS),
2026-01-13 19:49:51 +03:00
},
},
});