# Guía de migración: 9.9.1 → 9.10.0

Osumi Framework **9.10.0** incorpora soporte nativo para respuestas HTTP por streaming.

La actualización desde 9.9.1 es compatible hacia atrás y no requiere modificar el código existente de la aplicación.

No existe un paso automático de migración para esta versión porque no es necesario transformar archivos ni configuración del proyecto.

---

## Respuestas streaming

Los componentes pueden devolver ahora un `OStreamResponse` directamente desde su método `run()`.

```php
<?php

declare(strict_types=1);

namespace Osumi\OsumiFramework\App\Module\Download;

use Osumi\OsumiFramework\Core\OComponent;
use Osumi\OsumiFramework\Web\OStreamResponse;

class DownloadComponent extends OComponent {
    /**
     * Stream a file to the client.
     *
     * @return OStreamResponse Streamed HTTP response.
     */
    public function run(): OStreamResponse {
        $stream = fopen(
            '/path/to/file.zip',
            'rb'
        );

        if ($stream === false) {
            throw new \RuntimeException(
                'Could not open file.'
            );
        }

        return new OStreamResponse(
            $stream,
            [
                'Content-Type' => 'application/zip',
                'Content-Length' => strval(
                    filesize('/path/to/file.zip')
                ),
                'Content-Disposition' => 'attachment; filename="file.zip"'
            ]
        );
    }
}
```

Un componente cuyo `run()` declara explícitamente `OStreamResponse` puede no tener archivo de plantilla.

---

## Ciclo de vida

Una respuesta streaming utiliza el siguiente flujo:

```text
Middleware before
↓
Componente
↓
OStreamResponse
↓
Middleware afterRender
↓
Middleware afterResponse
↓
Cierre de conexiones de base de datos
↓
Cabeceras HTTP
↓
Emisión del stream por bloques
```

No se aplica ningún layout a una respuesta streaming.

El framework no comienza a enviar bytes hasta que han finalizado `afterRender` y `afterResponse`.

Esto permite que un Middleware detenga todavía la petición antes de iniciar la descarga.

---

## Middlewares

Durante una respuesta streaming:

```php
$data['is_streaming_response'] === true
```

Los Middlewares pueden seguir modificando:

- `context`
- `headers`
- `status_code`
- `stop`
- `message`

No pueden devolver `body`, ya que una respuesta streaming no dispone de un cuerpo completo materializado en memoria.

Si un Middleware devuelve `stop => true` antes de comenzar la emisión:

- se descarta el stream;
- se restauran las cabeceras normales;
- se genera la respuesta de error habitual;
- no se envía ningún byte del stream.

---

## Gestión del recurso

Por defecto, `OStreamResponse` considera que el framework es propietario del stream y lo cerrará automáticamente.

También utiliza un tamaño de bloque predeterminado de 1 MiB, de forma que archivos grandes pueden enviarse sin cargar su contenido completo en memoria.

```php
new OStreamResponse(
    $stream,
    $headers,
    200,
    1048576,
    true
);
```

Los parámetros son:

1. stream legible;
2. cabeceras HTTP;
3. código HTTP;
4. tamaño de bloque;
5. cerrar automáticamente el stream al terminar.

---

## Compatibilidad

Las respuestas tradicionales basadas en plantillas continúan funcionando sin cambios.

Los componentes existentes pueden seguir usando:

```php
public function run(): void
```

```php
public function run(ORequest $req): void
```

```php
public function run(MyDTO $dto): void
```

El nuevo `OStreamResponse` amplía estas posibilidades y no sustituye el sistema de renderizado tradicional.
