Files
skills/docs/money/finance/currency-provider-coingecko/src/coingecko/coingecko.md
2026-05-29 08:20:56 +01:00

4.5 KiB
Raw Blame History

CoinGeckoProvider

(no submodules)

Purpose

CoinGecko sibling for @suaveplan/currency-providers. Implements the CurrencyProvider contract from @suaveplan/currency against the public /simple/price endpoint, with optional Pro-tier apiKey support that attaches the x-cg-pro-api-key header to every outbound request. The free public tier (no key, 10–30 calls/min) and the Pro tier share the same URL shape, so upgrading from free to Pro is a single-field config change with no other wiring impact.

Features

  • CoinGeckoProvider implements CurrencyProvider — name = "coingecko", supportsCrypto = true, supportsFiat = true.
  • Optional apiKey config (x-cg-pro-api-key header attachment).
  • Optional baseUrl and fetch config (default https://api.coingecko.com/api/v3 and globalThis.fetch).
  • Caller AbortSignal propagation via the shared httpRequest() helper (composes with timeouts from the helper).
  • Proactive UNKNOWN_CURRENCY gate — unknown options.targets reject before the HTTP call is issued.
  • Typed CurrencyProviderError on every failure path: HTTP_ERROR, PARSE_ERROR, UPSTREAM_ERROR, UNKNOWN_CURRENCY.

Usage: Basic

import { CoinGeckoProvider } from "@suaveplan/currency-provider-coingecko/coingecko/coingecko";

const provider = new CoinGeckoProvider();
const result = await provider.fetchRates({ base: "USD" });
// result.rates.BTC = 0.0000149… (1 USD ≈ 0.0000149 BTC at ~$67k/BTC)

Usage: Advanced

import { CurrencyConverter } from "@suaveplan/currency";
import { CurrencyProviderRegistry } from "@suaveplan/currency-providers";
import { CoinGeckoProvider } from "@suaveplan/currency-provider-coingecko/coingecko/coingecko";

const registry = new CurrencyProviderRegistry();
registry.register(
 new CoinGeckoProvider({
  apiKey: process.env.COINGECKO_PRO_KEY,
  baseUrl: "https://pro-api.coingecko.com/api/v3",
 }),
);

const converter = new CurrencyConverter({
 provider: registry.get("coingecko"),
 staleDurationMs: 60_000, // 1 minute — crypto rates move fast
});

// Targets are validated against the curated COIN_IDS map BEFORE the
// HTTP call — passing an unknown target raises UNKNOWN_CURRENCY
// without making a network round trip.
const controller = new AbortController();
const rates = await registry.get("coingecko").fetchRates({
 base: "EUR",
 targets: ["BTC", "ETH"],
 signal: controller.signal,
});

API Reference

class CoinGeckoProvider implements CurrencyProvider

  • constructor(config?: CoinGeckoConfig) — config is fully optional.
  • readonly name: "coingecko"
  • readonly supportsCrypto: true
  • readonly supportsFiat: true
  • fetchRates(options?: RateFetchOptions): Promise<RateFetchResult>
    • Issues GET ${baseUrl}/simple/price?ids=<curated-ids>&vs_currencies=<base.toLowerCase()>.
    • Forwards options.signal to the shared httpRequest() helper.
    • Pre-validates options.targets against COIN_IDS; an unknown entry raises CurrencyProviderError(UNKNOWN_CURRENCY) before any network activity.
    • Inverts upstream "1 crypto = X fiat" prices into the converter's "1 base = X crypto" convention.
    • Throws CurrencyProviderError with code ∈ {HTTP_ERROR, PARSE_ERROR, UPSTREAM_ERROR, UNKNOWN_CURRENCY} carrying providerName === "coingecko".

interface CoinGeckoConfig extends NoKeyConfig

  • readonly baseUrl?: string — overrides https://api.coingecko.com/api/v3.
  • readonly fetch?: FetchLike — overrides globalThis.fetch.
  • readonly apiKey?: string — Pro-tier key, attached as x-cg-pro-api-key header when present.

Implementation Notes

  • Pre-validating options.targets against COIN_IDS (not against the upstream response) means the rejection message names the bad symbol rather than swallowing it with a missing-key in the result map. This is the difference between "your ZZZ symbol is not in our curated set" (actionable) and "your rate result has no ZZZ field" (silent defect).
  • The shape guard (isResponseShape) accepts any value matching Record<string, Record<string, number>> rather than asserting the exact bitcoin/ethereum keys CoinGecko currently returns. The upstream may add new coins or rename old ones, and a strict assertion would treat that as a wire-format break instead of a benign superset.
  • Headers are constructed once at instantiation time and frozen so the per-request init spread is the only mutable copy — defends against accidental key leakage into a downstream debugger.