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.
createFontRowSizeResolver was reaching into TextLayoutEngine, which
internally called pretext's heavy layoutWithLines and then walked
per-grapheme cursors to build chars arrays. The resolver discarded all
that work and used only totalHeight.
Replace with direct prepare + layout from @chenglou/pretext — pretext
docs explicitly recommend layout() (not layoutWithLines) for the resize
hot path: pure arithmetic on cached segment widths, no canvas calls, no
string allocations.
Test spies on TextLayoutEngine.prototype.layout migrated to vi.mock-ed
pretext layout (pretext's ESM exports are frozen — vi.spyOn fails with
"Cannot redefine property").
TextLayoutEngine marked @deprecated since it has no remaining
consumers; slated for removal after a release cycle.
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.