5.0 KiB
Add @suaveplan/currency-provider-coingecko
Package: @suaveplan/currency-provider-coingecko
Status: PROPOSED
Type: new package (sibling-plugin landing from the
2026-05-17 slim-currency-providers refactor wave)
- Spec delta: ./specs/currency-provider-coingecko/spec.md
Why
@suaveplan/currency-providers was slimmed on 2026-05-17 to a thin foundation
shipping the CurrencyProvider contract, CurrencyProviderRegistry,
defineCurrencyProvider factory, shared httpRequest + composeAbortSignal
HTTP helper, the ApiKeyConfig / NoKeyConfig config shapes, and the typed
CurrencyProviderError + CURRENCY_PROVIDER_CODES registry. The nine
concrete providers (ECB, Fixer, OXR, Binance, CoinGecko, CoinMarketCap,
CryptoCompare, Kraken, Virtual) moved to sibling
@suaveplan/currency-provider-<name> packages so consumers install only what
they wire in and each provider iterates on its own version cadence.
This change lands the CoinGecko sibling. CoinGecko exposes a free public
endpoint (no key, rate-limited at 10–30 calls/min) and a paid Pro tier that
accepts the API key via an x-cg-pro-api-key header. Both shapes share the
same request URL pattern (/simple/price?ids=...&vs_currencies=...) and the
same response shape, so the key is genuinely optional rather than mutually
exclusive — consumers upgrade by passing apiKey without otherwise changing
their wiring.
What changes
ADDED
CoinGeckoProviderclass implementingCurrencyProvider from @suaveplan/currency—name = "coingecko",supportsCrypto = true,supportsFiat = true. Constructor accepts an optional config object of shapeNoKeyConfig & { readonly apiKey?: string }; theapiKeyfield is truly optional (free tier requires nothing).fetchRates(options?)issues a single request through the sharedhttpRequest()helper, attaches thex-cg-pro-api-keyheader iffapiKeywas supplied, parses the JSON body, inverts the upstream price ("1 crypto = X fiat") into the converter's rate convention ("1 base = X crypto"), and filters tooptions.targetswhen given.getCoinGeckoId(symbol)lookup helper exposing the curated symbol → CoinGecko-ID mapping (BTC, ETH, SOL, USDT, USDC, BNB, XRP, ADA, DOGE, DOT, AVAX, MATIC, LINK, UNI, ATOM, LTC). Case-insensitive; returnsundefinedfor unknown symbols.- Failure paths raise
CurrencyProviderError:HTTP_ERROR— non-2xx response (delegated tohttpRequest()).PARSE_ERROR— response body is not valid JSON.UPSTREAM_ERROR— JSON parses but is not the expectedRecord<string, Record<string, number>>shape.UNKNOWN_CURRENCY— caller-suppliedoptions.targetsincludes a symbol with no CoinGecko-ID mapping; raised proactively before the HTTP call so the diagnostic surfaces the bad symbol rather than a silent emptyratesfield.
Source mapping
| Migrated module | Upstream source |
|---|---|
CoinGeckoProvider, getCoinGeckoId |
../suaveplan/packages/finance/currency-providers/src/crypto/coingecko.ts |
Upstream used a bare fetch call, bare Error, and no key support. This
migration upgrades all three: routes through the shared httpRequest
helper (so abort-signal composition + per-call timeouts + typed
HTTP_ERROR come for free), raises typed CurrencyProviderErrors with
stable codes (so consumers can dispatch on err.code), and adds the
optional apiKey field with x-cg-pro-api-key header attachment for
the Pro tier.
Impact
Affected dependents
Run bunx turbo ls --filter=...@suaveplan/currency-provider-coingecko to
enumerate. As this is a new package, the dependent list is empty at
landing.
- No current dependents (new package; verified by
bunx turbo ls --filter=...@suaveplan/currency-provider-coingecko).
The package consumes (does not modify):
@suaveplan/currency—CurrencyProvider,RateFetchOptions,RateFetchResultcontract types only. [x] no action needed (contract consumer, not modifier).@suaveplan/currency-providers—httpRequest,composeAbortSignal,CurrencyProviderError,CURRENCY_PROVIDER_CODES,NoKeyConfig. [x] no action needed (slim core is the surface this package is built against).@suaveplan/types—FetchLike. [x] no action needed.@suaveplan/error— transitively viaCurrencyProviderError's base class. [x] no action needed.
Out of scope
- Historical-rate queries (
/coins/{id}/history), trending coins, market cap data —CurrencyProvideronly contracts for spot rates. - WebSocket / push subscriptions — CoinGecko does not offer a public WebSocket; sibling providers that do (Binance, Kraken) own that surface.
- Auto-discovery of CoinGecko IDs beyond the curated 16-entry map — consumers needing a different symbol register it via their own wrapper or open a follow-up change extending the map.
- Rate-limit awareness, retry, OTel instrumentation — same deferral as the slim core and every other sibling provider; once those wrappers land they apply uniformly via the registry.