Files
2026-05-27 23:29:53 +01:00

5.0 KiB
Raw Permalink Blame History

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

  • CoinGeckoProvider class implementing CurrencyProvider from @suaveplan/currency — name = "coingecko", supportsCrypto = true, supportsFiat = true. Constructor accepts an optional config object of shape NoKeyConfig & { readonly apiKey?: string }; the apiKey field is truly optional (free tier requires nothing).
  • fetchRates(options?) issues a single request through the shared httpRequest() helper, attaches the x-cg-pro-api-key header iff apiKey was 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 to options.targets when 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; returns undefined for unknown symbols.
  • Failure paths raise CurrencyProviderError:
    • HTTP_ERROR — non-2xx response (delegated to httpRequest()).
    • PARSE_ERROR — response body is not valid JSON.
    • UPSTREAM_ERROR — JSON parses but is not the expected Record<string, Record<string, number>> shape.
    • UNKNOWN_CURRENCY — caller-supplied options.targets includes a symbol with no CoinGecko-ID mapping; raised proactively before the HTTP call so the diagnostic surfaces the bad symbol rather than a silent empty rates field.

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, RateFetchResult contract 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 via CurrencyProviderError's base class. [x] no action needed.

Out of scope

  • Historical-rate queries (/coins/{id}/history), trending coins, market cap data — CurrencyProvider only 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.