# Migration Guide: 9.9.1 → 9.10.0

Osumi Framework **9.10.0** introduces native support for streamed HTTP responses.

Updating from 9.9.1 is backward compatible and does not require changes to existing application code.

There is no automatic migration step for this release because no application files or configuration need to be transformed.

---

## Streamed responses

Components can now return an `OStreamResponse` directly from their `run()` method.

```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"'
            ]
        );
    }
}
```

A component whose `run()` method explicitly declares `OStreamResponse` does not require a template file.

---

## Lifecycle

A streamed response follows this pipeline:

```text
before Middleware
↓
Component
↓
OStreamResponse
↓
afterRender Middleware
↓
afterResponse Middleware
↓
Database connections closed
↓
HTTP headers
↓
Chunked stream emission
```

Layouts are not applied to streamed responses.

The framework does not start sending stream bytes until both `afterRender` and `afterResponse` have completed.

This allows Middleware to stop the request before a download begins.

---

## Middlewares

During a streamed response:

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

Middlewares can still modify:

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

They cannot return `body`, because a streamed response has no complete body materialized in memory.

If Middleware returns `stop => true` before emission starts:

- the stream is discarded;
- normal response headers are restored;
- the regular error response is generated;
- no stream bytes are sent.

---

## Resource management

By default, `OStreamResponse` considers the framework to own the stream and closes it automatically.

The default chunk size is 1 MiB, allowing large files to be served without loading their complete contents into memory.

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

The parameters are:

1. readable stream;
2. HTTP headers;
3. HTTP status code;
4. chunk size;
5. whether the stream is automatically closed.

---

## Compatibility

Traditional template-based responses continue to work unchanged.

Existing components can continue using:

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

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

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

The new `OStreamResponse` extends these capabilities and does not replace the traditional rendering system.
