unified client
Three layers. Comment in cards.ts: compose sub-endpoints so there is one loop, no all-in-one card route. Comment in useCards.ts: components never fetch; hooks own keys.
Layer A: envelope client#
src/api/unifiedClient.ts
PLATFORM_BASE:VITE_*_APIor/api/{platform}platformUrlencodes the handle, optional path, optional query (view,year)getJson: 429 readsRetry-After(header or body). Other errors prefermessagethendetail- Envelope failure if
status === 'error'orerror === trueorsuccess === false windowUnifiedHeatmapslices year / last 365 / all, then recomputes streaks. Detail pages use this. Aggregated profile mostly windows again on the fullview=allpayload.
Layer B: composed card#
src/api/cards.ts fetchCard:
- Six endpoints in parallel: profile, stats, contests, rating, heatmap, badges. Not summary.
- One failure becomes an empty stub. All six failing throws the first error.
- Empty stubs keep keys:
null/[]/{}. - Category ternary: GitHub →
development, Codeforces/CodeChef →competitive, everything else →dsa. Schema still lists GFG and HackerRank asfundamentals. The client does not.
Layer C: platform adapters#
Deep-dive pages want native shapes (pinned repos, GFG School/Basic, CodeChef stars).
| File | Card? | Extra |
|---|---|---|
github.ts |
yes | /pinned, /stars, /prs, /org-contributions, /profile-views. Failures fall back via ghJSON |
leetcode.ts |
mixed | leftover envelope fields (easySolved, submissionCalendar) |
codeforces.ts |
yes | GET /contests/upcoming |
gfg.ts |
yes | maps byDifficulty.school/basic/... |
codechef.ts |
yes | rating color bands in the client |
hackerrank.ts |
like LeetCode | legacy envelope fields |
tuf.ts |
card only | comment: TUF has no native extras |
useProfileCards flattens comma-separated handles (splitAccounts) into one query per account. Stacked accounts are first-class.