tools/deploy

The steps nix run .#deploy (flake.nix) runs before wrangler deploy, in order.

release-check.mjs runs inside nix run .#deploy, before anything is published. It compares the newest release note in the build (release-notes.json, from the repo's RELEASES.md) with the one the live site serves, and refuses the deploy when they are the same: every deploy carries a note, which the site's update prompt shows to visitors whose tab is on an older version.

resources.mjs then makes the Worker's storage exist and current, on the deploy's temporary copy of worker/ (the flake's strudel.worker: the Worker with its own dependencies, nix/worker-closure.mjs). Every D1 database and KV namespace the production config binds without an id is looked up by name (a KV namespace by the title wrangler itself would give it, jevstrudel-<binding>), and created if the account has none; its id goes into the copy's wrangler.json, never the repo's. Every R2 bucket it binds (bucket_name, a name, so nothing is written) is created if the account has none, since wrangler deploy refuses a binding to a missing bucket. Then each database's pending migrations (worker/migrations/) are applied with d1 migrations apply --remote, so the Worker published next never runs against an older schema. From a terminal, wrangler lists the migrations and asks before applying them.