114 lines
5.8 KiB
Markdown
114 lines
5.8 KiB
Markdown
# 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.
|