Files
v2.admin.gaertan.art/src/app/api/image/[...key]/route.ts
2026-02-03 13:12:31 +01:00

52 lines
1.5 KiB
TypeScript

import { s3 } from "@/lib/s3";
import type { S3Body } from "@/types/s3";
import { GetObjectCommand } from "@aws-sdk/client-s3";
import type { NextRequest } from "next/server";
import { Readable } from "node:stream";
function isWebReadableStream(value: unknown): value is ReadableStream<Uint8Array> {
return !!value && typeof (value as ReadableStream<Uint8Array>).getReader === "function";
}
function toBodyInit(body: S3Body): BodyInit {
if (body instanceof Readable) {
return Readable.toWeb(body) as ReadableStream<Uint8Array>;
}
if (isWebReadableStream(body)) {
return body;
}
return body as BodyInit;
}
// Streams images from S3 for the admin app.
export async function GET(_req: NextRequest, context: { params: Promise<{ key: string[] }> }) {
const { key } = await context.params;
const s3Key = key.join("/");
try {
const command = new GetObjectCommand({
Bucket: `${process.env.BUCKET_NAME}`,
Key: s3Key,
});
const response = await s3.send(command);
if (!response.Body) {
return new Response("No body", { status: 500 });
}
const contentType = response.ContentType ?? "application/octet-stream";
return new Response(toBodyInit(response.Body as S3Body), {
headers: {
"Content-Type": contentType,
"Cache-Control": "public, max-age=3600",
"Content-Disposition": "inline", // use 'attachment' to force download
},
});
} catch (err) {
console.error(err);
return new Response("Image not found", { status: 404 });
}
}