Skip to main content
Proposed (STA-828). It extends 0222 decision 1 and 0234 decision 7. OS audit gate A, gap 10.

Context

FileSystem#write takes one buffer, so an export for a large tenant is built whole in memory before it is stored.

Decision

  1. FileSystem#writeStream(key, source, options) takes a web ReadableStream<Uint8Array> or an AsyncIterable<Uint8Array | string> (strings are UTF-8).
  2. The port’s own default buffers: it reads the stream and calls write. The memory, local, GCS, Encore and Electron disks use it.
  3. The s3 disk (S3, R2, MinIO) uploads in parts of a fixed 8 MiB (above S3’s 5 MiB floor, equal as R2 requires), holding one part in memory. A stream shorter than one part is one PUT.
  4. Never a partial object. A stream that fails stores nothing: the buffered default never calls write, and the multipart upload is aborted (the abort’s own failure never hides the stream’s error).

Consequences

  • A large export streams on the managed buckets; a local or memory disk still holds it whole (development only).
  • The part size is a constant, not configuration: it is a protocol limit, not a business answer.

Enforcement

planned — packages/data/filesystem/src/contracts/ports/__tests__/file-system.port.test.ts and packages/data/filesystem/src/node/drivers/__tests__/s3-file-system.driver.test.ts.

Note 2026-10-27: streamed reads (STA-1259)

FileSystem#readStream(key) is the read side of decision 1. It resolves to a web ReadableStream<Uint8Array> once the file is found, so a missing file rejects the call with FileNotFoundError, never the stream. Every disk has it: the local and electron disks stream from an open file handle, s3 streams the GET body and gcs the download; the memory and encore_bucket disks use the port default, which reads the file whole and serves it as one chunk (development or small files, as decision 2 does for writes). Enforcement of this note: planned — file-system.port.test.ts and the driver tests under packages/data/filesystem/src/{node,desktop}/drivers/__tests__/ (written, run on ci-box).

Supersedes and sources

Supersedes: none. Sources: services/audit SPEC (gap 10); STA-828.