captcha-sdk 0.0.1

Unified server-side CAPTCHA verification for Rust
Documentation
# HTTP transport boundary

> **TARGET architecture — implementation pending.** This is the authoritative
> contract for the advanced HTTP transport SPI. Concrete dependency and runtime
> choices remain implementation decisions.

## Normal and advanced construction

Normal users do not configure transport. A built-in provider builder installs a
secure default with connection reuse, TLS verification, and bounded I/O.

Advanced users may inject a transport for proxies, custom TLS, tracing, or
deterministic tests:

```rust,ignore
// Illustrative only: this concrete transport may be feature-provided, renamed,
// or remain internal depending on the implementation dependency decision.
let transport = ReqwestTransport::builder().proxy(proxy).build()?;
let captcha = Turnstile::builder(secret)
    .transport(transport)
    .build()?;
```

The example name `ReqwestTransport` does not commit the public API to reqwest.
Provider builders remain generic over, or erase, the small SDK transport SPI.

## Object-safe SPI

```rust,ignore
pub trait HttpTransport: Send + Sync + 'static {
    fn send(&self, request: TransportRequest) -> TransportFuture<'_>;
}

pub type TransportFuture<'a> = Pin<Box<
    dyn Future<Output = Result<TransportResponse, TransportError>> + Send + 'a
>>;
```

The exact alias syntax may be refined, but object-safe async behavior and the
SDK-owned boundary are normative. `TransportRequest`, `TransportResponse`, and
`TransportError` expose private fields with getters and builders only where
external construction is necessary. They never expose reqwest or another HTTP
client's public types.

`TransportRequest` contains the HTTP method, validated HTTPS URL, constrained
headers, bounded serialized body, and remaining timeout budget.
`TransportResponse` contains status, constrained headers, and a bounded body.
`TransportError` contains safe normalized failure information and a redacted
source where appropriate.

## One-send responsibility

One `send` call performs one HTTP exchange. Transport has no CAPTCHA semantics:
it does not evaluate policy, interpret provider responses, generate idempotency
keys, retry, or decide whether a token can be replayed. Those responsibilities
remain with the adapter and attempt orchestration described in
[Attempts and safe retries](attempts-and-retries.md).

A custom transport necessarily sees serialized credential and token bytes in
`TransportRequest`. It is a privileged trust boundary. The SDK can document and
constrain the interface but cannot prevent a malicious implementation from
copying or logging those bytes.

## Security constraints

- Production provider endpoints require HTTPS with certificate verification.
- Redirects are disabled so credentials cannot be forwarded to a new origin.
- Request and response bodies and header collections are bounded.
- The remaining total-operation timeout and cancellation propagate to I/O.
- Errors are normalized and redact URLs, headers, bodies, credentials, tokens,
  and unsafe upstream messages.
- The default transport reuses connections and TLS sessions safely.
- Endpoint override remains dangerous, test-only, and feature-gated.

Dropping the returned future cancels owned I/O where the HTTP implementation
allows, but it does not prove that the request was not received. The adapter
classifies the resulting `TokenState` conservatively.