← Board
SC-30Ready for QAPhase Two · The First Floor

A drop on the holocron, for moving files between machines

Drop a file on one machine, pick it up on another. Two columns, a private store of its own, and no polling.

Full-width, below the tiles. Left half takes what you drop on it, right half lists what is in there with a download and a delete. It replaces wanting an FTP account somewhere: no third party, no server to patch, and it is already behind the gate.

Its own store, and that is not a preference

Public and private is a property of the store, not of a file in it. Podcast audio has to be public — a podcast client fetching an <enclosure> has no cookie to send — and a file drop has to be private. They cannot be the same store. Vercel's own guidance says the same thing under store limits: use separate stores to isolate public and private content.

So the store SC-20 created is left alone, and this gets a private one. It also means the delete button here cannot reach the audio, whatever anyone clicks.

Why nothing refreshes by itself

list() is an Advanced Operation and Hobby includes 2,000 a month. Polling the listing every five seconds is 720 an hour, so a page left open for three hours would spend the month and lock the store for thirty days. The listing moves on page load, after an upload, after a delete, and when you press refresh.

The first listing is rendered by the page rather than fetched on mount, so arriving costs one operation rather than two.

The file never touches the site

Uploads go straight from the browser to the store, with /api/drop/upload handing out a one-shot token. Through a Function instead, a file would be capped at 4.5 MB — the body limit — and the transfer would be paid for twice.

Downloads have to come back through /api/drop/file, because a private blob's URL answers to nobody without a token. That route streams it with Cache-Control: private, no-store.

Ceiling of 100 MB a file, because Vercel recommends against serving anything larger through a private store, and because 1 GB of storage does not survive many mistakes.

The gate is now carrying more than it was sized for

lib/holocron.ts says of itself:

This keeps a casual wanderer out and nothing more, which is the right size for a page with nothing in it.

The page no longer has nothing in it. The attempt counter lives in a cookie, so a private window resets it and two tries an hour is really unlimited guessing. Every route here checks the session server-side next to the call it guards, and a closed session gets a 404 that says nothing — but that is the door, not the lock. Real rate limiting needs server-side state keyed to something the visitor does not control.

Until that exists, the password is the whole of the security, and it should be long enough that unlimited guessing does not matter.

Not done until