# `Sat.Cfdi.Descarga.Masiva.Pipeline`

Orquestador del flujo completo de Descarga Masiva.

Encadena los 4 servicios (autenticacion -> solicitud -> verificacion ->
paquete) y entrega un stream de XMLs / metadatos al consumidor, ocultando
el ZIP por debajo.

> Nota: en produccion con Oban cada paso se ejecuta como worker independiente.
> Usar este modulo solo para scripts, CLI o volúmenes chicos.

## Ejemplo

    {:ok, cred} = Sat.Certificados.Credential.create("fiel.cer", "fiel.key", "pwd")

    params = %SolicitudParams{
      rfc_solicitante: "AAA010101AAA",
      fecha_inicial: ~U[2025-01-01 00:00:00Z],
      fecha_final:   ~U[2025-01-31 23:59:59Z],
      tipo_solicitud: :cfdi
    }

    Pipeline.stream_xml(params, credential: cred)
    |> Stream.each(fn
      {:ok, {filename, xml}} -> IO.puts(filename)
      {:error, reason} -> IO.warn(inspect(reason))
    end)
    |> Stream.run()

Polling y retries son configurables via opciones.

# `listar_metadata`

```elixir
@spec listar_metadata(
  Sat.Cfdi.Descarga.Masiva.Types.SolicitudParams.t(),
  keyword()
) :: {:ok, [map()]} | {:error, term()}
```

Lista metadata de todos los paquetes (cuando el `tipo_solicitud` es
`:metadata`). Devuelve una lista de mapas.

# `listar_xml`

```elixir
@spec listar_xml(
  Sat.Cfdi.Descarga.Masiva.Types.SolicitudParams.t(),
  keyword()
) :: {:ok, [{String.t(), String.t()}]} | {:error, term()}
```

Variante sincrona que materializa todos los CFDIs en una lista.
Solo recomendable para volumenes chicos (< 10,000).

# `stream_xml`

```elixir
@spec stream_xml(
  Sat.Cfdi.Descarga.Masiva.Types.SolicitudParams.t(),
  keyword()
) :: Enumerable.t()
```

Ejecuta el flujo completo y devuelve un `Stream` lazy donde cada elemento
es `{:ok, {filename, xml}}` o `{:error, reason}`.

Opciones:
  * `:credential` (requerido) — FIEL del solicitante
  * `:poll_interval_ms` — intervalo de polling para verificacion
  * `:max_attempts` — intentos maximos de polling
  * `:timeout` — HTTP timeout

---

*Consult [api-reference.md](api-reference.md) for complete listing*
