Files
suaveplan/openspec/archive/2026-05-17-add-currency-provider-cryptocompare/proposal.md
2026-05-27 23:29:53 +01:00

5.8 KiB

Add @suaveplan/currency-provider-cryptocompare sibling provider

Package: @suaveplan/currency-provider-cryptocompare Status: ARCHIVED Type: new package (sibling of slimmed @suaveplan/currency-providers)

  • Spec delta: ./specs/currency-provider-cryptocompare/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 CryptoCompare sibling — a crypto rate source backed by the min-api.cryptocompare.com/data/pricemulti REST endpoint.

CryptoCompare distinguishes itself from the keyed siblings (Fixer, OXR, CoinMarketCap) by being usable fully keyless — the free tier covers ~100,000 calls per month without any auth. Callers that want the higher rate limit can supply an apiKey in the constructor config; the provider attaches it on every request via the authorization: Apikey <key> header per CryptoCompare's documented Apikey scheme.

What changes

ADDED

  • @suaveplan/currency-provider-cryptocompare package at packages/finance/currency-provider-cryptocompare/, version 0.1.0, universal-tier (sideEffects: false).
  • CryptoCompareProvider class implementing CurrencyProvider from @suaveplan/currency. Constructed from CryptoCompareConfig (extends NoKeyConfig: apiKey? + baseUrl? + injectable FetchLike?).
  • supportsCrypto: true, supportsFiat: false, no supportsVirtual. CryptoCompare 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 <baseUrl>/pricemulti?fsyms=<targets>&tsyms=<base> via the shared httpRequest() helper from @suaveplan/currency-providers. The authorization: Apikey <key> header is attached only when config.apiKey is provided and non-whitespace.
  • 15 default crypto symbols (BTC, ETH, SOL, USDT, USDC, BNB, XRP, ADA, DOGE, DOT, AVAX, LINK, UNI, ATOM, LTC) when callers omit targets or pass an empty array. Default base currency: "USD".
  • Response parsing raises CurrencyProviderError(PARSE_ERROR) when the payload is not valid JSON or is not a JSON object.
  • Response parsing raises CurrencyProviderError(UPSTREAM_ERROR) when the payload carries Response: "Error". The Message field (or "unknown upstream error" when absent) is copied to error.upstreamMessage.
  • fetchRates() raises CurrencyProviderError(UNKNOWN_CURRENCY) when no requested symbol produces a finite positive 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 export for ./cryptocompare/cryptocompare.

KEPT (from slim core, consumed unchanged)

  • CurrencyProviderError + CURRENCY_PROVIDER_CODES registry (HTTP_ERROR, PARSE_ERROR, UPSTREAM_ERROR, UNKNOWN_CURRENCY).
  • NoKeyConfig shared config type (extended with the optional apiKey).
  • httpRequest() shared HTTP helper.
  • FetchLike from @suaveplan/types.

Source mapping

Module Source
CryptoCompareProvider ../suaveplan/packages/finance/currency-providers/src/crypto/cryptocompare.ts L1-L69 (upstream class)
Error mapping (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)
Optional API-key header (authorization: Apikey <key>) CryptoCompare public documentation — Apikey auth scheme; not present in the upstream class (which ignored the key entirely)
Inverted-price + zero-skip semantics upstream behaviour preserved (rates[symbol] = 1 / prices[base] when prices[base] > 0)

Impact

Affected dependents

Run bunx turbo ls --filter=...@suaveplan/currency-provider-cryptocompare to enumerate.

  • No current dependents (new sibling package; verified by bunx turbo ls --filter=...@suaveplan/currency-provider-cryptocompare).

The package's only upstream dependencies are @suaveplan/currency-providers (slim core, httpRequest / error registry / NoKeyConfig), @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

  • Historical-rate endpoints (/v2/histoday, /v2/histohour, /v2/histominute), OHLCV, WebSocket streaming. 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.
  • Multi-tsym ("multi-base") queries. pricemulti accepts a CSV tsyms list but the CurrencyProvider contract returns a single-base map; multi-base aggregation belongs in a future wrapper.
  • CryptoCompare-specific metadata endpoints (coin/general, social, news). Out of scope for a rates provider; a future @suaveplan/cryptocompare package can expose those if needed.
  • Fiat rates. CryptoCompare supports fiat tsyms but the sibling stays scoped to crypto (supportsFiat: false) per the slim-core sibling pattern; consumers needing fiat install one of the dedicated fiat siblings.