From 596c04d4d3a78e949009ea4e0956ee558cb2ef51 Mon Sep 17 00:00:00 2001 From: Richard R Date: Mon, 16 Feb 2026 15:46:30 -0700 Subject: [PATCH] feat(preview): improve failure recovery and configuration Update the client-side preview status logic to gracefully handle failed states and return fallback URLs. Add PDF worker tracing to the build configuration for preview-related API endpoints and include server-side error logging. --- next.config.ts | 9 +++++++++ src/lib/client-documents.ts | 18 ++++++++++++++++-- src/lib/server/document-previews.ts | 1 + 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/next.config.ts b/next.config.ts index de6f7dd..46689e3 100644 --- a/next.config.ts +++ b/next.config.ts @@ -17,6 +17,15 @@ const nextConfig: NextConfig = { '/api/whisper': [ './node_modules/ffmpeg-static/ffmpeg', ], + '/api/documents/blob/preview/ensure': [ + './node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs', + ], + '/api/documents/blob/preview/presign': [ + './node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs', + ], + '/api/documents/blob/preview/fallback': [ + './node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs', + ], }, }; diff --git a/src/lib/client-documents.ts b/src/lib/client-documents.ts index 3bdb954..092db4e 100644 --- a/src/lib/client-documents.ts +++ b/src/lib/client-documents.ts @@ -328,10 +328,24 @@ export async function getDocumentPreviewStatus( }; } + // Handle failed preview generation (500 with status: 'failed') const contentType = res.headers.get('content-type') || ''; if (contentType.includes('application/json')) { - const data = (await res.json().catch(() => null)) as { error?: string } | null; - throw new Error(data?.error || `Failed to load preview status (status ${res.status})`); + const data = (await res.json().catch(() => null)) as { + status?: string; + lastError?: string; + error?: string; + } | null; + if (data?.status === 'failed') { + return { + kind: 'pending', + status: 'failed', + retryAfterMs: 0, + fallbackUrl: documentPreviewFallbackUrl(id), + presignUrl: documentPreviewPresignUrl(id), + }; + } + throw new Error(data?.error || data?.lastError || `Failed to load preview status (status ${res.status})`); } throw new Error(`Failed to load preview status (status ${res.status})`); diff --git a/src/lib/server/document-previews.ts b/src/lib/server/document-previews.ts index 3089de2..99a72a0 100644 --- a/src/lib/server/document-previews.ts +++ b/src/lib/server/document-previews.ts @@ -388,6 +388,7 @@ export async function ensureDocumentPreview(doc: PreviewSourceDocument, namespac eTag: head.eTag, }); } catch (error) { + console.error(`[document-previews] Preview generation failed for ${doc.id} (type=${doc.type}):`, error); await markPreviewFailed(doc.id, namespaceKey, error); } }