v1.4.0

Minor
  • Add Alibaba Cloud Object Storage Service (OSS) adapter (files-sdk/alibaba). Thin wrapper around the S3 adapter — endpoint derived from the region code (oss-<region>.aliyuncs.com), virtual-hosted-style addressing, errors relabelled as "Alibaba Cloud error". Auto-loads from ALIBABA_ACCESS_KEY_ID and ALIBABA_ACCESS_KEY_SECRET.

  • Add files CLI for agents and scripts. One binary covers every adapter via --provider <name> with lazy imports — cold-start cost matches whichever single provider you select. Each Adapter method maps to a subcommand (upload, download, head, exists, delete, copy, list, url, sign-upload), with JSON-by-default output, stdin/stdout streaming for binary bodies, --dry-run and --verbose modes, and a stable exit-code mapping (NotFound → 1, Provider → 2, Unauthorized → 3, Conflict → 4). Provider credentials come from each adapter's existing env-var conventions, and --config-json is an escape hatch for the long tail of adapter options. files ... mcp boots a stdio MCP server exposing every command as a tool — provider and credentials bind at startup, so the agent only passes operation arguments.

  • Add Cloudinary adapter (files-sdk/cloudinary). Defaults to resource_type: "raw" for arbitrary-bytes storage; switch to image/video for transforms. Reads CLOUDINARY_URL or individual CLOUDINARY_* env vars. Full Adapter surface including signed delivery URLs for private/authenticated types and form-POST signed upload URLs.

  • Add Firebase Storage adapter (files-sdk/firebase-storage). Wraps the official firebase-admin SDK; the underlying getStorage().bucket() returns a @google-cloud/storage Bucket, so V4 signed read URLs, POST policy uploads with maxSize, server-side copy, and the full metadata round-trip all work out of the box. Auto-loads credentials from FIREBASE_PROJECT_ID / FIREBASE_CLIENT_EMAIL / FIREBASE_PRIVATE_KEY / FIREBASE_STORAGE_BUCKET, falling back to a service-account JSON path (GOOGLE_APPLICATION_CREDENTIALS) and then to Application Default Credentials. Accepts an existing App or Bucket via app to share initialization with Firestore/Auth. The bucket name defaults to <projectId>.firebasestorage.app when neither bucket nor FIREBASE_STORAGE_BUCKET is set. Firebase's ?alt=media&token=… download-token URL form is out of scope for v1 — reach for adapter.raw if you need it.

  • Add PocketBase adapter (files-sdk/pocketbase). Wraps the official pocketbase JS SDK and maps the unified key/blob API onto a dedicated collection: each upload becomes (or updates) a record whose configurable keyField (unique-indexed text, default "key") holds the user-facing key and whose configurable fileField (single-value file, default "file") holds the body. Auto-loads from POCKETBASE_URL plus either POCKETBASE_ADMIN_EMAIL + POCKETBASE_ADMIN_PASSWORD (admin login on first call) or POCKETBASE_AUTH_TOKEN (pre-issued token); accepts an existing PocketBase client via client. url() returns pb.files.getURL(), threading a short-lived file token from pb.files.getToken() for authenticated clients; set publicBaseUrl for a CDN override. signedUploadUrl() throws — PocketBase has no presigned upload primitive. copy() is read-then-write (no server-side copy). list() paginates via page number encoded as a numeric cursor string. UploadOptions cacheControl and metadata throw — PocketBase has no per-file HTTP cache headers and no arbitrary-metadata field on the file; add extra typed columns to the collection and write via raw if you need them. responseContentDisposition on url() throws — use raw and the ?download=true query string instead.

  • Add SharePoint adapter (files-sdk/sharepoint). Resolves siteUrl and named documentLibrary to a drive via Microsoft Graph, then delegates to the OneDrive adapter for file operations. Falls back to SHAREPOINT_* env vars then to ONEDRIVE_*. Resolution is lazy and cached after the first call.

  • Add Tencent Cloud Object Storage (COS) adapter (files-sdk/tencent). Thin wrapper around the S3 adapter — endpoint derived from the region code (cos.<region>.myqcloud.com), virtual-hosted-style addressing, errors relabelled as "Tencent Cloud error". Auto-loads from TENCENT_SECRET_ID and TENCENT_SECRET_KEY. Bucket name must include the -<appid> suffix per COS's namespacing.

  • Add Yandex Object Storage adapter (files-sdk/yandex). Thin wrapper around the S3 adapter — fixed global endpoint (storage.yandexcloud.net), region defaults to ru-central1 for signing, virtual-hosted-style addressing, errors relabelled as "Yandex Cloud error". Auto-loads from YANDEX_ACCESS_KEY_ID and YANDEX_SECRET_ACCESS_KEY.

  • Add Bun S3 adapter at files-sdk/bun-s3, backed by Bun's native Bun.S3Client instead of @aws-sdk/client-s3. Use this when you're already on Bun and want to skip the AWS SDK dependency. Implements the full adapter surface (upload, download, head, exists, delete, copy, list, url, signedUploadUrl) with three deliberate limitations vs files-sdk/s3: copy() is client-side (Bun has no server-side CopyObject primitive), and upload(metadata|cacheControl) plus signedUploadUrl(maxSize) throw because Bun.S3Client doesn't expose equivalent options. Pass client: Bun.s3 to reuse the global singleton, or hand in any custom Bun.S3Client-shaped instance.

  • Add Bunny Storage adapter (files-sdk/bunny-storage). Wraps the official @bunny.net/storage-sdk and connects to a Storage Zone via zone name + access key + region. Auto-loads from BUNNY_STORAGE_ZONE / BUNNY_STORAGE_ACCESS_KEY / BUNNY_STORAGE_REGION, with STORAGE_* accepted as aliases (the names used in the Bunny SDK's README). url() requires publicBaseUrl (typically a Bunny Pull Zone) and returns a permanent CDN URL — Bunny has no signed-read primitive, so expiresIn is ignored and responseContentDisposition throws. signedUploadUrl() throws because Bunny writes require the Storage API AccessKey header. copy() is a read-then-write (no server-side copy primitive in the SDK). Custom metadata and cacheControl on upload throw — configure cache behavior on the Pull Zone instead.

  • Move provider SDKs to optional peer dependencies. Installing files-sdk no longer pulls in every provider SDK by default — the package fully installs at a fraction of the previous size, and unused providers can't drag in transitive CVEs. Install only what you use:

    # S3 (and any S3-compatible: R2, MinIO, DigitalOcean Spaces,)npm install files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presigner# GCSnpm install files-sdk @google-cloud/storage google-auth-library# Azurenpm install files-sdk @azure/storage-blob @azure/identity

    Breaking (install-time only): if you upgrade and your project doesn't list the relevant provider SDK in its own package.json, the next adapter import will throw ERR_MODULE_NOT_FOUND. Fix is one npm install. The published JS for each adapter subpath (files-sdk/s3, files-sdk/gcs, …) is byte-identical to the previous release — provider SDKs were already externalized, so runtime behavior, tree-shaking, and bundle sizes don't change. The files CLI keeps commander as a regular dep, so npx files works out of the box. Fixes #34.

Patch
  • Expand adapter test coverage for error-recovery branches that were previously unexercised: exists() swallowing a thrown NotFound (azure, gcs, netlify-blobs, r2) versus rethrowing other mapped errors; the supabase stream-download error envelope; and dropbox's exists() returning false for folder/deleted .tags plus the shared_link_already_exists recovery falling through when no usable URL is embedded. No runtime behavior changes.