Files
2026-05-27 23:29:53 +01:00

4.9 KiB

Tasks: enterprise-currency-providers

Change ID: enterprise-currency-providers Package: @suaveplan/currency-providers Target path: finance/currency/currency-providers Prerequisites on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/currency, @suaveplan/retry, @suaveplan/logger


0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create full directory tree per proposal.md layout.
  • package.json at 0.1.0, "sideEffects": false, exports "." + per-provider subpaths + http/fetch-wrapper + http/coalesce + wrappers/rate-limited.
  • Deps: workspace + catalog deps as listed in proposal.
  • DevDeps: vitest catalog:testing, @vitest/coverage-istanbul catalog:testing, @suaveplan/testing workspace:^.
  • tsconfig.json extending library.json; vitest.config.ts with createTestConfig().
  • Scripts: lint, typecheck, test, test:coverage, build, docs:check.

2. Types and errors

  • Define ApiKeyConfig, NoKeyConfig, HttpFetchOptions, RateLimitOptions in src/types/provider.types.ts.
  • Write provider.types.md (≥200 words).
  • src/error-codes.ts: CURRENCY_PROVIDER_AUTH_FAILED, CURRENCY_PROVIDER_RATE_LIMITED, CURRENCY_PROVIDER_NETWORK_ERROR, CURRENCY_PROVIDER_PARSE_FAILED; implement ProviderError / AuthError / RateLimitError / NetworkError / ParseError hierarchy; registerCurrencyProviderErrorCodes(); eager call.

3. HTTP utilities

  • Implement FetchWrapper in src/http/fetch-wrapper/fetch-wrapper.ts:
    • request(url, init, options): add AbortSignal timeout; parse X-RateLimit-* headers; on 401 throw AuthError; on 429 throw RateLimitError with retryAfterMs; on network error throw NetworkError. Wrap with @suaveplan/retry.
    • OTel span per request with provider name, URL, status.
  • Write fetch-wrapper.test.ts: 200 success; 401 AuthError; 429 RateLimitError with header; timeout; retry.
  • Write fetch-wrapper.md (≥200 words).
  • Implement coalesce in src/http/coalesce/coalesce.ts: per-key in-flight dedup using Map<string, Promise<T>>.
  • Write coalesce.test.ts: concurrent calls to same key share one promise; different keys independent.
  • Write coalesce.md (≥200 words).

4. Provider implementations

For each of the nine providers (EcbProvider, FixerProvider, OpenExchangeRatesProvider, BinanceProvider, CoinGeckoProvider, CoinMarketCapProvider, CryptoCompareProvider, KrakenProvider, VirtualCurrencyProvider):

  • Implement the provider class implementing CurrencyProvider.
  • All HTTP calls use the shared FetchWrapper.
  • Parse upstream response via Zod schema; throw ParseError on mismatch.
  • isHealthy(): return false when circuit is open (delegated to the circuit breaker in @suaveplan/currency).
  • Write unit test using vi.stubGlobal('fetch', ...) with a recorded response fixture: happy path + auth error + rate limit + parse error.
  • Write .md doc (≥200 words, API reference, auth setup, rate limits documented).

5. RateLimitedProvider wrapper

  • Implement RateLimitedProvider in src/wrappers/rate-limited-provider/: wraps a provider, enforces per-second QPS using a token-bucket; delays calls that exceed the limit; honours Retry-After from RateLimitError.
  • Write rate-limited-provider.test.ts: QPS enforcement; Retry-After propagation.
  • Write rate-limited-provider.md (≥200 words).

6. Integration tests

  • tests/integration.test.ts: skip unless RUN_CURRENCY_LIVE=1. EcbProvider fetches real rates (no API key). Assert at least USD and EUR rates are positive and sane.

7. Docs + verify + publish

  • Root README.md: provider comparison table (auth, fiat/crypto, rate limit), quick-start with ECB, API table.
  • bunx turbo lint --filter=@suaveplan/currency-providers — zero errors.
  • bunx turbo typecheck --filter=@suaveplan/currency-providers — zero errors.
  • bunx turbo test --filter=@suaveplan/currency-providers — all pass.
  • bunx turbo test:coverage --filter=@suaveplan/currency-providers — 100%.
  • bun scripts/publish.ts --package @suaveplan/currency-providers.
  • Update CLAUDE.md; archive to openspec/archive/2026-04-24-enterprise-currency-providers/.