@molecule/api-fx-rates-ecb
v1.0.1
Published
European Central Bank reference FX rates provider for molecule.dev (free, keyless, EUR pivot)
Maintainers
Readme
@molecule/api-fx-rates-ecb
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
ECB FX-rates provider for molecule.dev.
Implements the {@link import('@molecule/api-fx-rates').FxRatesProvider}
interface against the European Central Bank's public reference-rate XML
feeds (eurofxref-daily.xml and eurofxref-hist-90d.xml). Both feeds are
keyless, free, and EUR-pivoted. Cross-rates are computed by pivoting
through EUR (USD->GBP = rates[GBP] / rates[USD]).
Snapshots are cached in memory for a configurable TTL (default 1h) and,
when the 'cache' bond is registered, written through to it as well.
Quick Start
import { setProvider } from '@molecule/api-fx-rates'
import { provider } from '@molecule/api-fx-rates-ecb'
setProvider(provider)Type
provider
Installation
npm install @molecule/api-fx-rates-ecb @molecule/api-bond @molecule/api-fx-rates fast-xml-parserAPI
Interfaces
EcbDailySnapshot
A single daily snapshot of EUR-pivot reference rates parsed from the ECB
XML feed. The pivot (EUR) itself is included with rate 1.
interface EcbDailySnapshot {
/**
* The publication date of the snapshot (UTC midnight on the publication day).
*/
asOf: Date
/**
* Map from currency code to rate, where `1 EUR = rates[code] units of code`.
* Always contains the `EUR` entry with rate `1`.
*/
rates: Record<string, number>
}EcbFxRatesConfig
Configuration options for the ECB FX-rates provider.
The European Central Bank's daily and 90-day-history reference-rate XML
feeds (https://www.ecb.europa.eu/stats/eurofxref/) are keyless and free,
so every field is optional.
interface EcbFxRatesConfig {
/**
* Base URL override. Defaults to `'https://www.ecb.europa.eu/stats/eurofxref'`.
*/
baseUrl?: string
/**
* Daily-feed XML filename. Defaults to `'eurofxref-daily.xml'`. Used when
* the caller does not request an `asOf` date or requests a date the daily
* snapshot already covers.
*/
dailyPath?: string
/**
* Historical 90-day-feed XML filename. Defaults to
* `'eurofxref-hist-90d.xml'`. Used when the caller requests an `asOf` date
* older than the latest snapshot.
*/
historicalPath?: string
/**
* Request timeout in milliseconds. Defaults to `10000`.
*/
timeout?: number
/**
* TTL for the in-memory cache of parsed snapshots, in milliseconds.
* Defaults to `3_600_000` (1 hour). Set to `0` to disable internal caching.
*
* If the `'cache'` bond is registered, snapshots are also written through
* to it with the equivalent TTL in seconds.
*/
cacheTtlMs?: number
}Functions
computeRate(snapshot, from, to)
Computes the conversion rate 1 unit of from = rate units of to from a
EUR-pivot snapshot. Both sides may equal the pivot.
function computeRate(snapshot: EcbDailySnapshot, from: string, to: string): numbersnapshot— The dated snapshot to read.from— Source currency.to— Target currency.
Returns: The conversion ratio as a plain number.
createProvider(config)
Creates an ECB FX-rates provider.
function createProvider(config?: EcbFxRatesConfig): FxRatesProviderconfig— Provider configuration. All fields are optional.
Returns: An {@link FxRatesProvider} backed by the ECB reference-rate feeds.
parseEcbXml(xml)
Parses the body of an ECB XML feed (daily or historical) into an array of snapshots, sorted newest-first.
function parseEcbXml(xml: string): EcbDailySnapshot[]xml— Raw XML body fetched from the ECB endpoint.
Returns: Snapshots sorted newest-first.
Constants
provider
Default ECB FX-rates provider, lazily constructed on first access.
Reads the optional ECB_FX_BASE_URL environment variable to override the
endpoint base URL (e.g. for a local mirror in tests). The public ECB
endpoints require no key.
const provider: FxRatesProviderCore Interface
Implements @molecule/api-fx-rates interface.
Bond Wiring
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/api-fx-rates'
import { provider } from '@molecule/api-fx-rates-ecb'
export function setupFxRatesEcb(): void {
setProvider(provider)
}Injection Notes
Requirements
Peer dependencies:
@molecule/api-bond^1.0.1@molecule/api-fx-rates^1.0.1
Runtime Dependencies
@molecule/api-bond@molecule/api-fx-ratesfast-xml-parser
E2E Tests
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual currency/pricing screens, and check every box off one by one. This is money: a wrong rate silently corrupts every price, so verify the NUMBERS the app computes, not just that a value rendered. A box you can't check is an integration bug to fix — not a skip:
- [ ] A known pair returns a PLAUSIBLE rate:
getRate('USD', 'EUR')yields a real ratio (roughly 0.8-1.0 for USD->EUR), never 0, null, NaN, negative, or an absurd value like 1e9 — and the UI shows it as an actual number. - [ ]
convertdoes the CORRECT MATH: converting 100 USD (amountMinor10_000cents) USD->EUR returns approximately10_000 * ratein the target's minor units, rounded sensibly for that currency (integer cents; JPY has 0 decimals), and the UI shows that converted amount — not the untouched original. - [ ] Round-trip consistency: the inverse pair is reciprocal —
getRate('EUR', 'USD')is approximately1 / getRate('USD', 'EUR')— and same-currency is identity:getRate('USD', 'USD')is exactly1andconvert(x, 'USD', 'USD')returnsxunchanged. - [ ] Changing the selected pair changes the displayed result (USD->EUR vs USD->JPY give visibly different converted amounts) — the screen is not pinned to one hardcoded rate.
- [ ] An unknown/unsupported code (e.g.
'ZZZ', absent fromlistSupportedCurrencies()) surfaces a clear error in the UI — NEVER a silent rate of 0 (which zeroes the price) or a pass-through of 1. - [ ] If a historical lookup is exposed (
options.asOf), a past date returns that day's rate (different from latest for a volatile pair), not today's. - [ ] A provider/network failure surfaces gracefully (a visible error or retry) and the amount is left unconverted — the app NEVER falls back to converting at rate 0 or 1, which would corrupt the price shown or charged.
- [ ] The provider API key stays server-side — fx-rates is server-only; the key never appears in the browser bundle, the network tab, or any client response.
