# `provider` — KrakenProvider class _(no submodules)_ ## Purpose `KrakenProvider` is the universal `CurrencyProvider` implementation for Kraken's free `/0/public/Ticker` endpoint. It fetches real-time last-trade-closed prices for a fixed set of high-volume crypto pairs and returns them as reciprocal-of-USD rates, so a downstream `CurrencyConverter` can translate `USD → BTC` (and friends) without callers ever seeing Kraken's non-standard pair names. The class is the canonical sibling-package surface defined by the slim `@suaveplan/currency-providers` core: it wraps a single upstream endpoint, maps every documented failure mode to a typed `CurrencyProviderError`, and exposes nothing that consumers can't already obtain from the shared core helpers. ## Features - No API key required — Kraken's public endpoint is free and rate-limited per IP - 12 high-volume symbols out of the box (BTC, ETH, SOL, USDT, DOT, ADA, LINK, AVAX, ATOM, LTC, DOGE, XRP); extensible via constructor `extraSymbols` - Reciprocal-of-USD rate model — `1 USD = (1 / krakenLastTradePrice)` of the target crypto, matching the shape every `CurrencyConverter` consumer expects - Uses the slim core's `httpRequest()` helper so HTTP failures, timeouts, and caller abort-signal propagation are handled uniformly - Maps the four wire-level failure modes to typed `CurrencyProviderError`: `HTTP_ERROR` (non-2xx), `UPSTREAM_ERROR` (Kraken `error[]` array), `PARSE_ERROR` (malformed JSON / shape mismatch), `UNKNOWN_CURRENCY` (all requested targets unmapped) - Universal — no `node:`/`bun:`/DOM imports; runs unchanged under Node ≥ 18, Bun, modern browsers (subject to Kraken's CORS), Web Workers - Optional injectable `FetchLike` (defaults to `globalThis.fetch`) for recording tests, proxying, or staging URLs ## Usage: Basic ```ts import { KrakenProvider } from "@suaveplan/currency-provider-kraken/provider/provider"; const provider = new KrakenProvider(); const result = await provider.fetchRates({ base: "USD" }); console.log(result.rates.BTC); // e.g. 0.0000149 (≈ 1 / 67000) console.log(result.rates.ETH); // e.g. 0.0002857 (≈ 1 / 3500) ``` ## Usage: Advanced ```ts import { CurrencyConverter } from "@suaveplan/currency"; import { CurrencyProviderRegistry } from "@suaveplan/currency-providers"; import { KrakenProvider } from "@suaveplan/currency-provider-kraken/provider/provider"; // Use the slim core's registry — wire Kraken plus any other sibling // providers your app supports. The Kraken instance extends coverage with // a newly-listed pair via `extraSymbols`, and reuses a custom fetch // closure that adds a proxy header. const registry = new CurrencyProviderRegistry(); registry.register( new KrakenProvider({ baseUrl: "https://kraken.proxy.example.com/0/public", fetch: async (url, init) => fetch(url, { ...init, headers: { ...(init?.headers ?? {}), "x-proxy-token": process.env.PROXY_TOKEN ?? "", }, }), extraSymbols: { MATIC: "MATICUSD" }, }), ); const converter = new CurrencyConverter({ provider: registry.get("kraken"), }); const btcRate = await converter.getRate("USD", "BTC"); const maticRate = await converter.getRate("USD", "MATIC"); ``` ## API Reference | Export | Kind | Description | |---|---|---| | `DEFAULT_KRAKEN_BASE_URL` | `string` | `"https://api.kraken.com/0/public"` — overridable via `config.baseUrl`. | | `KrakenProviderConfig` | `interface` extends `NoKeyConfig` | Optional `baseUrl`, optional `fetch` (`FetchLike`), optional `extraSymbols` (`Record`). | | `KrakenProvider` | `class implements CurrencyProvider` | Fixed `name = "kraken"`, `supportsCrypto = true`, `supportsFiat = false`. Constructor takes an optional `KrakenProviderConfig`. | | `KrakenProvider.fetchRates(options?)` | `(RateFetchOptions?) => Promise` | Issues one `GET /Ticker?pair=` via the injected fetch. Returns `{ base, rates, timestamp }`. Throws `CurrencyProviderError` on every documented failure path. | ### Error codes raised | Code | When | |---|---| | `CURRENCY_PROVIDER.HTTP_ERROR` | Non-2xx response (raised by the shared `httpRequest`). Carries `status`. | | `CURRENCY_PROVIDER.UPSTREAM_ERROR` | Kraken response carries a non-empty `error[]` array. Carries `upstreamMessage`. | | `CURRENCY_PROVIDER.PARSE_ERROR` | Body fails JSON-parse, OR the parsed body does not match the `{ error: string[], result: object }` shape. Carries `cause` for the JSON-parse case. | | `CURRENCY_PROVIDER.UNKNOWN_CURRENCY` | Caller supplied `options.targets` but none of the requested symbols resolved to a mapped Kraken pair. | ## Implementation Notes - The pair list sent in the `pair=` query is the value list of the merged symbol map — Kraken supports a comma-separated batch so the whole supported set is fetched in a single round trip. This is more efficient than one request per symbol AND matches what Kraken's documentation recommends. - The rate model is `1 / Number.parseFloat(ticker.c[0])` where `c[0]` is Kraken's "last trade closed" price. Entries whose price does not parse to a positive finite number are skipped (not raised) — Kraken occasionally returns `"0.00"` for freshly-listed pairs. If the entire mapped set drops, `options.targets` filtering will subsequently raise `UNKNOWN_CURRENCY` on the caller's behalf. - `options.signal` is forwarded into `httpRequest()` so the caller's `AbortController` composes with any future timeout the helper applies. - The provider does **not** retry, cache, or rate-limit. Those concerns belong in wrapper providers (the slim core's `## Out of scope` defers them) — keeping this class focused on Kraken's wire protocol keeps the failure surface auditable. - All HTTP error mapping flows through the shared `httpRequest()` helper exported from `@suaveplan/currency-providers/http/http`, so the response is never read on a non-2xx path — Kraken's body on a 5xx is typically HTML and would otherwise raise a confusing `PARSE_ERROR`. - Tier purity: no `node:` imports, no DOM imports, no `setTimeout`. The helper uses `AbortSignal.timeout` for timeouts (universal in Node 17.3+, Bun, modern browsers).