52 lines
1.5 KiB
TypeScript
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 });
|
|
}
|
|
}
|