refactor: extract magic constants — wave 2 (TanStack Query defaults)
Promote the duplicated query lifecycle constants in \$shared/api/queryClient.ts: - staleTime (5 minutes) -> DEFAULT_QUERY_STALE_TIME_MS - gcTime (10 minutes) -> DEFAULT_QUERY_GC_TIME_MS - retry (3) -> QUERY_RETRY_COUNT - retryDelay (1s base, 30s cap) -> QUERY_RETRY_BASE_DELAY_MS + QUERY_RETRY_MAX_DELAY_MS fontCatalogStore and availableFilterStore now import the stale/gc constants instead of re-deriving '5 * 60 * 1000' / '10 * 60 * 1000'. fontCatalogStore.svelte.spec.ts's queryClient mock now passes through the new named exports via importOriginal so the consumer's imports resolve.
This commit is contained in:
@@ -19,11 +19,15 @@ import {
|
|||||||
import type { UnifiedFont } from '../../types';
|
import type { UnifiedFont } from '../../types';
|
||||||
import { FontCatalogStore } from './fontCatalogStore.svelte';
|
import { FontCatalogStore } from './fontCatalogStore.svelte';
|
||||||
|
|
||||||
vi.mock('$shared/api/queryClient', () => ({
|
vi.mock('$shared/api/queryClient', async importOriginal => {
|
||||||
|
const actual = await importOriginal<typeof import('$shared/api/queryClient')>();
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
queryClient: new QueryClient({
|
queryClient: new QueryClient({
|
||||||
defaultOptions: { queries: { retry: 0, gcTime: 0 } },
|
defaultOptions: { queries: { retry: 0, gcTime: 0 } },
|
||||||
}),
|
}),
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
vi.mock('../../../api', () => ({ fetchProxyFonts: vi.fn() }));
|
vi.mock('../../../api', () => ({ fetchProxyFonts: vi.fn() }));
|
||||||
|
|
||||||
import { queryClient } from '$shared/api/queryClient';
|
import { queryClient } from '$shared/api/queryClient';
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { queryClient } from '$shared/api/queryClient';
|
import {
|
||||||
|
DEFAULT_QUERY_GC_TIME_MS,
|
||||||
|
DEFAULT_QUERY_STALE_TIME_MS,
|
||||||
|
queryClient,
|
||||||
|
} from '$shared/api/queryClient';
|
||||||
import {
|
import {
|
||||||
type InfiniteData,
|
type InfiniteData,
|
||||||
InfiniteQueryObserver,
|
InfiniteQueryObserver,
|
||||||
@@ -427,8 +431,8 @@ export class FontCatalogStore {
|
|||||||
const next = lastPage.offset + lastPage.limit;
|
const next = lastPage.offset + lastPage.limit;
|
||||||
return next < lastPage.total ? { offset: next } : undefined;
|
return next < lastPage.total ? { offset: next } : undefined;
|
||||||
},
|
},
|
||||||
staleTime: hasFilters ? 0 : 5 * 60 * 1000,
|
staleTime: hasFilters ? 0 : DEFAULT_QUERY_STALE_TIME_MS,
|
||||||
gcTime: 10 * 60 * 1000,
|
gcTime: DEFAULT_QUERY_GC_TIME_MS,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -17,7 +17,11 @@
|
|||||||
|
|
||||||
import { fetchProxyFilters } from '$features/FilterAndSortFonts/api/filters/filters';
|
import { fetchProxyFilters } from '$features/FilterAndSortFonts/api/filters/filters';
|
||||||
import type { FilterMetadata } from '$features/FilterAndSortFonts/api/filters/filters';
|
import type { FilterMetadata } from '$features/FilterAndSortFonts/api/filters/filters';
|
||||||
import { queryClient } from '$shared/api/queryClient';
|
import {
|
||||||
|
DEFAULT_QUERY_GC_TIME_MS,
|
||||||
|
DEFAULT_QUERY_STALE_TIME_MS,
|
||||||
|
queryClient,
|
||||||
|
} from '$shared/api/queryClient';
|
||||||
import {
|
import {
|
||||||
type QueryKey,
|
type QueryKey,
|
||||||
QueryObserver,
|
QueryObserver,
|
||||||
@@ -81,8 +85,8 @@ export class AvailableFilterStore {
|
|||||||
return {
|
return {
|
||||||
queryKey: this.getQueryKey(),
|
queryKey: this.getQueryKey(),
|
||||||
queryFn: () => this.fetchFn(),
|
queryFn: () => this.fetchFn(),
|
||||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
staleTime: DEFAULT_QUERY_STALE_TIME_MS,
|
||||||
gcTime: 10 * 60 * 1000, // 10 minutes
|
gcTime: DEFAULT_QUERY_GC_TIME_MS,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,31 @@
|
|||||||
import { QueryClient } from '@tanstack/query-core';
|
import { QueryClient } from '@tanstack/query-core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TanStack Query client instance
|
* TanStack Query client instance
|
||||||
*
|
*
|
||||||
@@ -15,14 +41,8 @@ import { QueryClient } from '@tanstack/query-core';
|
|||||||
export const queryClient = new QueryClient({
|
export const queryClient = new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
queries: {
|
queries: {
|
||||||
/**
|
staleTime: DEFAULT_QUERY_STALE_TIME_MS,
|
||||||
* Data remains fresh for 5 minutes after fetch
|
gcTime: DEFAULT_QUERY_GC_TIME_MS,
|
||||||
*/
|
|
||||||
staleTime: 5 * 60 * 1000,
|
|
||||||
/**
|
|
||||||
* Unused cache entries are removed after 10 minutes
|
|
||||||
*/
|
|
||||||
gcTime: 10 * 60 * 1000,
|
|
||||||
/**
|
/**
|
||||||
* Don't refetch when window regains focus
|
* Don't refetch when window regains focus
|
||||||
*/
|
*/
|
||||||
@@ -31,15 +51,12 @@ export const queryClient = new QueryClient({
|
|||||||
* Refetch on mount if data is stale
|
* Refetch on mount if data is stale
|
||||||
*/
|
*/
|
||||||
refetchOnMount: true,
|
refetchOnMount: true,
|
||||||
|
retry: QUERY_RETRY_COUNT,
|
||||||
/**
|
/**
|
||||||
* Retry failed requests up to 3 times
|
* Exponential backoff: 1s, 2s, 4s, 8s... capped at 30s
|
||||||
*/
|
*/
|
||||||
retry: 3,
|
retryDelay: attemptIndex =>
|
||||||
/**
|
Math.min(QUERY_RETRY_BASE_DELAY_MS * 2 ** attemptIndex, QUERY_RETRY_MAX_DELAY_MS),
|
||||||
* Exponential backoff for retries
|
|
||||||
* 1s, 2s, 4s, 8s... capped at 30s
|
|
||||||
*/
|
|
||||||
retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user