Store, track, and enrich media on your own Cloudflare account. Images, video, audio, documents. Config picks the backend; the package does the rest.
@pithy-sh/media
pithy add mediaMedia that knows what it is. Upload images, video, audio and documents; get back records you can query, with optional AI enrichment on your own Workers AI binding.
What it sits on
Config picks the backend per media type: images to R2 or Cloudflare Images, video to R2 or Stream, audio and documents always R2. Bytes never proxy through your Worker — the client uploads straight to Cloudflare.
Enrichment runs as a Workflow, so a slow model never blocks an upload.
The honest bit
Cloudflare Images and Stream buy you a delivery pipeline — variants, adaptive bitrate, a player. R2 buys you the bytes and nothing else, more cheaply. This package makes the choice config rather than architecture, but it is still a choice, and moving later means moving files.
If you build it yourself
An image pipeline is a project. A video pipeline is a department.
Bytes should never pass through your Worker. Minting the upload URL correctly for each backend is the price of that.
Images to R2 or Cloudflare Images, video to R2 or Stream — a decision that changes the record model and cannot be swapped later without moving files.
Sizes, formats, and the fact that the browser asking has opinions about all three.
Captioning, labeling and transcription are slow and fail; they belong in a Workflow, not a request.
Content hashing, so the same file uploaded twice is stored once and counted once.
pithy add mediaComposes with
Passwordless sessions, mobile and web both first-class. Magic link, email OTP, Google, Apple.
One encrypted store per environment, a worker-only master key, and automatic at-rest rotation.
General file storage in your own R2 bucket, with an owner, a quota, and a link you can take back.
In the dashboard
Every asset, its backend, its enrichment status, and what the models said about it.
The dashboard is the admin interface for your own application: whatever this capability writes, your team can look up, check and act on from a browser. Reading is free, forever, with no time limit. Connect the project when you deploy.
Everything else
Each one composes the same way. Nothing you skip costs you anything.
One command installs the package, wires its bindings into every environment your project declares, and runs its migrations.