mirror of
https://github.com/juherr/kill-the-news.git
synced 2026-06-20 22:03:48 +00:00
f150d40c45
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 <noreply@anthropic.com>
38 lines
1.0 KiB
TypeScript
38 lines
1.0 KiB
TypeScript
import { Context } from "hono";
|
|
import { Env } from "../types";
|
|
import { getAttachmentBucket } from "../utils/attachments";
|
|
|
|
export async function handle(c: Context<{ Bindings: Env }>): Promise<Response> {
|
|
const bucket = getAttachmentBucket(c.env);
|
|
if (!bucket) {
|
|
return new Response("Attachment storage not configured", { status: 404 });
|
|
}
|
|
|
|
const attachmentId = c.req.param("attachmentId");
|
|
const filename = c.req.param("filename");
|
|
|
|
if (!attachmentId || !filename) {
|
|
return new Response("Not found", { status: 404 });
|
|
}
|
|
|
|
const object = await bucket.get(attachmentId);
|
|
|
|
if (!object) {
|
|
return new Response("Not found", { status: 404 });
|
|
}
|
|
|
|
const headers = new Headers();
|
|
object.writeHttpMetadata(headers);
|
|
headers.set("etag", object.httpEtag);
|
|
headers.set("Cache-Control", "public, max-age=31536000, immutable");
|
|
|
|
if (!headers.get("Content-Disposition")) {
|
|
headers.set(
|
|
"Content-Disposition",
|
|
`attachment; filename="${decodeURIComponent(filename)}"`,
|
|
);
|
|
}
|
|
|
|
return new Response(object.body, { headers });
|
|
}
|