From fc9c220be6737979ef3f8d108a74a7e2f806e2b6 Mon Sep 17 00:00:00 2001 From: Froidefond Julien Date: Sat, 14 Mar 2026 17:53:37 +0100 Subject: [PATCH] perf: stream Stripstream images and increase image fetch timeout Stream image responses directly to the client instead of buffering the entire image in memory, reducing perceived latency. Increase image fetch timeout from 15s to 60s to avoid AbortError on slow page loads. Co-Authored-By: Claude Opus 4.6 --- .../books/[bookId]/pages/[pageNumber]/route.ts | 15 ++++++++------- .../providers/stripstream/stripstream.client.ts | 3 ++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/app/api/stripstream/images/books/[bookId]/pages/[pageNumber]/route.ts b/src/app/api/stripstream/images/books/[bookId]/pages/[pageNumber]/route.ts index 5ca02fb..81a4536 100644 --- a/src/app/api/stripstream/images/books/[bookId]/pages/[pageNumber]/route.ts +++ b/src/app/api/stripstream/images/books/[bookId]/pages/[pageNumber]/route.ts @@ -35,14 +35,15 @@ export async function GET( const response = await client.fetchImage(path); const contentType = response.headers.get("content-type") ?? "image/jpeg"; - const buffer = await response.arrayBuffer(); + const contentLength = response.headers.get("content-length"); - return new NextResponse(buffer, { - headers: { - "Content-Type": contentType, - "Cache-Control": "public, max-age=86400", - }, - }); + const headers: Record = { + "Content-Type": contentType, + "Cache-Control": "public, max-age=86400", + }; + if (contentLength) headers["Content-Length"] = contentLength; + + return new NextResponse(response.body, { headers }); } catch (error) { logger.error({ err: error }, "Stripstream page fetch error"); diff --git a/src/lib/providers/stripstream/stripstream.client.ts b/src/lib/providers/stripstream/stripstream.client.ts index 842039d..d599173 100644 --- a/src/lib/providers/stripstream/stripstream.client.ts +++ b/src/lib/providers/stripstream/stripstream.client.ts @@ -3,6 +3,7 @@ import { ERROR_CODES } from "@/constants/errorCodes"; import logger from "@/lib/logger"; const TIMEOUT_MS = 15000; +const IMAGE_TIMEOUT_MS = 60000; interface FetchErrorLike { code?: string; cause?: { code?: string } } @@ -149,7 +150,7 @@ export class StripstreamClient { Accept: "image/webp, image/jpeg, image/png, */*", }); const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS); + const timeoutId = setTimeout(() => controller.abort(), IMAGE_TIMEOUT_MS); try { const response = await fetch(url, { headers, signal: controller.signal }); if (!response.ok) {