Initial Commit
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
# 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 `CurrencyProviderError`s 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.
|
||||
Reference in New Issue
Block a user