R2 replaced with local filesystem storage

andrsschultz swapped Cloudflare R2 out for a local `fs`-backed storage layer, removing the entire AWS SDK dependency tree. The replacement isn't pluggable - R2 is gone, not feature-flagged.

infrastructuresecurity

backend/src/lib/storage.ts is rewritten to read and write files under LOCAL_STORAGE_DIR (defaults to ./storage) using Node's built-in fs module. The four R2 env vars are dropped. @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner come out of backend/package.json, which is why the package-lock diff runs to ~2000 lines.

The presigned URL mechanism is replaced. Previously getSignedUrl() produced a time-limited S3 presign. Now it calls buildDownloadUrl() in downloadTokens.ts, returning a token-based URL instead. The frontend upload helper (frontend/src/lib/storage.ts) is deleted outright.

resolveStoragePath() includes a traversal guard worth reading: it explicitly rejects .. segments, absolute paths, drive letters, NUL bytes, and empty path components before constructing the full path.

The security model shifts when you adopt this - the old time-limited presign is gone. Audit downloadTokens.ts to understand what the token URLs actually enforce before adopting.

So what Worth a look if you're targeting air-gapped or single-machine deployments where R2 isn't available. Skip if you're running hosted - R2 is fine there and the token-URL security model change needs careful review before production use.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

1 commit from andrsschultz/mike, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
acbc99b7 Replace R2 storage with local filesystem asschultz 2026-04-30 ↗ GitHub

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-81.md from inside the repo you want the changes in.

⬇ Download capture-thread-81.md