# @suaveplan/currency-providers - Universal slim core for currency providers: CurrencyProviderRegistry, defineCurrencyProvider factory, shared httpRequest/composeAbortSignal helper, typed CurrencyProviderError + 8-code registry, and the ApiKeyConfig / NoKeyConfig / HttpFetchOptions / ProviderConfigBase shared types. Concrete providers (ECB, Fixer, Open Exchange Rates, Binance, CoinGecko, CoinMarketCap, CryptoCompare, Kraken, Virtual) ship as sibling @suaveplan/currency-provider- packages. Slim plugin core for `@suaveplan/currency` rate providers. Ships the `CurrencyProviderRegistry` (name-keyed lookup), the `defineCurrencyProvider` factory, the shared `httpRequest` / `composeAbortSignal` helper, the typed `CurrencyProviderError` with the 8-code `CURRENCY_PROVIDER_*` registry, and the four shared config types (`ApiKeyConfig`, `NoKeyConfig`, `HttpFetchOptions`, `ProviderConfigBase`) that every sibling provider extends. The concrete provider classes (ECB, Fixer, Open Exchange Rates, Binance, CoinGecko, CoinMarketCap, CryptoCompare, Kraken, Virtual) live in sibling `@suaveplan/currency-provider-` packages — install only the ones you wire in. ## Documentation tree - [error-codes](./src/error-codes/error-codes.md) — Defines the stable `CURRENCY_PROVIDER_CODES` registry and the `CurrencyProviderError` class every provider in `@suavepl… - [error-codes](./src/error-codes/error-codes.md) — Defines the stable `CURRENCY_PROVIDER_CODES` registry and the `CurrencyProviderError` class every provider in `@suavepl… - [factory](./src/factory/factory.md) — Exposes `defineCurrencyProvider`, the low-ceremony factory that sibling `@suaveplan/currency-provider-` packages… - [factory](./src/factory/factory.md) — Exposes `defineCurrencyProvider`, the low-ceremony factory that sibling `@suaveplan/currency-provider-` packages… - [http](./src/http/http.md) — Exposes the two HTTP utilities every sibling `@suaveplan/currency-provider-` package repeats: `httpRequest` (an a… - [http](./src/http/http.md) — Exposes the two HTTP utilities every sibling `@suaveplan/currency-provider-` package repeats: `httpRequest` (an a… - [registry](./src/registry/registry.md) — Defines `CurrencyProviderRegistry`, the in-memory registry that sibling `@suaveplan/currency-provider-` packages… - [registry](./src/registry/registry.md) — Defines `CurrencyProviderRegistry`, the in-memory registry that sibling `@suaveplan/currency-provider-` packages… - [types](./src/types/configs.md) — Defines the three configuration interfaces every concrete provider in `@suaveplan/currency-providers` consumes: `ApiKey… - [configs](./src/types/configs.md) — Defines the three configuration interfaces every concrete provider in `@suaveplan/currency-providers` consumes: `ApiKey… ## Install ```bash bun add @suaveplan/currency-providers @suaveplan/currency # plus whichever sibling provider packages you need: bun add @suaveplan/currency-provider-ecb @suaveplan/currency-provider-coingecko ``` ## Quick start ```ts import { CurrencyConverter } from "@suaveplan/currency"; import { CurrencyProviderRegistry } from "@suaveplan/currency-providers"; import { EcbProvider } from "@suaveplan/currency-provider-ecb"; import { CoinGeckoProvider } from "@suaveplan/currency-provider-coingecko"; const registry = new CurrencyProviderRegistry(); registry.register(new EcbProvider()); registry.register(new CoinGeckoProvider()); const converter = new CurrencyConverter({ provider: registry.get("ecb"), fallbackProviders: [registry.get("coingecko")], }); const rate = await converter.getRate("USD", "EUR"); ``` Direct instantiation without the registry is equally supported — the registry is a convenience for callers that wire many providers and want a single lookup surface. Sibling packages remain `CurrencyProvider`-compatible so `new CurrencyConverter({ provider: new EcbProvider() })` continues to work. ## Features - `CurrencyProviderRegistry` — register / get / has / list / unregister. Typed `PROVIDER_NOT_REGISTERED` / `PROVIDER_ALREADY_REGISTERED` errors; `list()` returns a sorted snapshot for deterministic downstream tests - `defineCurrencyProvider` — factory for sibling packages that prefer the object-literal idiom over a hand-rolled class. Returns an `Object.freeze`-d `CurrencyProvider` - `httpRequest` — shared HTTP helper used by every sibling provider: abort-signal composition, timeout derivation, non-2xx → `HTTP_ERROR` mapping, returns the raw `Response` - `composeAbortSignal` — pure four-way composition of caller + timeout `AbortSignal`s (`undefined`, single, single, `AbortSignal.any`) - Typed `CurrencyProviderError` extending `SuaveplanError` with 8 stable codes (`HTTP_ERROR`, `PARSE_ERROR`, `UPSTREAM_ERROR`, `UNSUPPORTED_BASE`, `MISSING_CONFIG`, `UNKNOWN_CURRENCY`, `PROVIDER_NOT_REGISTERED`, `PROVIDER_ALREADY_REGISTERED`) - Shared config types — `ApiKeyConfig`, `NoKeyConfig`, `HttpFetchOptions`, `ProviderConfigBase` with optional injectable `FetchLike` - Universal — zero browser/Node APIs, runs unchanged under Node ≥ 18, Bun, modern browsers, and Web Workers - Five subpath exports; explicit named barrels; 100/100/100/100 istanbul coverage ## Modules - [`src/error-codes/error-codes.md`](./src/error-codes/error-codes.md) — `CURRENCY_PROVIDER_CODES` registry + `CurrencyProviderError` class - [`src/types/configs.md`](./src/types/configs.md) — `ApiKeyConfig`, `NoKeyConfig`, `HttpFetchOptions`, `ProviderConfigBase` - [`src/registry/registry.md`](./src/registry/registry.md) — `CurrencyProviderRegistry` - [`src/factory/factory.md`](./src/factory/factory.md) — `defineCurrencyProvider` factory + `DefineCurrencyProviderInput` - [`src/http/http.md`](./src/http/http.md) — `httpRequest` + `composeAbortSignal` shared HTTP helpers ## Sibling provider packages | Provider | Sibling package | |--------------------------|-------------------------------------------------------| | European Central Bank | `@suaveplan/currency-provider-ecb` | | Fixer.io | `@suaveplan/currency-provider-fixer` | | Open Exchange Rates | `@suaveplan/currency-provider-open-exchange-rates` | | Binance | `@suaveplan/currency-provider-binance` | | CoinGecko | `@suaveplan/currency-provider-coingecko` | | CoinMarketCap | `@suaveplan/currency-provider-coinmarketcap` | | CryptoCompare | `@suaveplan/currency-provider-cryptocompare` | | Kraken | `@suaveplan/currency-provider-kraken` | | Virtual (game / loyalty) | `@suaveplan/currency-provider-virtual` | Each sibling depends on this slim core for the registry, factory, HTTP helper, error class, and config types — and re-implements only its own provider-specific logic. ## Status `0.1.0` (pre-graduation). Slim refactor of the 2026-05-17 migration: provider classes moved out to sibling packages; the registry / factory / HTTP helper landed here. See the design proposal for the refactor record and migration notes.