Refactor code

This commit is contained in:
2026-02-03 13:12:31 +01:00
parent 8572e22c5d
commit 531bb8750e
23 changed files with 106 additions and 48 deletions

View File

@ -2,7 +2,7 @@ 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 "stream";
import { Readable } from "node:stream";
function isWebReadableStream(value: unknown): value is ReadableStream<Uint8Array> {
return !!value && typeof (value as ReadableStream<Uint8Array>).getReader === "function";

View File

@ -4,7 +4,7 @@ import type { S3Body } from "@/types/s3";
import { GetObjectCommand } from "@aws-sdk/client-s3";
import archiver from "archiver";
import type { NextRequest } from "next/server";
import { Readable } from "stream";
import { Readable } from "node:stream";
// Streams commission request files (single or zip) from S3.
type Mode = "display" | "download" | "bulk";
@ -17,13 +17,30 @@ function contentDisposition(filename: string, mode: Mode) {
}
function sanitizeZipEntryName(name: string) {
return name.replace(/[^\w.\- ()\[\]]+/g, "_").slice(0, 180);
return name.replace(/[^\w.\- ()[\]]+/g, "_").slice(0, 180);
}
function isWebReadableStream(value: unknown): value is ReadableStream<Uint8Array> {
return !!value && typeof (value as ReadableStream<Uint8Array>).getReader === "function";
}
function webStreamToAsyncIterable(stream: ReadableStream<Uint8Array>) {
const reader = stream.getReader();
return {
async *[Symbol.asyncIterator]() {
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
if (value) yield value;
}
} finally {
reader.releaseLock();
}
},
};
}
function toBodyInit(body: S3Body): BodyInit {
if (body instanceof Readable) {
return Readable.toWeb(body) as ReadableStream<Uint8Array>;
@ -141,9 +158,16 @@ export async function GET(req: NextRequest) {
if (body instanceof Readable) {
archive.append(body, { name: entryName });
} else if (isWebReadableStream(body)) {
archive.append(Readable.from(body as AsyncIterable<Uint8Array>), { name: entryName });
archive.append(Readable.from(webStreamToAsyncIterable(body)), { name: entryName });
} else if (body instanceof Blob) {
const stream = body.stream();
archive.append(Readable.from(webStreamToAsyncIterable(stream)), { name: entryName });
} else if (Buffer.isBuffer(body)) {
archive.append(body, { name: entryName });
} else if (body instanceof Uint8Array) {
archive.append(Buffer.from(body), { name: entryName });
} else {
archive.append(body as Buffer, { name: entryName });
throw new Error("Unsupported S3 body type for zip entry");
}
}

View File

@ -3,7 +3,7 @@
import { useEffect } from "react";
// Global error UI for the app router segment.
export default function Error({
export default function ErrorPage({
error,
reset,
}: {
@ -27,6 +27,7 @@ export default function Error({
<div className="flex justify-center gap-4 pt-2">
<button
type="button"
onClick={reset}
className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition"
>

View File

@ -21,6 +21,7 @@ export default function GlobalError({
</p>
<button
type="button"
onClick={reset}
className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition"
>