/** * Contract for HTTP fetching — enables dependency inversion. * Consumers depend on this abstraction, not on concrete fetch implementations. */ interface HttpFetcher { get(url: string, signal?: AbortSignal): Promise; } /** * Default HTTP fetcher using the global `fetch` API. * Single Responsibility: only concerned with HTTP GET and error mapping. * * Dependency Inversion: Accepts `fetch` as a constructor parameter, * allowing tests or consumers to inject alternatives. */ declare class FetchHttpFetcher implements HttpFetcher { private readonly fetchFn; private readonly timeoutMs; constructor(fetchFn?: typeof globalThis.fetch, timeoutMs?: number); get(url: string, externalSignal?: AbortSignal): Promise; } /** * All ISO 4217 currency codes supported by the ECB, as a runtime array. * Use this to programmatically list or iterate over all available currencies. * * @example * ```ts * import { ALL_CURRENCY_CODES } from "ecb-exchange-rates-ts"; * console.log(ALL_CURRENCY_CODES); // ["AUD", "BGN", ..., "ZAR"] * ``` */ declare const ALL_CURRENCY_CODES: readonly ["AUD", "BGN", "BRL", "CAD", "CHF", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "ISK", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PLN", "RON", "SEK", "SGD", "THB", "TRY", "USD", "ZAR"]; /** * ISO 4217 currency codes supported by the ECB. */ type CurrencyCode = (typeof ALL_CURRENCY_CODES)[number]; /** Data frequency for the exchange rate series. */ type Frequency = "D" | "M" | "A"; /** Exchange rate type as defined in the ECB's EXR dataflow. */ type ExchangeRateType = "SP00" | "EN00"; /** Series variation suffix. */ type SeriesVariation = "A" | "E"; /** * A single exchange rate observation from the ECB. */ interface ExchangeRateObservation { /** The date of the observation (YYYY-MM-DD for daily). */ readonly date: string; /** The target currency code. */ readonly currency: string; /** The denomination (base) currency. */ readonly baseCurrency: string; /** The exchange rate value: 1 baseCurrency = `rate` units of `currency`. */ readonly rate: number; } /** * Result for a single currency rate query. */ interface ExchangeRateResult { /** The base (denomination) currency. */ readonly base: string; /** Map of date → rate for each observation. */ readonly rates: ReadonlyMap; /** The target currency. */ readonly currency: string; /** The originally requested date (set when fallback to a different date occurred). */ readonly requestedDate?: string; } /** * Result for a multi-currency rate query. */ interface ExchangeRatesResult { /** The base (denomination) currency. */ readonly base: string; /** Map of date → { currency → rate }. */ readonly rates: ReadonlyMap>>; /** The currencies included in the result. */ readonly currencies: readonly string[]; } /** * Result of a currency conversion via `EcbClient.convert()`. */ interface ConversionResult { /** The converted amount in the target currency (rounded to 2 decimal places). */ readonly amount: number; /** The exchange rate used for the conversion. */ readonly rate: number; /** The date of the exchange rate used. */ readonly date: string; /** The target currency code. */ readonly currency: string; /** The originally requested date, if different from the actual rate date due to weekend/holiday fallback. */ readonly requestedDate?: string; } /** * Parameters to query exchange rates. */ interface ExchangeRateQuery { /** One or more target currencies. */ readonly currencies: readonly string[]; /** Start date (inclusive), format YYYY-MM-DD. */ readonly startDate: string; /** End date (inclusive), format YYYY-MM-DD. */ readonly endDate?: string; /** Data frequency. Defaults to "D" (daily). */ readonly frequency?: Frequency; /** Base (denomination) currency. Defaults to the client's configured baseCurrency. */ readonly baseCurrency?: string; } /** * Configuration for the ECB client. */ interface EcbClientConfig { /** Base URL of the ECB SDMX API. Defaults to the official endpoint. */ readonly baseUrl?: string; /** Request timeout in milliseconds. Defaults to 30_000. */ readonly timeoutMs?: number; /** Custom fetch implementation for dependency injection. */ readonly fetchFn?: typeof globalThis.fetch; /** Default base (denomination) currency. Defaults to "EUR". */ readonly baseCurrency?: string; } /** A dimension or attribute value in the SDMX-JSON structure. */ interface SdmxValue { readonly id?: string; readonly name: string; readonly start?: string; readonly end?: string; } /** A dimension component (series-level or observation-level). */ interface SdmxDimension { readonly id: string; readonly name: string; readonly role?: string; readonly values: readonly SdmxValue[]; } /** A single series within a dataset, keyed by colon-separated dimension indices. */ interface SdmxSeries { readonly attributes: readonly (number | null)[]; /** * Observations keyed by observation-dimension index (as string). * Each value is a tuple: [rate, ...attributeIndices]. */ readonly observations: Readonly>; } /** A dataset in the SDMX-JSON response. */ interface SdmxDataSet { readonly action?: string; readonly validFrom?: string; readonly series: Readonly>; } /** The structure metadata in the SDMX-JSON response. */ interface SdmxStructure { readonly name?: string; readonly dimensions: { readonly series: readonly SdmxDimension[]; readonly observation: readonly SdmxDimension[]; }; readonly attributes?: { readonly series?: readonly SdmxDimension[]; readonly observation?: readonly SdmxDimension[]; }; } /** Top-level SDMX-JSON data message from the ECB API. */ interface SdmxJsonResponse { readonly header: { readonly id: string; readonly test: boolean; readonly prepared: string; readonly sender: { readonly id: string; }; }; readonly dataSets: readonly SdmxDataSet[]; readonly structure: SdmxStructure; } /** * ECB Exchange Rates Client. * * Provides a clean, typed interface to the European Central Bank's * exchange rate reference data via the SDMX RESTful API. * * Uses the `Accept: application/json` header to receive SDMX-JSON * responses, then parses them into strongly-typed results. * * Design principles: * - **Single Responsibility**: Orchestrates query → fetch → parse → transform. * - **Open/Closed**: New data sources can be added via the `HttpFetcher` interface. * - **Dependency Inversion**: Depends on `HttpFetcher` abstraction, not `fetch` directly. * - **Interface Segregation**: Exposes focused methods for specific use cases. * * @example * ```ts * const client = new EcbClient(); * * // Get rate for a specific date (defaults to EUR base) * const result = await client.getRate("USD", "2025-01-15"); * console.log(result.rates.get("2025-01-15")); // e.g. 1.03 * * // Use a different base currency * const client2 = new EcbClient({ baseCurrency: "USD" }); * ``` */ declare class EcbClient { private readonly baseUrl; private readonly baseCurrency; private readonly fetcher; constructor(config?: EcbClientConfig); /** * Creates an EcbClient with a custom HttpFetcher implementation. * Useful for testing or when you need full control over HTTP behavior. */ static withFetcher(fetcher: HttpFetcher, config?: Pick): EcbClient; /** * Get the exchange rate for a single currency against the base currency. * * @param currency - Target currency code (e.g. "USD") * @param date - The date to query (YYYY-MM-DD). Returns the nearest available rate. */ getRate(currency: string, date: string): Promise; /** * Get the exchange rate for a single currency over a date range. * * @param currency - Target currency code (e.g. "USD") * @param startDate - Start date (YYYY-MM-DD) * @param endDate - End date (YYYY-MM-DD) * @param frequency - Data frequency (default: "D" daily) */ getRateHistory(currency: string, startDate: string, endDate: string, frequency?: Frequency): Promise; /** * Get exchange rates for multiple currencies. * * @param query - The query parameters */ getRates(query: ExchangeRateQuery): Promise; /** * Get raw observations — useful when you need full control over the data. * * @param query - The query parameters */ getObservations(query: ExchangeRateQuery): Promise; /** * Convert an amount from the base currency to a target currency at a specific date. * * @param amount - The amount in the base currency * @param currency - Target currency code * @param date - The date for the exchange rate (YYYY-MM-DD) * @throws {EcbNoDataError} When no rate is available for the given date (weekends, holidays, future dates) */ convert(amount: number, currency: string, date: string): Promise; /** * Resolves a query by applying the client's default baseCurrency * when the query doesn't specify one. */ private resolveQuery; private fetchAndParse; /** * Builds an EUR-denominated query that includes the base currency * so we can compute cross rates after fetching. */ private buildEurQuery; /** * Converts EUR-based observations to cross rates against a non-EUR base. * * Math: if ECB gives 1 EUR = X base, 1 EUR = Y target, * then 1 base = Y/X target. * For EUR as target: 1 base = 1/X EUR. */ private adjustForBaseCurrency; /** * Filters a rate result to only the most recent observation. * Used by getRate() to pick the latest rate from the lookback window. * Sets requestedDate when the actual date differs from what was requested. */ private filterToMostRecentRate; private getSingleCurrencyRates; private transformToMultiCurrencyResult; } /** * Base error for all ECB client errors. * Follows the Liskov Substitution Principle — all subtypes are interchangeable. */ declare class EcbError extends Error { readonly code: string; constructor(message: string, code: string, options?: ErrorOptions); } /** * Thrown when the ECB API returns an HTTP error. */ declare class EcbApiError extends EcbError { readonly statusCode: number; readonly statusText: string; constructor(statusCode: number, statusText: string, body?: string); } /** * Thrown when the network request fails (timeout, DNS, connection refused, etc.). */ declare class EcbNetworkError extends EcbError { constructor(message: string, cause?: unknown); } /** * Thrown when the API response cannot be parsed. */ declare class EcbParseError extends EcbError { constructor(message: string, cause?: unknown); } /** * Thrown when query parameters are invalid. */ declare class EcbValidationError extends EcbError { constructor(message: string); } /** * Thrown when the ECB API returns a valid response but contains no data. * This typically happens when querying dates where no rates are published * (weekends, holidays, future dates). */ declare class EcbNoDataError extends EcbError { readonly startDate: string; readonly endDate?: string; readonly currencies: readonly string[]; constructor(currencies: readonly string[], startDate: string, endDate?: string); } /** * Parses an SDMX-JSON response from the ECB into typed observations. * * Single Responsibility: only concerned with SDMX-JSON → typed data transformation. * * The ECB SDMX-JSON format uses index-based keys: * - Series keys (e.g. "0:0:0:0:0") map to dimension value indices * - Observation keys (e.g. "0") map to observation-dimension value indices * - Observation values are tuples: [rate, ...attributeIndices] * * @see https://data.ecb.europa.eu/help/api/data */ declare function parseJsonResponse(data: SdmxJsonResponse): ExchangeRateObservation[]; /** * Safely parses a raw JSON string into an SdmxJsonResponse. */ declare function parseSdmxJson(raw: string): SdmxJsonResponse; /** * Builds the ECB SDMX API URL for exchange rate queries. * Single Responsibility: only concerned with URL construction. * * URL pattern: {base}/data/EXR/{freq}.{currencies}.EUR.SP00.A?params * * The ECB API only supports EUR as the denomination currency. * Non-EUR base currencies are handled via cross-rate math in the client. * * Content format is controlled via the HTTP Accept header (application/json), * not via a URL parameter. */ declare function buildExchangeRateUrl(query: ExchangeRateQuery, baseUrl?: string): string; /** * Validates exchange rate query parameters. * Single Responsibility: only concerned with input validation. */ declare function validateQuery(query: ExchangeRateQuery): void; export { ALL_CURRENCY_CODES, type ConversionResult, type CurrencyCode, EcbApiError, EcbClient, type EcbClientConfig, EcbError, EcbNetworkError, EcbNoDataError, EcbParseError, EcbValidationError, type ExchangeRateObservation, type ExchangeRateQuery, type ExchangeRateResult, type ExchangeRateType, type ExchangeRatesResult, FetchHttpFetcher, type Frequency, type HttpFetcher, type SdmxDataSet, type SdmxDimension, type SdmxJsonResponse, type SdmxSeries, type SdmxStructure, type SdmxValue, type SeriesVariation, buildExchangeRateUrl, parseJsonResponse, parseSdmxJson, validateQuery };