Reference

Changelog

All notable changes to Fileway

View the canonical source on GitHub →

All notable changes to Fileway are documented here. Releases are cut from main via the automated release workflow with npm provenance (SLSA) attestation on every publish.

Upcoming — v1.0.0

The first stable release. Target scope, tracked on the roadmap:

  • Stable public APIUploadOptions, UploadResult<TMeta>, BaseDriver, and FilewayClient lock in 1.0 semantics. Breaking changes become semver-major.
  • True streaming uploads — ✅ landed for S3: aws-chunked per-chunk SigV4 signing via options.size, plus bounded-memory multipart uploads for unknown sizes and very large objects.
  • Upload cancellation — ✅ landed for all drivers: options.signal rejects with AbortError and cleans up partial artifacts.
  • Middleware stream transformationbeforeUpload will be able to transform the stream itself, not just options.
  • Operational hardening — progress events ✅ landed (options.onProgress); classified error types ✅ landed (StorageError codes); retries with backoff still to come.
  • Signed downloads — ✅ landed for S3 (getPresignedUrl) and Cloudinary (signed delivery URLs).

Expected: once the roadmap items above land and the API has gone through real-world feedback via GitHub Discussions.

v0.1.0 — 2026-07-31

  • Optional logger + onError callbacksFilewayClient config now accepts a dependency-free logger ({ debug?, info?, warn?, error? }) and an onError(error, context) hook, so you can plug in your own tooling (Pino, Sentry, Datadog) with a few lines and no adapter package. The logger receives "<operation> started/succeeded" info events (structured meta: operation, path, filename, size, id, url, durationMs) and error on failures — silent when omitted, and a throwing logger never breaks the operation it reports on. onError is awaited with the raw error plus { operation, durationMs, path, ... } context before the error is rethrown; it is skipped for aborts (AbortError is cancellation, not failure) but fires for ValidationError/config errors, and a throwing onError never masks the original error. New exports: Logger, LogLevel, Operation, ErrorContext in @fileway/core.
  • Typed error taxonomy@fileway/core now exports a single StorageError (with the StorageErrorCode union: validation, config, not-found, bucket-not-found, auth-failed, size-exceeded, network, provider-error) carrying optional statusCode, provider, and cause, plus isAbortError(). ValidationError is now a StorageError subclass (code === "validation", instanceof behavior unchanged), and abort signals still surface as standard DOMException/AbortError. All drivers throw typed errors instead of generic Errors: S3 classifies AWS/MinIO XML <Code> responses (NoSuchBucket, NoSuchKey/NoSuchUpload, AccessDenied/InvalidAccessKeyId/SignatureDoesNotMatch/ExpiredToken/InvalidToken, EntityTooLarge) with an HTTP-status fallback, wraps non-abort fetch failures as network (preserving the cause), and throws config when credentials are missing; Cloudinary maps status (401/403 → auth-failed, upload 404 → bucket-not-found, get 404 → not-found, 413 → size-exceeded, else provider-error); Local classifies missing files as not-found; FilewayClient.getPresignedUrl throws config for drivers without presigned-URL support. Message strings are unchanged, so existing callers keep working. This is the foundation for retries (retry network/provider-error only).
  • @fileway/driver-s3: presigned URLsgetPresignedUrl(path, { expiresIn }) (with a FilewayClient.getPresignedUrl passthrough) returns a time-limited, SigV4-signed GET URL so a file in a private bucket can be downloaded by anyone holding the link, with no credentials and no network call to sign it. Auth travels in the query string (X-Amz-Algorithm, X-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amz-SignedHeaders=host, X-Amz-Signature) and only host is signed with an UNSIGNED-PAYLOAD hash. expiresIn defaults to 3600 seconds and must be an integer in 1..604800 (AWS's 7-day cap) or a ValidationError is thrown. Works with endpoint/forcePathStyle (MinIO, R2) and reuses the existing Web Crypto SigV4 primitives. Verified against AWS's documented presigned-URL example and a live MinIO round-trip.
  • @fileway/driver-cloudinary: presigned URLsgetPresignedUrl(publicId, { expiresIn, deliveryType }) returns a Cloudinary signed delivery URL (the /s--SIG--/ path component plus ?expires_at=) using the same { resourceType, version } hint / upload-cache / Admin API resolution chain as getUrl. The signature is the first 8 characters of a URL-safe base64 SHA-1 digest of the resource path concatenated with the API secret, computed purely with Web Crypto. expiresIn defaults to 3600 and must be a positive integer. The signature restricts access only for assets with authenticated/private delivery (pass deliveryType); upload-type assets created by CloudinaryDriver.upload are already public, so their signed URLs resolve but do not gate access. Signature format verified against Cloudinary's documented delivery-signature example.
  • New optional BaseDriver.getPresignedUrl? — S3 and Cloudinary implement it; Local omits it and FilewayClient.getPresignedUrl throws a clear error for drivers without support.
  • Upload progress (onProgress) — pass options.onProgress to client.upload() on any driver to receive { bytes, total?, progress? } as chunks flow through the stream (new exported UploadProgress type in @fileway/core). total/progress are reported only when options.size is known. Cadence is adaptive: chunks ≥ 256 KiB (or ≥ 5% of a known total) report immediately, smaller chunks coalesce to ~1 event per 100 ms, and an exact final event always fires (progress reaches exactly 1). No event fires on abort. Progress is counted at the client layer, so every driver gets it with zero driver changes; Cloudinary reports during its pre-signature Blob buffering (its fetch upload exposes no progress).
  • @fileway/driver-cloudinary: resource type resolution for getUrl/delete/getgetUrl(publicId, options?) and delete(publicId, options?) now resolve an asset's resource_type/version via an explicit hint ({ resourceType, version }), the in-memory upload cache, then a one-time Cloudinary Admin API resources/search lookup (Basic auth) before defaulting to image. Assets uploaded by another process or before a restart no longer produce broken /image/ URLs or failed deletes for video/raw files. delete now uses the Admin API DELETE /resources/{type}/upload endpoint with the resolved type and returns false for unknown assets without issuing a destroy call.
  • Upload cancellation (AbortSignal) — pass options.signal to client.upload() on any driver to cancel an in-flight upload. Drivers reject with a DOMException named AbortError (exported helper abortError() in @fileway/core). Local destroys both streams and unlinks the partial file; S3 aborts the request and, for multipart uploads, sends AbortMultipartUpload so no orphaned parts remain; Cloudinary aborts the upload request.
  • Streaming downloads (get(path)) — new BaseDriver.get(path): Promise<ReadableStream<Uint8Array>> method on every driver, with a FilewayClient.get(path) passthrough. Files stream back pull-based with backpressure instead of being buffered whole. Local streams from disk (createReadStreamReadable.toWeb), S3 uses an authenticated SigV4 GET, and Cloudinary fetches the public CDN URL. Missing paths throw.
  • @fileway/driver-s3: bounded-memory streaming uploads — pass options.size (≤ 5 GiB) and the payload is uploaded as a SigV4 aws-chunked body (STREAMING-AWS4-HMAC-SHA256-PAYLOAD); chunks are signed lazily as the stream is read, so memory stays constant regardless of file size.
  • @fileway/driver-s3: multipart uploads — unknown sizes and objects > 5 GiB now stream through a multipart upload (CreateMultipartUploadUploadPartCompleteMultipartUpload) into part-sized buffers (default 8 MiB, minimum 5 MiB), so peak memory stays bounded even without a declared size. Configurable via partSize and forceMultipart.
  • @fileway/driver-s3: size-mismatch safety — streams that end before/after the declared size abort the upload and throw a validation error instead of storing a corrupted object.
  • Launch docs: rewritten README.md, new CHANGELOG.md, and npm keywords on all four packages.

v0.0.5 — 2026-07-31

  • CI stability: build now runs before typecheck (drivers resolve @fileway/core types from build output); CI and release builds target only publishable packages (no docs build).
  • Cross-package version alignment at 0.0.5.

v0.0.4 — 2026-07-31

  • npm provenance via Trusted Publishers (OIDC) — no stored NPM_TOKEN; every publish ships SLSA attestation signed by GitHub Actions.
  • MIT licensing added to all packages.
  • Package READMEs with npm version and bundle-size badges.

v0.0.3 — 2026-07-31

First public release of all four packages.

  • @fileway/core — zero-dependency client engine, types, middleware pipeline.
  • @fileway/driver-s3 — rewritten to zero runtime dependencies: hand-rolled SigV4 signing over pure fetch + Web Crypto, streaming ReadableStream<Uint8Array> bodies. Removed @aws-sdk/lib-storage and all node:* imports.
  • @fileway/driver-cloudinary — rewritten to zero runtime dependencies: fetch + FormData + Web Crypto (crypto.subtle SHA-1 signatures). Removed the cloudinary SDK.
  • @fileway/driver-local — native node:fs streams with path-traversal guards and size limits.
  • Cross-runtime support verified: Node.js, Bun, Cloudflare Workers (edge-runtime tests), and Deno.
  • Conditional exports (worker, deno, bun, import, require) on every package.

On this page