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 API —
UploadOptions,UploadResult<TMeta>,BaseDriver, andFilewayClientlock in 1.0 semantics. Breaking changes become semver-major. - True streaming uploads — ✅ landed for S3:
aws-chunkedper-chunk SigV4 signing viaoptions.size, plus bounded-memory multipart uploads for unknown sizes and very large objects. - Upload cancellation — ✅ landed for all drivers:
options.signalrejects withAbortErrorand cleans up partial artifacts. - Middleware stream transformation —
beforeUploadwill be able to transform the stream itself, not just options. - Operational hardening — progress events ✅ landed (
options.onProgress); classified error types ✅ landed (StorageErrorcodes); 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+onErrorcallbacks —FilewayClientconfig now accepts a dependency-freelogger({ debug?, info?, warn?, error? }) and anonError(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"infoevents (structured meta:operation,path,filename,size,id,url,durationMs) anderroron failures — silent when omitted, and a throwing logger never breaks the operation it reports on.onErroris awaited with the raw error plus{ operation, durationMs, path, ... }context before the error is rethrown; it is skipped for aborts (AbortErroris cancellation, not failure) but fires forValidationError/configerrors, and a throwingonErrornever masks the original error. New exports:Logger,LogLevel,Operation,ErrorContextin@fileway/core. - Typed error taxonomy —
@fileway/corenow exports a singleStorageError(with theStorageErrorCodeunion:validation,config,not-found,bucket-not-found,auth-failed,size-exceeded,network,provider-error) carrying optionalstatusCode,provider, andcause, plusisAbortError().ValidationErroris now aStorageErrorsubclass (code === "validation",instanceofbehavior unchanged), and abort signals still surface as standardDOMException/AbortError. All drivers throw typed errors instead of genericErrors: S3 classifies AWS/MinIO XML<Code>responses (NoSuchBucket,NoSuchKey/NoSuchUpload,AccessDenied/InvalidAccessKeyId/SignatureDoesNotMatch/ExpiredToken/InvalidToken,EntityTooLarge) with an HTTP-status fallback, wraps non-abortfetchfailures asnetwork(preserving the cause), and throwsconfigwhen credentials are missing; Cloudinary maps status (401/403 →auth-failed, upload 404 →bucket-not-found, get 404 →not-found, 413 →size-exceeded, elseprovider-error); Local classifies missing files asnot-found;FilewayClient.getPresignedUrlthrowsconfigfor drivers without presigned-URL support. Message strings are unchanged, so existing callers keep working. This is the foundation for retries (retrynetwork/provider-erroronly). @fileway/driver-s3: presigned URLs —getPresignedUrl(path, { expiresIn })(with aFilewayClient.getPresignedUrlpassthrough) 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 onlyhostis signed with anUNSIGNED-PAYLOADhash.expiresIndefaults to3600seconds and must be an integer in1..604800(AWS's 7-day cap) or aValidationErroris thrown. Works withendpoint/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 URLs —getPresignedUrl(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 asgetUrl. The signature is the first 8 characters of a URL-safe base64SHA-1digest of the resource path concatenated with the API secret, computed purely with Web Crypto.expiresIndefaults to3600and must be a positive integer. The signature restricts access only for assets withauthenticated/privatedelivery (passdeliveryType);upload-type assets created byCloudinaryDriver.uploadare 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 andFilewayClient.getPresignedUrlthrows a clear error for drivers without support. - Upload progress (
onProgress) — passoptions.onProgresstoclient.upload()on any driver to receive{ bytes, total?, progress? }as chunks flow through the stream (new exportedUploadProgresstype in@fileway/core).total/progressare reported only whenoptions.sizeis 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 (progressreaches exactly1). 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-signatureBlobbuffering (itsfetchupload exposes no progress). @fileway/driver-cloudinary: resource type resolution forgetUrl/delete/get—getUrl(publicId, options?)anddelete(publicId, options?)now resolve an asset'sresource_type/versionvia an explicit hint ({ resourceType, version }), the in-memory upload cache, then a one-time Cloudinary Admin APIresources/searchlookup (Basic auth) before defaulting toimage. Assets uploaded by another process or before a restart no longer produce broken/image/URLs or failed deletes for video/raw files.deletenow uses the Admin APIDELETE /resources/{type}/uploadendpoint with the resolved type and returnsfalsefor unknown assets without issuing a destroy call.- Upload cancellation (
AbortSignal) — passoptions.signaltoclient.upload()on any driver to cancel an in-flight upload. Drivers reject with aDOMExceptionnamedAbortError(exported helperabortError()in@fileway/core). Local destroys both streams and unlinks the partial file; S3 aborts the request and, for multipart uploads, sendsAbortMultipartUploadso no orphaned parts remain; Cloudinary aborts the upload request. - Streaming downloads (
get(path)) — newBaseDriver.get(path): Promise<ReadableStream<Uint8Array>>method on every driver, with aFilewayClient.get(path)passthrough. Files stream back pull-based with backpressure instead of being buffered whole. Local streams from disk (createReadStream→Readable.toWeb), S3 uses an authenticated SigV4GET, and Cloudinary fetches the public CDN URL. Missing paths throw. @fileway/driver-s3: bounded-memory streaming uploads — passoptions.size(≤ 5 GiB) and the payload is uploaded as a SigV4aws-chunkedbody (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 (CreateMultipartUpload→UploadPart→CompleteMultipartUpload) into part-sized buffers (default8 MiB, minimum5 MiB), so peak memory stays bounded even without a declared size. Configurable viapartSizeandforceMultipart.@fileway/driver-s3: size-mismatch safety — streams that end before/after the declaredsizeabort the upload and throw a validation error instead of storing a corrupted object.- Launch docs: rewritten
README.md, newCHANGELOG.md, and npmkeywordson all four packages.
v0.0.5 — 2026-07-31
- CI stability: build now runs before typecheck (drivers resolve
@fileway/coretypes 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 purefetch+ Web Crypto, streamingReadableStream<Uint8Array>bodies. Removed@aws-sdk/lib-storageand allnode:*imports.@fileway/driver-cloudinary— rewritten to zero runtime dependencies:fetch+FormData+ Web Crypto (crypto.subtleSHA-1 signatures). Removed thecloudinarySDK.@fileway/driver-local— nativenode:fsstreams 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.