Commit Graph

109 Commits

Author SHA1 Message Date
Ilia Mashkov 7f20f36d0a fix(api): mark schema-validation errors as non-retryable
The proxy returned `{fonts: null, total: 0}` for empty results, which
fetchProxyFonts surfaced as a generic Error. fontCatalogStore wrapped it
as FontNetworkError, and TanStack retried 3× with exponential backoff —
pinning the loading skeleton for ~7s before settling on an empty list.

Schema mismatches are deterministic; retrying only delays surfacing the
contract violation.

- shared/api/queryClient: introduce NonRetryableError marker class.
  The default retry handler short-circuits when it sees this so any
  store using the shared client gets fail-fast behavior for free.
- entities/Font/lib/errors: FontResponseError extends NonRetryableError.
- entities/Font/api/proxy/proxyFonts: throw FontResponseError (was a
  bare Error). Document that ProxyFontsResponse.fonts is always an array.
- entities/Font/.../fontCatalogStore.fetchPage: preserve a
  FontResponseError raised lower in the stack instead of re-wrapping
  it as FontNetworkError.
- features/FilterAndSortFonts/api/filters: throw NonRetryableError on
  invalid filters payloads and document the array-never-null contract.
2026-05-28 21:37:23 +03:00
Ilia Mashkov 2bb43797f0 refactor: extract magic constants — wave 3 (font lifecycle)
Promote font-loading scheduling and lifecycle tunables to named
module-level constants:

- comparisonStore: FONT_READY_FALLBACK_MS (1000ms) — UI unblock safety net
- fontLifecycleManager:
  - PURGE_INTERVAL_MS (60000) — periodic eviction sweep
  - IDLE_CALLBACK_TIMEOUT_MS (150) — requestIdleCallback timeout
  - SCHEDULE_FALLBACK_MS (16) — setTimeout fallback (~60fps)
  - YIELD_INTERVAL_MS (8) — parse-loop yield budget for non-Chromium
  - CRITICAL_FONT_WEIGHTS ([400, 700]) — data-saver allowlist
- FontEvictionPolicy: DEFAULT_FONT_TTL_MS (5 minutes)
- FontLoadQueue: FONT_LOAD_MAX_RETRIES (3)

No behavior changes — values preserved exactly. Class-private fields
that mirrored these constants are removed in favor of module scope.
2026-05-24 21:13:38 +03:00
Ilia Mashkov ccef3cf7bb 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.
2026-05-24 20:33:46 +03:00
Ilia Mashkov 728380498b refactor(Font): rename fontStore and appliedFontsManager
Both names were vague or overloaded:

- fontStore / FontStore -> fontCatalogStore / FontCatalogStore
  Three font-related stores live in this slice; the new name names the
  paginated catalog specifically.

- appliedFontsManager / AppliedFontsManager -> fontLifecycleManager /
  FontLifecycleManager
  "Applied" collided with the filter-side appliedFilterStore (different
  meaning). The class actually orchestrates a load-use-evict lifecycle
  with FontBufferCache + FontEvictionPolicy + FontLoadQueue
  collaborators, so "Manager" is justified. Companion types file moved
  alongside (appliedFonts.ts -> fontLifecycle.ts).

Directories, file basenames, factory (createFontStore ->
createFontCatalogStore), and the AppliedFontsManagerDeps interface all
renamed. All consumers (ComparisonView, SampleList, FontList,
FontApplicator, FontVirtualList, FilterAndSortFonts bindings,
createFontRowSizeResolver, mocks) updated.
2026-05-24 20:00:43 +03:00
Ilia Mashkov 07d044f4d6 refactor: extract BatchFontStore into new FetchFontsByIds feature
The byId font fetch was a verb-oriented capability with a single
consumer driven by a feature need (materializing comparison picks).
That shape belongs at the feature layer, not on the entity.

Move:
- entities/Font/model/store/batchFontStore -> features/FetchFontsByIds/model/store/fontsByIdsStore
- Class BatchFontStore -> FontsByIdsStore

