# Voxgig SDK features

> Wrapping endpoints is the mechanical half of an SDK. Voxgig also generates the twenty 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, credential resolution with refresh-token exchange, payload validation against the model's own field types, 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 honors a `Retry-After` header. Does not retry a status the server meant, such as 404 or 422. Options: `retries` (2), `minDelay` (50 ms), `maxDelay` (2,000 ms), `factor` (2), `statuses` (408, 425, 429, 500, 502, 503, 504).
- `timeout`: a deadline per request, default 30,000 ms, which signals an AbortController so a live fetch is canceled 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` 5,000 ms, `max` 256 entries, `methods` GET only. Normalizes 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.
- `validate`: checks an outbound payload against the operation's request shape, and optionally each returned record against the entity's field types. It uses the types the model already carries, so there is no schema to write. A failed request short-circuits with a `validate_failed` error before the network call, and a failed response is rejected after it arrives and before it reaches the caller; `mode: 'report'` collects and continues. Options: `request` (true), `response` (false), `strict` (false, reject undeclared keys), `mode` ('throw').

## 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 asynchronous 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 descriptive 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`, for example `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, 429 responses with Retry-After, and hard outages.

## How they work

Two seams. Eight features (retry, timeout, ratelimit, cache, proxy, netsim, cost, secrets) 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)
