# Add @suaveplan/currency-provider-coinmarketcap sibling provider **Package**: `@suaveplan/currency-provider-coinmarketcap` **Status**: PROPOSED **Type**: new package (sibling of slimmed `@suaveplan/currency-providers`) - **Spec delta**: ./specs/currency-provider-coinmarketcap/spec.md ## Why The 2026-05-17 `slim-currency-providers` refactor moved the nine concrete provider classes out of `@suaveplan/currency-providers` and committed each one to its own publishable sibling package. This change lands the `CoinMarketCap` sibling — a crypto rate source backed by the `pro-api.coinmarketcap.com` REST API and authenticated through the `X-CMC_PRO_API_KEY` HTTP header. Consumers that already register sibling providers via `CurrencyProviderRegistry` (or instantiate them directly into `CurrencyConverter`) gain a CoinMarketCap option without installing eight other provider packages they do not wire in. ## What changes ### ADDED - `@suaveplan/currency-provider-coinmarketcap` package at `packages/finance/currency-provider-coinmarketcap/`, version `0.1.0`, universal-tier (`sideEffects: false`). - `CoinMarketCapProvider` class implementing `CurrencyProvider` from `@suaveplan/currency`. Constructed from `ApiKeyConfig` (`apiKey`, optional `baseUrl`, optional injectable `FetchLike` from `@suaveplan/types`). - `supportsCrypto: true`, `supportsFiat: false`, no `supportsVirtual`. CoinMarketCap is a crypto-rates source — fiat rates are out of scope for this sibling (consumers wanting fiat install `currency-provider-ecb` / `currency-provider-fixer` / `currency-provider-open-exchange-rates`). - `fetchRates(options?)` calls `GET /cryptocurrency/quotes/latest?symbol=&convert=` via the shared `httpRequest()` helper from `@suaveplan/currency-providers`. The `X-CMC_PRO_API_KEY` header carries `config.apiKey`; the `Accept` header is `application/json`. - Constructor raises `CurrencyProviderError(MISSING_CONFIG)` when `config.apiKey` is empty or whitespace-only (consistent with the `ApiKeyConfig` contract documented in the slim core). - Response parsing raises `CurrencyProviderError(PARSE_ERROR)` when the payload is not valid JSON or the `data` map is missing / wrong shape. - Response parsing raises `CurrencyProviderError(UPSTREAM_ERROR)` when the upstream payload contains a non-null `status.error_code` field. - `fetchRates()` raises `CurrencyProviderError(UNKNOWN_CURRENCY)` when none of the requested target symbols resolve to a quote in the configured `base` currency. - Non-2xx HTTP responses surface as `CurrencyProviderError(HTTP_ERROR)` (raised by the shared `httpRequest()` helper, with `status` populated). - README, sibling `.md` per implementation file, and subpath exports for `./coinmarketcap/coinmarketcap`. ### KEPT (from slim core, consumed unchanged) - `CurrencyProviderError` + `CURRENCY_PROVIDER_CODES` registry (`HTTP_ERROR`, `PARSE_ERROR`, `UPSTREAM_ERROR`, `MISSING_CONFIG`, `UNKNOWN_CURRENCY`). - `ApiKeyConfig` shared config type. - `httpRequest()` shared HTTP helper. - `FetchLike` from `@suaveplan/types`. ## Source mapping | Module | Source | |---|---| | `CoinMarketCapProvider` | `../suaveplan/packages/finance/currency-providers/src/crypto/coinmarketcap.ts` L1-L61 (upstream class) | | Error mapping (`MISSING_CONFIG` / `PARSE_ERROR` / `UPSTREAM_ERROR` / `UNKNOWN_CURRENCY`) | genesis-original — upstream threw raw `Error`; the slim core's typed `CurrencyProviderError` registry replaces that | | `httpRequest` / `composeAbortSignal` plumbing | `@suaveplan/currency-providers/src/http/http.ts` (slim core, genesis-original) | | Symbol-based crypto query shape | upstream behaviour preserved (`symbol=&convert=` against `/v1/cryptocurrency/quotes/latest`) | ## Impact ### Affected dependents Run `bunx turbo ls --filter=...@suaveplan/currency-provider-coinmarketcap` to enumerate. - No current dependents (new sibling package; verified by `bunx turbo ls --filter=...@suaveplan/currency-provider-coinmarketcap`). The package's only upstream dependencies are `@suaveplan/currency-providers` (slim core, registry / factory / HTTP helper / error registry / configs), `@suaveplan/currency` (the `CurrencyProvider` contract), `@suaveplan/types` (`FetchLike`), `@suaveplan/error` (transitive), and `tslib`. None of those packages need to be touched by this change — the sibling consumes their public surfaces unchanged. ## Out of scope - Fiat conversion endpoints. CoinMarketCap exposes `/v1/fiat/map` and `/v2/tools/price-conversion` but this sibling stays scoped to the crypto quotes endpoint (`supportsFiat: false`). A fiat follow-up can land separately if a real consumer needs it. - Historical-rate endpoints, OHLCV, WebSocket streams. Same deferral as every other sibling provider — interface extension lands once `@suaveplan/currency`'s `CurrencyProvider` contract grows the slots. - Rate-limit and retry orchestration. Deferred to `@suaveplan/rate-limiter` and `@suaveplan/retry` integrations once those wrappers land — every sibling provider gains them uniformly through a single composition. - CoinMarketCap-specific helper utilities (rank, market-cap weighting, metadata). Out of scope for a rates provider; a future `@suaveplan/coinmarketcap` package can expose those if needed.