entities/Font retains the transport primitives (fetchFontsByIds,
seedFontCache) and the keyspace (fontKeys); the feature wraps them in
the reactive store. comparisonStore now imports FontsByIdsStore from
the new feature. The proxy API is imported via direct path so vi.spyOn
on the source module still observes the call.
2026-05-24 19:41:40 +03:00
Ilia Mashkov 1573950605 chore(Font): move batchFontStore to separate directory 2026-05-24 13:54:15 +03:00
Ilia Mashkov 0d4356b8f1 chore: remove @ts-expect-error since scheduler was added in new TS release 2026-05-05 17:03:18 +03:00
Ilia Mashkov d6914f8179 feat(FontStore): add fetchAllPagesTo for parallel batch page loading 2026-04-22 09:01:45 +03:00
Ilia Mashkov 67fc9dee72 fix(FontList): address the bug with selected font transition animations 2026-04-20 13:36:05 +03:00
Ilia Mashkov 12e8bc0a89 chore: enforce brackets for if clause and for/while loops 2026-04-17 13:05:36 +03:00
Ilia Mashkov cfaff46d59 chore: follow the general comments style 2026-04-17 12:14:55 +03:00
Ilia Mashkov dde187e0b2 chore: move ControlId type to the entities/Font layer 2026-04-16 11:19:17 +03:00
Ilia Mashkov db08f523f6 chore: move typography constants to the entity/Font layer 2026-04-16 09:05:34 +03:00
Ilia Mashkov cd349aec92 fix: imports 2026-04-15 22:32:45 +03:00
Ilia Mashkov adaa6d7648 feat: refactor ComparisonStore to use BatchFontStore
Replace hand-rolled async fetching (fetchFontsByIds + isRestoring flag)
with BatchFontStore backed by TanStack Query. Three reactive effects
handle batch sync, CSS font loading, and default-font fallback.
isLoading now derives from batchStore.isLoading + fontsReady.
2026-04-15 22:25:34 +03:00
Ilia Mashkov 10f4781a67 test: enrich coverage for queryKeys, BaseQueryStore, and BatchFontStore
- queryKeys: add mutation-safety test for batch(), key hierarchy tests
  (list/batch/detail keys rooted in their parent base keys), and
  unique-key test for different detail IDs
- BaseQueryStore: add initial-state test (data undefined, isError false
  before any fetch resolves)
- BatchFontStore: add FontResponseError type assertion on malformed
  response, null error assertion on success, and setIds([]) disables
  query and returns empty fonts without triggering a fetch
