v2.0.0 · MIT license · TypeScript
uploaderkit
File uploads for React and Node, from one shared contract.
Scopes both sides validate against, a headless uploader with progress / abort / compression, and a server storage service with pluggable providers.
Installation
npm install uploaderkitFeatures
Everything the package ships, from its own README.
One contract, both sides
a scope registry declares where a file lands, who may read it, what is accepted and how big it may be. The browser and the server validate against the same object, so a rejection is never a surprise at the end of a 40 MB upload.
Headless first
useUploaderowns selection, validation, compression, per-file progress, abort and error state; it renders nothing./uiis an opt-in skin over it, so an app with its own design system loses no behavior by skipping it.Client-side validation before the first byte
extension, size and magic numbers, so an
.exerenamed to.pdfnever leaves the machine.Real upload progress
the default strategy is XHR because
fetchstill has no usable upload progress in browsers. Every in-flight upload is abortable, per file or all at once.Image compression in the scope
declare
compressand images are downscaled and re-encoded before travelling. EXIF (GPS, camera) drops in the process.Pluggable transport
the
UploadStrategyis a single function(file, scope, entityId, { onProgress, signal }). Swap the endpoint, the auth header or the whole protocol without touching hook state.Server storage service
createStoragere-runs the same validation, encrypts the scopes that ask for it, and answers signed expiring URLs for private objects.Boot-time guards
a private scope on a provider that cannot sign, or an encrypted scope without an injected cipher, throws at construction. Deploys fail loudly instead of 500ing on the first upload.
Framework adapters
structural handlers for Express (the app owns multer) and for the Next.js App Router (native
Request/Response). No framework dependency is pulled in.Provider adapters
Google Cloud Storage (two-bucket layout), any S3-compatible backend (AWS, Cloudflare R2, Backblaze B2, MinIO, Wasabi) and an in-memory provider for tests. All optional peers: choosing GCS never installs the AWS SDK.
Named slots
SlottedUploaderfills one file per named position (letterhead, ID, tax certificate); a bulk drop routes each file to its slot and renames it so re-uploads overwrite in place.No cipher shipped by default
private scopes declare
encrypt: trueand the app injectsCryptoHooks.createAesGcmCryptois available as a reference implementation.You choose when the upload fires
uploadOn: 'select'sends as soon as a valid file lands;'manual'holds files untilupload()— the form-submit flow, reachable from the styled components throughcontrollerRef.onUploadStartannounces the moment a batch leaves.Retry with backoff + concurrency cap
opt-in resilience for flaky networks: transient strategy failures retry behind exponential backoff, and large batches queue behind a concurrency limit.
Confirmation dialogs built in
confirmRemove/confirmReplacegate destructive file actions behind an accessible dialog (focus lands on cancel), andConfirmDialogis exported for app-level use.Paste and camera capture
a focused dropzone accepts a pasted screenshot, and
captureopens the mobile camera directly.Translatable copy
every user-facing string flows through a labels object, on the client AND on the server. English by default,
ES_LABELSincluded, any language via a partial override.Rebrandable theme
the styled layer reads
--color-ui-*CSS variables so one:rootoverride rebrands the whole styled layer.Sizes, icons and motion
size='sm' | 'md'compacts every row and zone,iconswaps (or removes) the dropzone glyph, and the whole surface animates: rows fade in, the drag state scales the zone, overlays enter and exit with a transition, the uploading indicator pulses.Touch-first by default
on coarse pointers the zone reads as a tap target ("Toca para elegir un archivo") with press feedback instead of advertising a drag nobody can do;
captureopens the camera directly.
Entry points
Import only what you use; each subpath is tree-shaken independently.
- uploaderkit
- uploaderkit/react
- uploaderkit/ui
- uploaderkit/presets
- uploaderkit/server
- uploaderkit/server/express
- uploaderkit/server/next
- uploaderkit/adapters/s3
- uploaderkit/adapters/gcs
- uploaderkit/adapters/memory