Initial Commit
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
# Add @suaveplan/currency-provider-binance — Binance public-ticker provider
|
||||
|
||||
**Package**: `@suaveplan/currency-provider-binance`
|
||||
**Status**: ARCHIVED
|
||||
**Type**: feature (sibling provider in the slim currency-providers wave)
|
||||
|
||||
- **Design**: ./design.md
|
||||
- **Spec delta**: ./specs/currency-provider-binance/spec.md
|
||||
|
||||
## Why
|
||||
|
||||
The 2026-05-17 slim refactor of `@suaveplan/currency-providers` removed
|
||||
nine concrete provider classes from the umbrella package and committed
|
||||
to landing each as its own `@suaveplan/currency-provider-<name>`
|
||||
sibling. `BinanceProvider` is the Binance leg of that wave. It is the
|
||||
key-less crypto-rates provider in the line-up — alongside CoinGecko,
|
||||
CryptoCompare, and Kraken — and the only one that ships sub-second
|
||||
trading-desk pricing. Without it the slim core has no working crypto
|
||||
provider out of the box; downstream agents would have to hand-roll one,
|
||||
which is exactly the bug the slim refactor exists to fix.
|
||||
|
||||
This change ports the Binance implementation that previously lived at
|
||||
`packages/finance/currency-providers/src/crypto/binance.ts` upstream
|
||||
into the genesis monorepo as a standalone package, with three quality
|
||||
improvements over the upstream form:
|
||||
|
||||
1. HTTP transport is delegated to the slim core's `httpRequest` helper,
|
||||
so `HTTP_ERROR` carries the typed `CurrencyProviderError` shape
|
||||
instead of a plain `Error` and abort/timeout composition is uniform
|
||||
across every sibling.
|
||||
2. Failure paths are split into the four typed codes the slim spec
|
||||
defines (`HTTP_ERROR`, `PARSE_ERROR`, `UPSTREAM_ERROR`,
|
||||
`UNKNOWN_CURRENCY`) — the upstream form raised a single plain
|
||||
`Error` on the HTTP path and silently dropped malformed payloads or
|
||||
missing targets.
|
||||
3. Payload shape is structurally validated (array of
|
||||
`{ symbol: string; price: string }`); upstream took the wire shape
|
||||
on faith and would `TypeError` on a Cloudflare error page.
|
||||
|
||||
## What changes
|
||||
|
||||
### ADDED
|
||||
|
||||
- `BinanceProvider` — class implementing the `CurrencyProvider`
|
||||
contract on top of the Binance public spot ticker (`GET
|
||||
/api/v3/ticker/price`).
|
||||
- `BINANCE_PROVIDER_NAME` (`"binance"`) and `BINANCE_DEFAULT_BASE_URL`
|
||||
(`"https://api.binance.com/api/v3"`) constants so consumers can wire
|
||||
the registry and overrides without string literals.
|
||||
|
||||
### NOT INCLUDED (out of scope — same deferrals as the slim core)
|
||||
|
||||
- WebSocket streaming (Binance `/ws/!ticker@arr`) — REST-only for v1
|
||||
- Historical klines / candlesticks
|
||||
- Authenticated endpoints (account, orders) — non-goal for a
|
||||
`CurrencyProvider`
|
||||
- Per-call rate-limit accounting — deferred to the future
|
||||
`RateLimitedProvider` wrapper from the slim core
|
||||
|
||||
## Source mapping
|
||||
|
||||
| Module | Upstream source |
|
||||
|---|---|
|
||||
| `BinanceProvider` | `../suaveplan/packages/finance/currency-providers/src/crypto/binance.ts` |
|
||||
| Sibling-shape contract | `openspec/archive/2026-05-17-slim-currency-providers/design.md` |
|
||||
| Slim core surface consumed | `packages/finance/currency-providers/src/{http,error-codes,types}/` |
|
||||
|
||||
The new genesis-original wrappers (`httpRequest` delegation, typed
|
||||
`PARSE_ERROR` / `UPSTREAM_ERROR` / `UNKNOWN_CURRENCY` paths, structural
|
||||
payload validation) are listed in the design rationale; they have no
|
||||
upstream analogue because upstream raised plain `Error` and ignored
|
||||
payload shape.
|
||||
|
||||
## Parity Checklist
|
||||
|
||||
| Capability | Upstream | Migrated | Notes |
|
||||
|---|---|---|---|
|
||||
| Class-based `BinanceProvider implements CurrencyProvider` | ✅ | ✅ | Identical constructor shape; takes `NoKeyConfig` now (super-set of upstream's optional `{ baseUrl }`). |
|
||||
| `name === "binance"`, `supportsCrypto === true`, `supportsFiat === false` | ✅ | ✅ | Verbatim. Exposed as `BINANCE_PROVIDER_NAME` for registry wiring. |
|
||||
| Default base URL `https://api.binance.com/api/v3` | ✅ | ✅ | Exported as `BINANCE_DEFAULT_BASE_URL` constant. |
|
||||
| Custom `baseUrl` override | ✅ | ✅ | Via `NoKeyConfig.baseUrl`. |
|
||||
| `GET /ticker/price` fetch | ✅ | ✅ | Now via slim-core `httpRequest`. |
|
||||
| Default base `USDT` | ✅ | ✅ | Verbatim. |
|
||||
| Suffix-match decoding (`BTCUSDT` → `BTC` when base is `USDT`) | ✅ | ✅ | Plus a defensive length check that rejects symbols equal to the suffix. |
|
||||
| Skip zero-price tickers | ✅ | ✅ | Verbatim. |
|
||||
| Skip negative-price / non-finite tickers | 🚫 | ⬆️ | Upstream only checked `price > 0` — fails open on `NaN`. Genesis form adds `Number.isFinite`. |
|
||||
| Optional `targets` filter | ✅ | ⬆️ | Upstream silently dropped missing targets; genesis raises `UNKNOWN_CURRENCY` so consumers learn about upstream listing changes immediately. |
|
||||
| Plain `Error` on non-2xx HTTP | ✅ | 🚫 | Replaced by typed `CurrencyProviderError(HTTP_ERROR)` raised by the slim core's `httpRequest`. Reason: the slim core's contract requires typed errors from every sibling. |
|
||||
| Structural payload validation | 🚫 | ⬆️ | Upstream cast the response shape without checking; genesis raises `UPSTREAM_ERROR` on malformed rows. |
|
||||
| `PARSE_ERROR` on non-JSON body | 🚫 | ⬆️ | Upstream would leak a runtime `SyntaxError`; genesis wraps `response.json()` in a typed catch. |
|
||||
| Injectable `FetchLike` | 🚫 | ⬆️ | Upstream used `globalThis.fetch` directly; genesis form takes a `NoKeyConfig.fetch` override for tests / proxies / edge runtimes. |
|
||||
| Optional per-request timeout | 🚫 | ⬆️ | New: `timeoutMs` flows through to `httpRequest` and composes with the caller's `signal`. |
|
||||
| `AbortSignal` propagation from `RateFetchOptions` | 🚫 | ⬆️ | Upstream did not honour `options.signal`; genesis forwards it through `httpRequest`. |
|
||||
| Upstream test suite (vi.spyOn-based fetch mock) | ✅ | ⬆️ | Rewritten to `@suaveplan/testing/runner` with a recording `FetchLike` closure — no `vi.mock`, no `vi.spyOn`. |
|
||||
| Sibling `.md` per source file + ≥200-word README | 🚫 | ⬆️ | Upstream `binance.md` was 46 lines; genesis form ships the §4 doc contract. |
|
||||
|
||||
No 🚫 row is left without justification.
|
||||
|
||||
## Impact
|
||||
|
||||
### Affected dependents
|
||||
|
||||
Run `bunx turbo ls --filter=...@suaveplan/currency-provider-binance` to
|
||||
enumerate.
|
||||
|
||||
- No current dependents (verified by
|
||||
`bunx turbo ls --filter=...@suaveplan/currency-provider-binance` —
|
||||
this is a new package and downstream commerce stacks consume it
|
||||
through the `CurrencyProviderRegistry` lookup, not by direct import).
|
||||
- `@suaveplan/currency-providers` — [ ] tests run / [x] docs reviewed
|
||||
/ [x] no action needed (this package consumes the slim core; the
|
||||
slim core has no knowledge of any sibling and was not modified)
|
||||
- `@suaveplan/currency` — [ ] tests run / [x] docs reviewed / [x] no
|
||||
action needed (we depend on the `CurrencyProvider` contract — the
|
||||
contract is unchanged)
|
||||
|
||||
## Migration
|
||||
|
||||
There is no migration path because this is a new package. Consumers
|
||||
that previously used the upstream `BinanceProvider` from the
|
||||
pre-slim-refactor `@suaveplan/currency-providers` (which has never
|
||||
shipped on genesis) replace:
|
||||
|
||||
```ts
|
||||
// Before — upstream pre-slim-refactor form
|
||||
import { BinanceProvider } from "@suaveplan/currency-providers";
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```ts
|
||||
// After — genesis sibling form
|
||||
import { BinanceProvider } from "@suaveplan/currency-provider-binance";
|
||||
```
|
||||
|
||||
Constructor signatures are compatible: `new BinanceProvider()` and
|
||||
`new BinanceProvider({ baseUrl: "…" })` both work unchanged. New
|
||||
capabilities (`fetch`, `timeoutMs`) are additive and optional.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- The other eight sibling provider packages — each lands under its own
|
||||
OpenSpec change per AGENTS.md §0c.
|
||||
- Streaming / WebSocket / authenticated endpoints — REST-only for v1.
|
||||
- Retry orchestration, circuit breaker, rate-limit accounting — those
|
||||
ship as wrapper providers consuming the `CurrencyProvider` contract.
|
||||
Reference in New Issue
Block a user