# XamiLib Rust — Referencia de clases

Crate: `xamisdk_client`. El punto de entrada es `XamiSDK`, creado con
`XamiSDK::new(config)`. Cada llamada a `xami.pades()`, `xami.health()`, etc. devuelve
un valor nuevo que envuelve un `Client` clonado (barato — internamente comparte el
agente HTTP), en vez de cachear una instancia perezosa como en el resto de SDKs de la
suite; es el patrón más idiomático en Rust para este caso. Como `self` es palabra
reservada, `Health::self()` se llama `get_self()`.

---

## `XamiSDK`

Punto de entrada de la librería.

### Constructor

```rust
XamiSDK::new(config: Config) -> XamiSDK
```

`Config` acepta:

| Campo | Descripción |
|---|---|
| `endpoint` | URL del servicio local (por defecto `http://127.0.0.1:8300`). |
| `wrapper_key` | Credencial de aplicación (`wrp_...`). |
| `wrapper_secret` | Secret de la credencial (`wsec_...`). |
| `timeout_seconds` | Timeout HTTP en segundos (30 por defecto). |

### Métodos

| Método | Devuelve | Descripción |
|---|---|---|
| `pades()` | `Pades` | Servicio de firma de documentos PDF. |
| `blockchain()` | `Blockchain` | Servicio de firma de transacciones EVM. |
| `credentials()` | `Credentials` | Consulta de credenciales. |
| `designs()` | `Designs` | Consulta de diseños de sello. |
| `health()` | `Health` | Estado del servicio local. |
| `results()` | `Results` | Resultados de firma recientes. *(xamiSDK ≥ 0.2.0)* |
| `errors()` | `Errors` | Errores registrados por el servicio local. *(xamiSDK ≥ 0.2.0)* |
| `sync() -> Result<Value, XamiException>` | resumen | Recarga credenciales y diseños desde Xami sin reiniciar. *(xamiSDK ≥ 0.2.0)* |

---

## `Pades`

Firma de documentos PDF (PAdES).

### Métodos

#### `sign(&self, pdf_bytes: &[u8], opts: &PadesSignOptions) -> Result<String, XamiException>`
Envía un PDF a firmar. Devuelve el `request_id`. `PadesSignOptions`: `credential_key`
(requerido), `design_key`, `variables`, `reason`, `location`, `signer_name`.

#### `result(&self, request_id: &str) -> Result<Value, XamiException>`
Consulta el estado. Cuando está `DONE`, incluye el PDF firmado en `pdf_base64`.

#### `wait(&self, request_id: &str, timeout_seconds: u64, poll_seconds: f64) -> Result<Vec<u8>, XamiException>`
Bloquea hasta que la firma esté lista y devuelve el PDF firmado.

#### `sign_and_wait(&self, pdf_bytes: &[u8], opts: &PadesSignOptions, timeout_seconds: u64) -> Result<Vec<u8>, XamiException>`
Atajo: `sign()` + `wait()`. Devuelve el PDF firmado.

### Ejemplo

```rust
use xamisdk_client::PadesSignOptions;

let pdf_bytes = std::fs::read("documento.pdf")?;
let firmado = xami.pades().sign_and_wait(
    &pdf_bytes,
    &PadesSignOptions {
        credential_key: "TU_CREDENCIAL".to_string(),
        signer_name: Some("Tu Nombre".to_string()),
        reason: Some("Aprobación".to_string()),
        ..Default::default()
    },
    60,
)?;
std::fs::write("documento_firmado.pdf", firmado)?;
```

---

## `Blockchain`

Firma de transacciones / mensajes EVM. El chip actúa como wallet y devuelve `r`/`s`/`v`;
tú ensamblas la transacción con tu librería EVM.

### Métodos

#### `sign(&self, tx_hash: &str, opts: &BlockchainSignOptions) -> Result<String, XamiException>`
Envía el hash a firmar. Devuelve el `request_id`. `BlockchainSignOptions`:
`credential_key` (requerido, credencial EVM), `chain_id`.

#### `result(&self, request_id: &str) -> Result<Value, XamiException>`
Consulta el estado.

#### `wait(&self, request_id: &str, timeout_seconds: u64, poll_seconds: f64) -> Result<Value, XamiException>`
Bloquea hasta tener la firma. Devuelve el objeto con `r`/`s`/`v`/`signature`.

