# OpenSpec Change: enterprise-currency-providers - **Change ID**: enterprise-currency-providers - **Package**: `@suaveplan/currency-providers` - **Category**: finance - **Target path**: `finance/currency/currency-providers` - **Status**: PROPOSED - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/currency-providers.md` --- ## Summary Deliver `@suaveplan/currency-providers` on the genesis branch from scratch at enterprise quality. The package implements concrete `CurrencyProvider` implementations (from `@suaveplan/currency`) for eight real exchange-rate APIs: three fiat providers (ECB XML feed, Open Exchange Rates, Fixer) and five crypto providers (CoinGecko, CoinMarketCap, Binance, Kraken, CryptoCompare), plus a `VirtualCurrencyProvider`. All HTTP calls go through a shared `fetch` wrapper with timeout, retry via `@suaveplan/retry`, rate-limit header parsing, and in-flight request coalescing. Typed error hierarchy (`AuthError`, `RateLimitError`, `NetworkError`, `ParseError`). Optional `RateLimitedProvider` decorator. --- ## Current-state audit (genesis) Does not exist on genesis — fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | Typed `CURRENCY_PROVIDER.*` error codes | | `@suaveplan/types` (`workspace:^`) | `LoggerLike` | | `@suaveplan/currency` (`workspace:^`) | `CurrencyProvider` interface | | `@suaveplan/retry` (`workspace:^`) | HTTP retry + backoff | | `@suaveplan/logger` (`workspace:^`) | Structured logs | | `zod` (`catalog:forms`) | Response parsing schemas | | `@opentelemetry/api` (`catalog:observability`) | Spans + counters + histograms | | `tslib` (`catalog:build`) | Runtime helpers | --- ## Public API surface ```ts // Fiat providers class EcbProvider implements CurrencyProvider { ... } class FixerProvider implements CurrencyProvider { constructor(config: ApiKeyConfig) } class OpenExchangeRatesProvider implements CurrencyProvider { constructor(config: ApiKeyConfig) } // Crypto providers class BinanceProvider implements CurrencyProvider { ... } class CoinGeckoProvider implements CurrencyProvider { ... } class CoinMarketCapProvider implements CurrencyProvider { constructor(config: ApiKeyConfig) } class CryptoCompareProvider implements CurrencyProvider { ... } class KrakenProvider implements CurrencyProvider { ... } // Virtual class VirtualCurrencyProvider implements CurrencyProvider { ... } // Wrapper class RateLimitedProvider implements CurrencyProvider { constructor(provider: CurrencyProvider, options: RateLimitOptions) } // Errors class ProviderError extends SuaveplanError { ... } class AuthError extends ProviderError { ... } class RateLimitError extends ProviderError { retryAfterMs?: number } class NetworkError extends ProviderError { ... } class ParseError extends ProviderError { ... } // HTTP utilities function createFetchWrapper(options: FetchWrapperOptions): FetchWrapper function coalesce(key: string, fn: () => Promise): Promise ``` --- ## File layout ```text finance/currency/currency-providers/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts types/ provider.types.ts provider.types.md http/ fetch-wrapper/ fetch-wrapper.ts fetch-wrapper.md fetch-wrapper.test.ts index.ts coalesce/ coalesce.ts coalesce.md coalesce.test.ts index.ts fiat/ ecb-provider/ ecb-provider.ts / .md / .test.ts / index.ts fixer-provider/ fixer-provider.ts / .md / .test.ts / index.ts open-exchange-rates-provider/ open-exchange-rates-provider.ts / .md / .test.ts / index.ts crypto/ binance-provider/ ... coingecko-provider/ ... coinmarketcap-provider/ ... cryptocompare-provider/ ... kraken-provider/ ... virtual/ virtual-currency-provider/ ... wrappers/ rate-limited-provider/ ... tests/ integration.test.ts ``` --- ## Impact Requires `@suaveplan/currency` to be published first (implements its `CurrencyProvider` interface). Downstream: `@suaveplan/currency` consumers via the fallback chain. **Prerequisites on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/currency`, `@suaveplan/retry`, `@suaveplan/logger`.