---
changelog:
  category: Release
  version: files-sdk@2.2.0
date: '2026-07-19T22:48:35Z'
seo:
  description: >-
    Add first-class NestJS support (#95). New files-sdk/nestjs subpath exports a
    dynamic FilesModule (forRoot() / forRootAsync()) that configures the
    gateway…
title: files-sdk@2.2.0
type: changelog
---
### Minor Changes

- cd93019: Add first-class NestJS support (#95). New `files-sdk/nestjs` subpath exports a dynamic `FilesModule` (`forRoot()` / `forRootAsync()`) that configures the gateway, mounts it at a configurable `path` (default `/api/files`) through Nest's middleware layer, and shares the `Files` instance via DI — `@InjectFiles()` / `FILES` token, with the configured router under `FILES_API`. Works on both the Express adapter (create the app with `bodyParser: false`) and the Fastify adapter (no parser configuration needed — middleware runs before body parsing). `@nestjs/common` is a new optional peer dependency.
- 38317d8: Lightweight `aws4fetch`-powered engine for Cloudflare R2 (#76). `r2({ client: "fetch" })` runs the HTTP adapter on a SigV4-signed `fetch` core (~2.5 KB gzipped, Web Crypto only) instead of `@aws-sdk/client-s3` — no `@aws-sdk/*` installs needed. It covers upload, download (+ ranges), head, exists, delete, list (+ delimiter), server-side copy, presigned `url()`, and `signedUploadUrl()`; multipart/resumable uploads throw with guidance to the default `"aws-sdk"` client, and stream bodies are buffered before the single PUT. Hybrid binding mode (binding + HTTP credentials) now signs `url()` / `signedUploadUrl()` through the same fetch core unconditionally, so binding and hybrid Workers never pull the AWS SDK into their bundle. Adds `aws4fetch` as a regular (tree-shaken, ~2.5 KB) dependency.
- 8e6fee9: React Native / Expo support for `files-sdk/client` and the framework hooks. `upload()` now accepts a `NativeFileRef` (`{ uri, name, type, size }` — the shape Expo pickers return): presigned-POST targets stream the descriptor through React Native's `FormData`, and every other path resolves the `uri` to a Blob automatically. `download()` falls back to buffering via `arrayBuffer()` on runtimes whose `fetch` never exposes `Response.body` (React Native), instead of returning an empty stream. Byte-body uploads fall back to sending raw bytes when the runtime's `Blob` cannot be constructed from `ArrayBuffer` parts. Adds a React Native docs page under UI → Client.

### Patch Changes

- 8992d9a: `FilesModule.forRootAsync()`: the `useFactory` return type now excludes `global` (new `FilesModuleFactoryResult` type). A `global` returned from the factory was silently ignored — the `DynamicModule` needs it before the factory runs, so it only takes effect on `FilesModuleAsyncOptions` itself. Returning it from the factory is now a type error instead of a no-op.
- 8992d9a: `r2()` binding mode: `url()` and `signedUploadUrl()` reject again instead of throwing synchronously on misconfiguration (no hybrid credentials, `responseContentDisposition` without signing). A refactor had made these the only adapter methods that could throw before a `.catch` handler was attached, breaking direct/plugin adapter callers. Also corrects the `R2BindingOptions.bucket` doc comment — it is required for hybrid signing, not an error label.
- 8992d9a: `StoredFile.blob()` now works on React Native. RN's `Blob` cannot be constructed from raw bytes, so `blob()` on a downloaded file threw at Blob construction — the exact platform the RN client work targets. On runtimes without byte-part Blobs, `blob()` now consumes the response's native `Response.blob()` instead, and later `text()`/`arrayBuffer()` calls read back through that Blob (via `Blob#arrayBuffer()` or `FileReader`). If bytes were already materialized first, `blob()` throws a clear `FilesError` explaining the ordering instead of an opaque platform error.
- 8992d9a: The `fetch` S3 client (`r2({ client: "fetch" })` and hybrid binding signing) now fails closed on keys containing `.` or `..` path segments. WHATWG `URL` — used by both the SigV4 signer and `fetch` itself — collapses dot segments (even percent-encoded ones) before signing, so such keys were silently signed and sent for a _different_, normalized key, and under path-style addressing a `..` segment could escape the bucket entirely. These keys now throw a permanent `Provider` error with guidance to use the `aws-sdk` client, which addresses them literally.
- 8992d9a: The `fetch` S3 client now maps post-dispatch failures to `FilesError` like everything else: a download/list/lazy-body read dying mid-stream, and signing errors in `url()` / `signedUploadUrl()` (e.g. an invalid `contentType` header value), previously escaped as raw runtime `TypeError`s when the adapter was used directly.
- 5d83642: Fix `useFiles` recreating its internal store on every render. The store is now initialized lazily once (matching the abort-controller ref pattern), avoiding the wasted `createStore()` call and throwaway allocation on each render.
