# XamiLib Node.js — Referencia de clases

Paquete: `xamisdk-client`. El punto de entrada es la clase `XamiSDK`. Los métodos
siguen la convención camelCase de JavaScript. Todos son `async` y devuelven
`Promise`. Incluye tipados `.d.ts` para TypeScript.

---

## `XamiSDK`

Punto de entrada de la librería.

### Constructor

```js
new XamiSDK(config)
```

`config` acepta:

| Clave | Descripción |
|---|---|
| `endpoint` | URL del servicio local (por defecto `http://127.0.0.1:8300`). |
| `wrapperKey` | Credencial de aplicación (`wrp_...`). |
| `wrapperSecret` | Secret de la credencial (`wsec_...`). |
| `timeout` | Timeout HTTP en segundos (opcional, 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(): Promise<object>` | resumen | Recarga credenciales y diseños desde Xami sin reiniciar. *(xamiSDK ≥ 0.2.0)* |

---

## `Pades`

Firma de documentos PDF (PAdES).

### Métodos

#### `sign(pdfBytes: Buffer, opts): Promise<string>`
Envía un PDF a firmar. Devuelve el `request_id`. `opts`: `credential_key` (requerido),
`design_key`, `variables`, `reason`, `location`, `signer_name`.

#### `result(requestId): Promise<object>`
Consulta el estado. Cuando está `DONE`, incluye el PDF firmado en `pdf_base64`.

#### `wait(requestId, timeoutSeconds = 60, pollSeconds = 1.0): Promise<Buffer>`
Bloquea hasta que la firma esté lista y devuelve el PDF firmado.

#### `signAndWait(pdfBytes, opts, timeoutSeconds = 60): Promise<Buffer>`
Atajo: `sign()` + `wait()`. Devuelve el PDF firmado.

### Ejemplo

```js
const pdfFirmado = await xami.pades().signAndWait(
  fs.readFileSync('documento.pdf'),
  {
    credential_key: 'TU_CREDENCIAL',
    signer_name: 'Tu Nombre',
    reason: 'Aprobación',
    variables: { name: 'Tu Nombre' },
  }
);
fs.writeFileSync('documento_firmado.pdf', pdfFirmado);
```

---

## `Blockchain`

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

### Métodos

#### `sign(txHash: string, opts): Promise<string>`
Envía el hash a firmar. Devuelve el `request_id`. `opts`: `credential_key` (requerido,
credencial EVM), `chain_id`.

#### `result(requestId): Promise<object>`
Consulta el estado.

#### `wait(requestId, timeoutSeconds = 60, pollSeconds = 1.0): Promise<object>`
Bloquea hasta tener la firma. Devuelve `{ r, s, v, signature, ... }`.

#### `signAndWait(txHash, opts, timeoutSeconds = 60): Promise<object>`
Atajo: `sign()` + `wait()`.

### Ejemplo

```js
const firma = await xami.blockchain().signAndWait('0xHASH_DE_LA_TX', {
  credential_key: 'TU_CREDENCIAL_EVM',
  chain_id: 648541,
});
// firma.r, firma.s, firma.v
```

---

## `Credentials`

Consulta de credenciales en la caché local.

| Método | Devuelve | Descripción |
|---|---|---|
| `all(): Promise<object[]>` | lista | Todas las credenciales disponibles. |
| `get(key): Promise<object\|null>` | credencial o `null` | Una credencial por su `credential_key`. |

---

## `Designs`

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

| Método | Devuelve | Descripción |
|---|---|---|
| `all(): Promise<object[]>` | lista | Todos los diseños disponibles. |
| `get(key): Promise<object\|null>` | diseño o `null` | Un diseño por su `design_key`. |

---

## `Health`

| Método | Devuelve | Descripción |
|---|---|---|
| `self(): Promise<object>` | estado | Estado del servicio local (pareado, tenant, versión, etc.). |
| `version(): Promise<string\|null>` | versión | Versión del xamiSDK local. `null` si es anterior a 0.2.0. |
| `apiVersion(): Promise<number>` | entero | Versión del contrato local. `1` = sin `sync()`, `results()` ni `errors()`. |

---

## `Results`

*Requiere xamiSDK ≥ 0.2.0.*

`Pades.result()` necesita que conserves el `requestId`. 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(limit = 50): Promise<object[]>` | lista | Últimos resultados (`PENDING` / `DONE` / `ERROR`). |
| `pending(limit = 50): Promise<object[]>` | lista | Solo los que siguen esperando la firma del chip. |

```js
for (const r of await xami.results().pending()) {
  console.log(r.request_id, 'esperando desde', 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(limit = 20): Promise<object[]>` | lista | Últimos errores registrados. |
| `forRequest(requestId): Promise<object[]>` | lista | Errores de un request concreto. |

```js
const fallos = await xami.errors().forRequest(requestId);
if (fallos.length) {
  console.log('No se pudo firmar:', fallos[0].short);
  console.log('Menciona', fallos[0].error_id, 'al pedir soporte.');
}
```

---

## 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:

```js
if ((await xami.health().apiVersion()) >= 2) {
  await xami.sync();
}
```

---

## Manejo de errores

Todos los métodos lanzan (rechazan la Promise con) `XamiException` ante un fallo
(credencial inválida, servicio caído, timeout). Expone `message` y `code`.

```js
const { XamiException } = require('xamisdk-client');

try {
  const pdf = await xami.pades().signAndWait(pdfBytes, { credential_key: '...' });
} catch (e) {
  if (e instanceof XamiException) {
    console.error('Error al firmar:', e.message, e.code);
  } else {
    throw e;
  }
}
```
