Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -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.