From d6d9144a21e1aac94d3fa41dda94d336535e6742 Mon Sep 17 00:00:00 2001 From: Dawn-Fighter Date: Wed, 27 May 2026 22:33:27 +0530 Subject: [PATCH 1/2] fix: use renderToBuffer instead of pdf().toBuffer() for resume download pdf().toBuffer() returns a PDFDocument object, not a Buffer, causing the Response to receive unusable data and throw 'Failed to generate resume'. Fix: - Replace pdf() with renderToBuffer() from @react-pdf/renderer which correctly returns a Node.js Buffer on the server side - Remove @ts-expect-error hack in route.ts since Buffer is now valid - Use anchor tag download instead of window.open() to avoid popup blockers - Show user-facing alert on failure instead of silent console.error Fixes #89 --- www/app/api/resume/route.ts | 4 +--- www/components/ClientResumeButton.tsx | 7 ++++++- www/lib/resume.tsx | 6 +++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/www/app/api/resume/route.ts b/www/app/api/resume/route.ts index 89bc2412..7a304ddc 100644 --- a/www/app/api/resume/route.ts +++ b/www/app/api/resume/route.ts @@ -10,10 +10,8 @@ export async function GET(request: NextRequest) { return Response.json({ error: "Username is required" }, { status: 400 }); } - const pdfInstance = await generateResumePDF(username); - const pdfBuffer = await pdfInstance.toBuffer(); + const pdfBuffer = await generateResumePDF(username); - //@ts-expect-error -- todo: fix this later return new Response(pdfBuffer, { headers: { "Content-Type": "application/pdf", diff --git a/www/components/ClientResumeButton.tsx b/www/components/ClientResumeButton.tsx index 6007ff0b..a6a4f7b4 100644 --- a/www/components/ClientResumeButton.tsx +++ b/www/components/ClientResumeButton.tsx @@ -22,9 +22,14 @@ export default function ClientResumeButton({ username }: { username: string }) { const blob = await response.blob(); const url = URL.createObjectURL(blob); - window.open(url, "_blank"); + const a = document.createElement("a"); + a.href = url; + a.download = `${username}-resume.pdf`; + a.click(); + URL.revokeObjectURL(url); } catch (error) { console.error("Error downloading resume:", error); + alert("Failed to generate resume. Please try again."); } finally { setIsLoading(false); } diff --git a/www/lib/resume.tsx b/www/lib/resume.tsx index 349bf7f3..5d97a328 100644 --- a/www/lib/resume.tsx +++ b/www/lib/resume.tsx @@ -3,7 +3,7 @@ import { Image, Link, Page, - pdf, + renderToBuffer, StyleSheet, Text, View, @@ -379,7 +379,7 @@ async function getResumeData(username: string): Promise { }; } -export async function generateResumePDF(username: string) { +export async function generateResumePDF(username: string): Promise { const resumeData = await getResumeData(username); - return pdf(); + return renderToBuffer(); } From 3baacdaea3d398a599488bcf76664c2ce9526adf Mon Sep 17 00:00:00 2001 From: Dawn-Fighter Date: Wed, 27 May 2026 22:36:06 +0530 Subject: [PATCH 2/2] fix: append anchor to DOM before click for Firefox compatibility --- www/components/ClientResumeButton.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/www/components/ClientResumeButton.tsx b/www/components/ClientResumeButton.tsx index a6a4f7b4..14d0078f 100644 --- a/www/components/ClientResumeButton.tsx +++ b/www/components/ClientResumeButton.tsx @@ -25,7 +25,9 @@ export default function ClientResumeButton({ username }: { username: string }) { const a = document.createElement("a"); a.href = url; a.download = `${username}-resume.pdf`; + document.body.appendChild(a); a.click(); + document.body.removeChild(a); URL.revokeObjectURL(url); } catch (error) { console.error("Error downloading resume:", error);