bsv-payment-actix-middleware 0.1.0

BSV payment middleware for Actix-web, wire-compatible with the TypeScript payment-express-middleware
Documentation
# API Reference

Public API reference for `bsv-payment-actix-middleware`. All types listed below
are re-exported from the crate root.

## Table of Contents

- [Middleware Types]#middleware-types
- [Configuration]#configuration
- [Payment Types]#payment-types
- [Error Types]#error-types
- [Extractors]#extractors
- [Bridge Types]#bridge-types (feature: `bridge`)
- [Constants]#constants

---

## Middleware Types

### `PaymentMiddlewareFactory<W>`

**Module:** `middleware`

Factory that produces `PaymentMiddlewareService` instances for each Actix
worker. Implements `actix_web::dev::Transform` so it can be passed to
`App::wrap()` or `Scope::wrap()`.

```rust
pub struct PaymentMiddlewareFactory<W: WalletInterface> {
    // config: Arc<PaymentMiddlewareConfig<W>>  (private)
}

impl<W: WalletInterface> PaymentMiddlewareFactory<W> {
    pub fn new(config: PaymentMiddlewareConfig<W>) -> Self;
}
```

**Type parameter:**
- `W` -- any type implementing `bsv::wallet::interfaces::WalletInterface`.

**Usage:**
```rust,ignore
let factory = PaymentMiddlewareFactory::new(config);
App::new().wrap(factory);
```

---

### `PaymentMiddlewareService<S, W>`

**Module:** `middleware`

Per-worker middleware service that enforces BSV payment on each request.
Implements `actix_web::dev::Service`. Created automatically by the factory;
not constructed directly.

```rust
pub struct PaymentMiddlewareService<S, W: WalletInterface> {
    // service: Rc<S>,                           (private)
    // config: Arc<PaymentMiddlewareConfig<W>>,   (private)
}
```

**Type parameters:**
- `S` -- the inner Actix service being wrapped.
- `W` -- wallet implementation.

**Response type:** `ServiceResponse<EitherBody<B>>` -- the middleware can
return either a passthrough response from the inner service (left body) or an
error/402 response constructed by the middleware itself (right body).

---

## Configuration

### `PaymentMiddlewareConfig<W>`

**Module:** `config`

Configuration struct holding the wallet and optional pricing callback. Created
via `PaymentMiddlewareConfigBuilder`.

```rust
pub struct PaymentMiddlewareConfig<W: WalletInterface> {
    pub wallet: W,
    pub calculate_request_price: Option<Arc<CalculateRequestPrice>>,
}
```

**Fields:**
- `wallet` -- the wallet instance used for nonce HMAC operations and
  transaction internalization.
- `calculate_request_price` -- optional async callback that determines the
  price in satoshis for a given request. When `None`, the middleware uses
  `DEFAULT_SATOSHIS` (100).

---

### `PaymentMiddlewareConfigBuilder<W>`

**Module:** `config`

Builder pattern for constructing `PaymentMiddlewareConfig`. The `wallet` field
is required; calling `build()` without it returns
`Err(PaymentError::ServerMisconfigured)`.

```rust
pub struct PaymentMiddlewareConfigBuilder<W: WalletInterface> {
    // wallet: Option<W>,                                    (private)
    // calculate_request_price: Option<Arc<CalculateRequestPrice>>,  (private)
}

impl<W: WalletInterface> PaymentMiddlewareConfigBuilder<W> {
    pub fn new() -> Self;
    pub fn wallet(self, wallet: W) -> Self;
    pub fn calculate_request_price(self, cb: CalculateRequestPrice) -> Self;
    pub fn build(self) -> Result<PaymentMiddlewareConfig<W>, PaymentError>;
}
```

**Example:**
```rust,ignore
let config = PaymentMiddlewareConfigBuilder::new()
    .wallet(my_wallet)
    .calculate_request_price(Box::new(|_req| Box::pin(async { Ok(500u64) })))
    .build()
    .expect("wallet is set");
```

---

## Payment Types

### `BSVPayment`

**Module:** `types`

Deserialized content of the `X-BSV-Payment` request header. Uses camelCase
serde renaming to match the TypeScript wire format.

```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BSVPayment {
    pub derivation_prefix: String,
    pub derivation_suffix: String,
    pub transaction: serde_json::Value,
}
```

**Fields:**
- `derivation_prefix` -- the nonce originally returned by the server in the
  402 response's `x-bsv-payment-derivation-prefix` header.
- `derivation_suffix` -- client-chosen suffix for key derivation.
- `transaction` -- the raw BSV transaction as an opaque JSON value (typically
  a base64-encoded string).

---

### `PaymentInfo`

**Module:** `types`

Result of payment processing, inserted into request extensions by the
middleware. Extractable in handlers via `FromRequest`.

```rust
#[derive(Clone, Debug)]
pub struct PaymentInfo {
    pub satoshis_paid: u64,
    pub accepted: Option<bool>,
    pub tx: Option<serde_json::Value>,
}
```