#### `sign_and_wait(&self, tx_hash: &str, opts: &BlockchainSignOptions, timeout_seconds: u64) -> Result<Value, XamiException>`
Atajo: `sign()` + `wait()`.

### Ejemplo

```rust
use xamisdk_client::BlockchainSignOptions;

let firma = xami.blockchain().sign_and_wait(
    "0xHASH_DE_LA_TX",
    &BlockchainSignOptions { credential_key: "TU_CREDENCIAL_EVM".to_string(), chain_id: Some(648541) },
    60,
)?;
// firma["r"], firma["s"], firma["v"]
```

---

## `Credentials`

Consulta de credenciales en la caché local.

| Método | Devuelve | Descripción |
|---|---|---|
| `all(&self) -> Result<Vec<Value>, XamiException>` | lista | Todas las credenciales disponibles. |
| `get(&self, key: &str) -> Result<Option<Value>, XamiException>` | credencial u `None` | Una credencial por su `credential_key`. |

---

## `Designs`

Consulta de diseños de sello en la caché local.

| Método | Devuelve | Descripción |
|---|---|---|
| `all(&self) -> Result<Vec<Value>, XamiException>` | lista | Todos los diseños disponibles. |
| `get(&self, key: &str) -> Result<Option<Value>, XamiException>` | diseño u `None` | Un diseño por su `design_key`. |

---

## `Health`

| Método | Devuelve | Descripción |
|---|---|---|
| `get_self(&self) -> Result<Value, XamiException>` | estado | Estado del servicio local (pareado, tenant, versión, etc.). |
| `version(&self) -> Result<Option<String>, XamiException>` | versión | Versión del xamiSDK local. `None` si es anterior a 0.2.0. |
| `api_version(&self) -> Result<u64, XamiException>` | entero | Versión del contrato local. `1` = sin `sync`, `results` ni `errors`. |

---

## `Results`

*Requiere xamiSDK ≥ 0.2.0.*

`Pades::result()` necesita que conserves el `request_id`. Si tu proceso se reinició o
el push no llegó, ese documento quedaba inalcanzable desde la librería. Con `Results`
puedes recuperar lo firmado sin depender de tu propio almacenamiento.

| Método | Devuelve | Descripción |
|---|---|---|
| `recent(&self, limit: u32) -> Result<Vec<Value>, XamiException>` | lista | Últimos resultados (`PENDING` / `DONE` / `ERROR`). |
| `pending(&self, limit: u32) -> Result<Vec<Value>, XamiException>` | lista | Solo los que siguen esperando la firma del chip. |

```rust
for r in xami.results().pending(50)? {
    println!("{} lleva esperando desde {}", r["request_id"], r["created_at"]);
}
```

---

## `Errors`

*Requiere xamiSDK ≥ 0.2.0.*

Devuelve el mensaje corto y el `error_id` de cada fallo. **Nunca devuelve el
traceback**: el detalle técnico solo sale del equipo del cliente cuando alguien
ejecuta `xamisdk report`. Está pensado para que tu aplicación pueda decirle al usuario
qué falló y con qué identificador pedir soporte.

| Método | Devuelve | Descripción |
|---|---|---|
| `recent(&self, limit: u32) -> Result<Vec<Value>, XamiException>` | lista | Últimos errores registrados. |
| `for_request(&self, request_id: &str) -> Result<Vec<Value>, XamiException>` | lista | Errores de un request concreto. |

```rust
let fallos = xami.errors().for_request(&request_id)?;
if let Some(f) = fallos.first() {
    println!("No se pudo firmar: {}", f["short"]);
    println!("Menciona {} al pedir soporte.", f["error_id"]);
}
```

---

## Compatibilidad de versiones

Los métodos marcados con *xamiSDK ≥ 0.2.0* devuelven `404` contra un servicio
anterior. Compruébalo antes si no controlas la versión instalada:

```rust
if xami.health().api_version()? >= 2 {
    xami.sync()?;
}
```

---

## Manejo de errores

Todos los métodos devuelven `Result<_, XamiException>`. `XamiException` implementa
`std::error::Error` y `Display`, con campos `message: String` y `code: Option<u16>`
(`None` en errores de red o de serialización).

```rust
match xami.pades().sign_and_wait(&pdf_bytes, &opts, 60) {
    Ok(pdf) => std::fs::write("documento_firmado.pdf", pdf)?,
    Err(e) => eprintln!("Error al firmar: {} ({:?})", e.message, e.code),
}
```
