# `error-codes` — Typed error registry for currency providers _(no submodules)_ ## Purpose Defines the stable `CURRENCY_PROVIDER_CODES` registry and the `CurrencyProviderError` class every provider in `@suaveplan/currency-providers` raises. The registry guarantees that downstream code — most importantly `CurrencyConverter`'s fallback chain — can programmatically dispatch on the namespaced code string instead of parsing free-form error messages. This is the suaveplan-quality replacement for the upstream package's plain `throw new Error(...)` pattern, which gave fallback logic no way to tell "Fixer returned 401 — try the next provider" apart from "Fixer URL was malformed — give up". `CurrencyProviderError` extends `SuaveplanError`, preserving the full `SuaveplanError` contract — `cause` chaining, `toWire()` redaction, OTel span enrichment, and i18n-key dispatch — while adding three optional discriminants relevant to provider failures: `providerName` (which provider hit the error), `status` (the HTTP status when the failure came from an HTTP response), and `upstreamMessage` (the free-form error string the upstream API supplied). ## Features - Eight stable error codes covering every provider failure mode plus the slim-core registry dispatch: HTTP_ERROR, PARSE_ERROR, UPSTREAM_ERROR, UNSUPPORTED_BASE, MISSING_CONFIG, UNKNOWN_CURRENCY, PROVIDER_NOT_REGISTERED, PROVIDER_ALREADY_REGISTERED - `CurrencyProviderError extends SuaveplanError` — full `SuaveplanError` contract preserved - Optional `providerName` / `status` / `upstreamMessage` discriminants - Registered via `defineCodes` so the code values are typed as the namespaced strings (`"CURRENCY_PROVIDER.HTTP_ERROR"` etc.) - The first six codes are reachable from sibling `@suaveplan/currency-provider-` packages (where the concrete HTTP call sites live); the two `PROVIDER_*` codes are reachable from this package's `CurrencyProviderRegistry` ## Usage: Basic Example ```ts import { CURRENCY_PROVIDER_CODES, CurrencyProviderError, } from "@suaveplan/currency-providers"; throw new CurrencyProviderError( CURRENCY_PROVIDER_CODES.HTTP_ERROR, "ECB API error: 503 Service Unavailable", { providerName: "ecb", status: 503 } ); ``` ## Usage: Advanced Example Use the codes to drive fallback-chain decisions in a custom converter: ```ts import { CURRENCY_PROVIDER_CODES, CurrencyProviderError, } from "@suaveplan/currency-providers"; async function fetchWithFallback(providers: readonly CurrencyProvider[]) { let lastError: unknown; for (const provider of providers) { try { return await provider.fetchRates(); } catch (error) { lastError = error; if (!(error instanceof CurrencyProviderError)) throw error; // 4xx auth / config errors are not worth retrying with the next // provider — re-throw to bubble up if (error.code === CURRENCY_PROVIDER_CODES.MISSING_CONFIG) throw error; if (error.status === 401 || error.status === 403) throw error; // anything else: try next provider } } throw lastError; } ``` ## API Reference - `const CURRENCY_PROVIDER_CODES` — frozen registry mapping each code name to its namespaced string (`"CURRENCY_PROVIDER.HTTP_ERROR"`, etc.). - `type CurrencyProviderErrorCode` — union of the eight namespaced strings. - `interface CurrencyProviderErrorOptions extends SuaveplanErrorOptions` — adds optional `providerName: string`, `status: number`, `upstreamMessage: string`. - `class CurrencyProviderError extends SuaveplanError` — constructor `(code, message, options?)`. Read-only `providerName`, `status`, `upstreamMessage` properties. ## Implementation Notes - The discriminants are surfaced as top-level read-only properties (rather than fields on `context`) to make destructured `try/catch` handling ergonomic — `if (error instanceof CurrencyProviderError && error.status === 429)` reads naturally. - Codes that don't have a natural HTTP shape (e.g. `MISSING_CONFIG`, `UNKNOWN_CURRENCY`) simply omit `status` and `upstreamMessage`. The optional fields are populated only when meaningful. - `defineCodes` enforces namespace prefix at runtime — `CURRENCY_PROVIDER.X` cannot collide with `CURRENCY.X` from `@suaveplan/currency` or any other package's registry.