feat(attachments): R2 toggle, storage metrics, and demo R2 config

Add an ATTACHMENTS_ENABLED switch (default on when R2 is bound) via a
central getAttachmentBucket helper, surface R2 + estimated KV usage
against the free tier on the status page and /api/stats (refreshed by the
hourly cron), let setup.sh create and wire the R2 bucket, and bind the
demo bucket so the deployed demo has attachments.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
Julien HerrandClaude Opus 4.7 committed 2026-05-23 17:33:50 +02:00
1 parent 7226e718f7
commit f150d40c45
19 files changed
+387 -23

No files matched your search

+3 -2
View File
@@ -7,6 +7,7 @@ import { waitUntilSafe } from "../../utils/worker";
import { feedRssUrl, feedEmailAddress } from "../../utils/urls";
import { logger } from "../../lib/logger";
import { sendUnsubscribes } from "../../utils/unsubscribe";
import { getAttachmentBucket } from "../../utils/attachments";
import { Layout } from "./ui";
import {
addFeedToList,
@@ -555,7 +556,7 @@ feedsRouter.post("/:feedId/delete", async (c) => {
waitUntilSafe(
c,
purgeFeedKeysStep(emailStorage, feedId, {
bucket: env.ATTACHMENT_BUCKET,
bucket: getAttachmentBucket(env),
}),
);
@@ -594,7 +595,7 @@ feedsRouter.post("/:feedId/purge", async (c) => {
const step = await purgeFeedKeysStep(emailStorage, feedId, {
cursor,
limit,
bucket: env.ATTACHMENT_BUCKET,
bucket: getAttachmentBucket(env),
});
return c.json({