**Fields:**
- `satoshis_paid` -- amount paid in satoshis (0 for zero-price passthrough).
- `accepted` -- whether the wallet accepted the transaction (`None` for
  zero-price passthrough).
- `tx` -- the raw transaction data after internalization (`None` for
  zero-price passthrough).

---

### `CalculateRequestPrice`

**Module:** `types`

Type alias for the async pricing callback.

```rust
pub type CalculateRequestPrice = Box<
    dyn Fn(
            &actix_web::dev::ServiceRequest,
        ) -> futures_util::future::BoxFuture<
            'static,
            Result<u64, Box<dyn std::error::Error + Send + Sync>>,
        > + Send
        + Sync,
>;
```

The callback receives a reference to the incoming `ServiceRequest` and returns
the price in satoshis. Return `Ok(0)` to allow a request through without
payment.

---

## Error Types

### `PaymentError`

**Module:** `error`

Error enum with five variants. Each variant produces a JSON error response
matching the TypeScript implementation's wire format:
`{"status":"error","code":"ERR_*","description":"..."}`.

```rust
#[derive(Debug, thiserror::Error)]
pub enum PaymentError {
    #[error("The payment middleware must be executed after the Auth middleware.")]
    ServerMisconfigured,

    #[error("The X-BSV-Payment header is not valid JSON.")]
    MalformedPayment,

    #[error("The X-BSV-Payment-Derivation-Prefix header is not valid.")]
    InvalidDerivationPrefix,

    #[error("{0}")]
    PaymentFailed(String),

    #[error("An internal error occurred while determining the payment required for this request.")]
    PaymentInternal,
}
```

**Variant details:**

| Variant                  | HTTP Status | Error Code                       |
| ------------------------ | ----------- | -------------------------------- |
| `ServerMisconfigured`    | 500         | `ERR_SERVER_MISCONFIGURED`       |
| `MalformedPayment`       | 400         | `ERR_MALFORMED_PAYMENT`          |
| `InvalidDerivationPrefix`| 400         | `ERR_INVALID_DERIVATION_PREFIX`  |
| `PaymentFailed(msg)`     | 400         | `ERR_PAYMENT_FAILED`             |
| `PaymentInternal`        | 500         | `ERR_PAYMENT_INTERNAL`           |

Note: The 402 `ERR_PAYMENT_REQUIRED` response is not a `PaymentError` variant.
It is built directly in the middleware because it includes extra fields
(`satoshisRequired`) and custom headers.

---

## Extractors

### `AuthIdentity`

**Module:** `extractor`

Identity of the authenticated caller, extracted from request extensions.
Implements `FromRequest`.

```rust
#[derive(Clone, Debug)]
pub struct AuthIdentity {
    pub identity_key: String,
}
```

The auth middleware (or the bridge) inserts this into request extensions. The
payment middleware reads it to obtain the sender's public identity key for
transaction internalization.

### `PaymentInfo` (as extractor)

`PaymentInfo` also implements `FromRequest`, allowing handlers to extract
payment results directly:

```rust,ignore
async fn handler(payment: PaymentInfo) -> HttpResponse {
    // payment.satoshis_paid, payment.accepted, payment.tx
}
```

Returns `PaymentError::ServerMisconfigured` if the payment middleware did not
run.

---

## Bridge Types

*Available with the `bridge` feature flag.*

### `AuthToPaymentBridge`

**Module:** `bridge`

Middleware that bridges `bsv_auth_actix_middleware::Authenticated` to
`AuthIdentity`. Resolves the `TypeId` mismatch between the auth crate's
identity struct and the payment crate's identity struct.

```rust
pub struct AuthToPaymentBridge;
```

**Usage:**
```rust,ignore
use bsv_payment_actix_middleware::AuthToPaymentBridge;

App::new()
    .wrap(PaymentMiddlewareFactory::new(config))
    .wrap(AuthToPaymentBridge)
    .wrap(AuthMiddleware::new(auth_config))
```

Register between the auth middleware and the payment middleware. When
`Authenticated` is absent from request extensions, the bridge passes through
silently and lets the payment middleware handle the missing identity.

---

### `AuthToPaymentBridgeService<S>`

**Module:** `bridge`

The inner service half of `AuthToPaymentBridge`. Created automatically by the
transform; not constructed directly.

```rust
pub struct AuthToPaymentBridgeService<S> {
    // service: Rc<S>  (private)
}
```

---

## Constants

### `DEFAULT_SATOSHIS`

**Module:** `types`

```rust
pub const DEFAULT_SATOSHIS: u64 = 100;
```

Default price in satoshis when no `calculate_request_price` callback is
configured.

### `PAYMENT_VERSION`

**Module:** `types`

```rust
pub const PAYMENT_VERSION: &str = "1.0";
```

Payment protocol version string, sent in the `x-bsv-payment-version` response
header on 402 responses.

---

*Generated from `bsv-payment-actix-middleware` v0.1.0 source.*