2026-04-15 15:59:01 +03:00
Ilia Mashkov f4a568832a feat: implement reactive BatchFontStore 2026-04-15 12:29:16 +03:00
Ilia Mashkov d9fa2bc501 refactor: consolidate font domain and model types into font.ts
Workflow / build (pull_request) Successful in 59s
Workflow / publish (pull_request) Has been skipped
2026-04-10 17:29:15 +03:00
Ilia Mashkov 5f38996665 chore: purge legacy font provider types and normalization logic 2026-04-10 16:05:57 +03:00
Ilia Mashkov dc6e15492a test: mock fontStore and update FontStore type signatures 2026-04-09 19:40:31 +03:00
Ilia Mashkov 45eac0c396 refactor: delete BaseFontStore and UnifiedFontStore — FontStore is the single implementation 2026-04-08 10:07:36 +03:00
Ilia Mashkov 468d2e7f8c feat(FontStore): export through entity barrel files 2026-04-08 09:55:40 +03:00
Ilia Mashkov 2a761b9d47 feat(FontStore): implement lifecycle, param management, async methods, shortcuts, pagination, category getters, singleton — all tests green 2026-04-08 09:54:27 +03:00
Ilia Mashkov a9e4633b64 feat(FontStore): implement fetchPage with error wrapping 2026-04-08 09:50:16 +03:00
Ilia Mashkov 778988977f feat(FontStore): implement state getters, pagination, buildQueryKey, buildOptions 2026-04-08 09:47:25 +03:00
Ilia Mashkov 9a9ff95bf3 test(FontStore): write full TDD spec and empty shell (InfiniteQueryObserver) 2026-04-08 09:43:29 +03:00
Ilia Mashkov 752e38adf9 test: full test coverage of baseFontStore and unifiedFontStore
Workflow / build (pull_request) Successful in 55s
Workflow / publish (pull_request) Has been skipped
2026-04-08 09:33:04 +03:00
Ilia Mashkov 9c538069e4 test(UnifiedFontStore): add isEmpty and destroy tests 2026-04-06 12:26:08 +03:00
Ilia Mashkov 71fed58af9 test(UnifiedFontStore): add category getter tests 2026-04-06 12:24:23 +03:00
Ilia Mashkov fee3355a65 test(UnifiedFontStore): add filter change reset tests 2026-04-06 12:19:49 +03:00
Ilia Mashkov 2ff7f1a13d test(UnifiedFontStore): add filter setter tests 2026-04-06 11:35:56 +03:00
Ilia Mashkov 6bf1b1ea87 test(UnifiedFontStore): add pagination navigation tests 2026-04-06 11:34:53 +03:00
Ilia Mashkov 3ef012eb43 test(UnifiedFontStore): add pagination state tests 2026-04-06 11:34:03 +03:00
Ilia Mashkov 5df60b236c test(UnifiedFontStore): cover fetchFn typed error paths and error getter 2026-04-05 15:20:15 +03:00
Ilia Mashkov df3c694909 feat(UnifiedFontStore): throw FontNetworkError and FontResponseError in fetchFn 2026-04-05 14:07:26 +03:00
Ilia Mashkov a1a1fcf39d feat(BaseFontStore): expose error getter 2026-04-05 11:03:00 +03:00
Ilia Mashkov b40e651be4 refactor(Font/model): move baseFontStore and unifiedFontStore to subdirectories, rename errors/index to errors/errors 2026-04-05 11:02:42 +03:00
Ilia Mashkov c6dabafd93 chore(appliedFontsStore): move FontBufferCache, FontEvicionPolicy and FontLoadQueue to appliedFontsStore/utils 2026-04-05 08:25:05 +03:00
Ilia Mashkov e88cca9289 test(FontBufferCache): change mock fetcher type 2026-04-04 16:43:54 +03:00
Ilia Mashkov d4cf6764b4 test(appliedFontsStore): rewrite tests with describe grouping and full coverage 2026-04-04 10:38:20 +03:00
Ilia Mashkov 5a065ae5a1 refactor: extract #fetchChunk, replace Promise.allSettled with self-describing results 2026-04-04 09:58:41 +03:00
Ilia Mashkov 20110168f2 refactor: extract #processFont and #scheduleProcessing from touch and #processQueue 2026-04-04 09:52:45 +03:00
Ilia Mashkov f88729cc77 fix: guard AbortError from retry counting; eviction policy removes stale keys 2026-04-04 09:40:21 +03:00
Ilia Mashkov d21de1bf78 chore(appliedFontsStore): use created collaborators classes 2026-04-03 16:09:10 +03:00
Ilia Mashkov 37e0c29788 refactor: loadFont throws FontParseError instead of re-throwing raw error 2026-04-03 15:42:08 +03:00
Ilia Mashkov 46ce0f7aab feat: extract FontBufferCache with injectable fetcher 2026-04-03 15:24:14 +03:00
Ilia Mashkov 128f341399 feat: extract FontEvictionPolicy with TTL and pin/unpin 2026-04-03 15:06:01 +03:00
Ilia Mashkov 64b97794a6 feat: extract FontLoadQueue with retry tracking 2026-04-03 15:01:36 +03:00
Ilia Mashkov d6eb02bb28 feat: add FontFetchError and FontParseError typed errors 2026-04-03 14:44:06 +03:00
Ilia Mashkov a711e4e12a chore(appliedFontsStore): move generateFontKey into separate function and cover it with tests 2026-04-03 12:50:50 +03:00