# Voxgig SDK features

> Wrapping endpoints is the easy half of an SDK. Voxgig also generates the eighteen features teams usually hand-write once per language: retry with backoff, timeouts, rate limiting, caching, idempotency keys, pagination, streaming, tracing, metrics, audit records, cost tracking with a spend budget, a debug buffer, RBAC, proxy routing, logging, and an offline mock transport with network simulation. Every feature is implemented for every language target, and every feature is off until you switch it on.

Reference documentation: https://github.com/voxgig/sdkgen/blob/main/docs/reference/features.md

## Resilience

- **retry**: retries transient failures with exponential backoff and jitter, and honours a `Retry-After` header. Does not retry a status the server meant, such as 404 or 422. Options: `retries` (2), `minDelay` (50ms), `maxDelay` (2000ms), `factor` (2), `statuses` (408, 425, 429, 500, 502, 503, 504).
- **timeout**: a deadline per request, default 30000ms, which signals an AbortController so a live fetch is cancelled rather than abandoned.
- **ratelimit**: a token bucket at `rate` tokens per second with capacity `burst`. Requests wait for a token instead of being rejected.
- **cache**: a bounded TTL cache for safe reads, keyed by method plus URL. Default `ttl` 5000ms, `max` 256 entries, `methods` GET only. Normalises one-shot response bodies so a cache hit is readable more than once.

## Correct writes

- **idempotency**: adds an `Idempotency-Key` header to mutating calls. The key is generated once per operation, before the request is built, so it stays stable across every transport retry of that call. A caller-supplied key is never overwritten.

## Large result sets

- **paging**: writes page, limit or cursor on the way out, and reads whichever signal the server sent on the way back: a `Link` rel="next" header, `X-Page` / `X-Next-Page` / `X-Total-Count`, body cursors, or a GraphQL Relay connection. An explicit `hasMore` from the server always beats inferring one from a cursor, so iteration stops on the last page instead of looping.
- **streaming**: an async iterator over list results, with optional chunking and an AbortSignal.

## Observability

- **telemetry**: a span per operation, with W3C `traceparent`, `X-Trace-Id` and `X-Span-Id` propagated to the server. Finished spans go to an exporter callback.
- **metrics**: counts and latency, in total and keyed by entity and operation.
- **audit**: one structured record per operation: sequence, timestamp, actor, entity, operation, outcome, status, correlation id. Optional sink callback.
- **debug**: a bounded ring buffer of recent calls, with authorization, cookie and API-key headers masked.
- **clienttrack**: a stable per-client session id, a fresh request id per call, and a real User-Agent.
- **log**: structured logging at every pipeline stage. A diagnosis tool, not a production logger.

## Governance and spend

- **rbac**: required permissions keyed by entity and operation, checked before the endpoint is resolved, so a denied call never reaches the network. Optional default-deny. This is fast local enforcement, not a security boundary; the server still has to authorize.
- **cost**: prices every HTTP attempt from a rate table (`rates`, keyed `<entity>.<op>` / `<op>` / `*`), a response header (`header` x `perUnit`), a body usage figure (`path` x `perUnit`, e.g. usage.total_tokens) or a flat `unit`. Attributes the spend to the operation and to the caller (`ctrl.actor`). Set `budget` for a ceiling; with `onBudget: 'deny'` a further operation is refused before an endpoint is resolved. Order it INSIDE `cache`, or a cache hit is charged for money nobody spent.
- **proxy**: outbound HTTP(S) proxy routing, from options or the standard HTTPS_PROXY / HTTP_PROXY / NO_PROXY variables.

## Testing

- **test**: an in-memory mock of your own API, seeded from data you supply, serving reads and writes and rebuilding whatever response envelope your operations unwrap.
- **netsim**: deterministic injection of latency, first-N failures, every-Nth failures, seeded random failures, 429s with Retry-After, and hard outages.

## How they work

Two seams. Seven features (retry, timeout, ratelimit, cache, proxy, netsim, cost) wrap the transport, so they see every HTTP attempt; the rest implement named pipeline hooks, so they see one operation. `cost` uses both: it prices at the transport, because money is spent per attempt, and attributes at PreDone, because it is owed by an operation. Because each wrapper wraps whatever is already installed, list order is nesting order. The default chain is: timeout, retry, ratelimit, proxy, netsim, cost, cache, then the real transport. Pass the features as an ordered array to change it.

Activation is per client, and everything is off by default:

```
const client = new MyapiSDK({
  feature: {
    retry:       { active: true, retries: 4, maxDelay: 5000 },
    timeout:     { active: true, ms: 10000 },
    idempotency: { active: true },
  },
})
```

Every feature that measures time or generates an identifier takes an injectable clock, wait, or generator, so offline tests assert on exact backoff delays rather than sleeping.

## Where to go next

- [SDK Generator](https://voxgig.com/sdk)
- [Feature reference](https://github.com/voxgig/sdkgen/blob/main/docs/reference/features.md)
- [SDK Catalog, 600+ worked examples](https://voxgig.com/voxgig-sdk)
- [Contact](https://voxgig.com/contact)
