# TransformStream

A interface `TransformStream` faz parte da Streams API do Azion Runtime. Ela é uma implementação concreta do conceito de transform stream de uma pipe chain: você a passa para o método [`pipeThrough()`](/pt-br/documentacao/devtools/runtime/api-reference/readable-stream/#metodos) de um `ReadableStream` para converter um stream de dados de um formato para outro. Use-a para decodificar ou codificar frames de vídeo, descompactar dados ou converter um stream de XML para JSON. `TransformStream` é um objeto transferível. Para mais informações, consulte [TransformStream](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) na MDN Web Docs.

---

## Construtor

O construtor [`TransformStream()`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream/TransformStream) cria e retorna um objeto transform stream:

```javascript
new TransformStream()
```

O construtor aceita um objeto de transformação opcional e estratégias de enfileiramento opcionais para os streams dele. Sem um objeto de transformação, os dados passam pelo stream sem alteração.

O objeto de transformação carrega o algoritmo de transformação. O método `transform(chunk, controller)` dele recebe cada chunk escrito no stream, e `controller.enqueue()` passa um chunk para o lado readable. Um objeto de transformação também pode definir os métodos `start()` e `flush()`, como mostra a seção [Exemplo](#exemplo).

Como estratégia de enfileiramento, o Azion Runtime define `CountQueuingStrategy`, mas não `ByteLengthQueuingStrategy`: uma referência a `ByteLengthQueuingStrategy` lança `ReferenceError: ByteLengthQueuingStrategy is not defined`.

---

## Propriedades

Um transform stream tem dois lados. Juntos, eles formam o par que `pipeThrough()` aceita:

| Propriedade                                                                             | Tipo             | Descrição                                                                 |
| --------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------- |
| [`readable`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream/readable) | `ReadableStream` | O lado readable do transform stream. Ele retorna os chunks transformados. |
| [`writable`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream/writable) | `WritableStream` | O lado writable do transform stream. Ele recebe os chunks a transformar.  |

---

## Exemplo

Este handler define `AnyToU8Stream`, um transform stream que repassa cada chunk que recebe como um `Uint8Array`. Ele canaliza uma string, um array de números e um `Uint16Array` pelo stream e depois retorna os bytes de cada chunk de saída:

```javascript
export default {
  async fetch(request, env, ctx) {
    const transformContent = {
      start() {}, // required.
      async transform(chunk, controller) {
        chunk = await chunk;
        switch (typeof chunk) {
          case 'object':
            // just say the stream is done
            if (chunk === null) {
              controller.terminate();
            } else if (ArrayBuffer.isView(chunk)) {
              controller.enqueue(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
            } else if (
              Array.isArray(chunk) &&
              chunk.every((value) => typeof value === 'number')
            ) {
              controller.enqueue(new Uint8Array(chunk));
            } else if (
              typeof chunk.valueOf === 'function' &&
              chunk.valueOf() !== chunk
            ) {
              this.transform(chunk.valueOf(), controller); // hack
            } else if ('toJSON' in chunk) {
              this.transform(JSON.stringify(chunk), controller);
            }
            break;
          case 'symbol':
            controller.error("Cannot send a symbol as a chunk part")
            break
          case 'undefined':
            controller.error("Cannot send undefined as a chunk part")
            break
          default:
            controller.enqueue(this.textencoder.encode(String(chunk)))
            break
        }
      },
      flush() { /* do any destructor work here */ }
    }

    class AnyToU8Stream extends TransformStream {
      constructor() {
        super({...transformContent, textencoder: new TextEncoder()})
      }
    }

    const stream = new ReadableStream({
      start(c) {
        c.enqueue('hi');
        c.enqueue([1, 2]);
        c.enqueue(new Uint16Array([65]));
        c.close();
      },
    }).pipeThrough(new AnyToU8Stream());

    const chunks = [];
    for await (const chunk of stream) chunks.push(Array.from(chunk));
    return Response.json(chunks);
  },
};
```

A function retorna estes bytes para os três chunks de saída. A string `'hi'` se torna os bytes codificados dela, o array de números se torna um `Uint8Array` com os mesmos valores e o `Uint16Array` sai como os dois bytes do buffer dele:

```json
[
 [
  104,
  105
 ],
 [
  1,
  2
 ],
 [
  65,
  0
 ]
]
```

---

## Recursos relacionados

- [ReadableStream](/pt-br/documentacao/devtools/runtime/api-reference/readable-stream.md): O stream cujo método `pipeThrough()` envia dados por um transform stream.
- [WritableStream](/pt-br/documentacao/devtools/runtime/api-reference/writable-stream.md): O tipo de stream do lado `writable` e como escrever chunks nele.
- [Encoding](/pt-br/documentacao/devtools/runtime/api-reference/encoding.md): O `TextEncoder` que o exemplo usa para transformar strings em bytes.
- [Web APIs](/pt-br/documentacao/devtools/runtime/api-reference/javascript.md): As outras Web APIs que o Azion Runtime suporta.
