Files
suaveplan/packages/persistence/storage/storage-cdn-bunnycdn/src/bunny-cdn-adapter/bunny-cdn-adapter.streams.md
2026-05-27 23:47:53 +01:00

3.1 KiB

bunny-cdn-adapter.streams

Purpose

Builds the ReadableStream and WritableStream instances BunnyCdnAdapter returns from createReadStream / createWriteStream. Splits the stream plumbing out of the main class body so each piece can be unit-tested without instantiating the full adapter.

buildReadStream lazily resolves the StorageClientCtx promise on the first pull (the adapter passes a promise that resolves once headers are computed) then pumps the Response.body chunks 1:1 to the consumer. buildWriteStream buffers chunks until close and dispatches via the caller-supplied commit callback — the adapter passes (body, signal) => this.set(safe, body, undefined, signal) so the write goes through the OTel-wrapped set path.

Features

  • Native streaming: buildReadStream returns Response.body chunks without buffering.
  • Error propagation: mid-stream errors surface via controller.error; aborts propagate through the underlying fetch's signal.
  • buildWriteStream accepts an injectable commit callback so the adapter (or test fixtures) controls how the buffered body is shipped.
  • abort() handler drops buffered chunks promptly so memory does not linger after cancellation.

Usage: Basic

import { buildReadStream, buildWriteStream } from "@suaveplan/storage-cdn-bunnycdn";

const stream = buildReadStream(ctxPromise, "k", signal);
for await (const chunk of stream) processChunk(chunk);

Usage: Advanced

import { buildWriteStream } from "@suaveplan/storage-cdn-bunnycdn";

const ws = buildWriteStream({
    key: "k",
    signal,
    commit: async (body, s) => storage.set("k", body, undefined, s),
});
const writer = ws.getWriter();
await writer.write(chunk);
await writer.close(); // triggers commit

API Reference

buildReadStream(ctxPromise, key, signal?): ReadableStream<Uint8Array>

Starts the GET on first read; pumps the response body until done. Response.body === null closes the stream cleanly without enqueueing.

interface WriteStreamArgs

{ key, signal, commit } — commit(body, signal) is invoked once at close time with the concatenated buffer.

buildWriteStream(args): WritableStream<Uint8Array>

Buffers chunks, concatenates on close, dispatches via commit. abort() clears the buffer without committing.

Implementation Notes

  • Buffered-then-flush is the right tradeoff for BunnyCDN Storage PUT: their API expects a known Content-Length, which means chunked transfers without orchestration aren't supported. Provider-specific streaming uploads (the documented multi-part upload pattern) belong in a separate helper.
  • abort() clears chunks rather than reusing the array — clearing length forces garbage collection of every enqueued buffer once the writer releases its reference.
  • releaseLock() on the response body reader runs in finally so a mid-stream error doesn't leak the lock.
  • ctxPromise is awaited inside start; if header resolution fails (e.g. a caller-supplied async headers callback rejects), the rejection surfaces via controller.error, which is what consumers expect for stream initialisation failures.