-
Notifications
You must be signed in to change notification settings - Fork 504
Add staging DMG download route and S3 upload #3420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add staging DMG download route and S3 upload #3420
Conversation
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
✅ Deploy Preview for hyprnote-storybook canceled.
|
✅ Deploy Preview for hyprnote ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| throw redirect({ | ||
| href: "/api/download/staging-dmg", | ||
| } as any); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The redirect uses href property with an as any cast, which bypasses type checking. TanStack Router's redirect function expects a to property, not href. This will likely cause the redirect to fail silently or not work as expected.
Fix: Use the correct property name:
throw redirect({
to: "/api/download/staging-dmg",
});| throw redirect({ | |
| href: "/api/download/staging-dmg", | |
| } as any); | |
| throw redirect({ | |
| to: "/api/download/staging-dmg", | |
| }); |
Spotted by Graphite Agent
Is this helpful? React 👍 or 👎 to let us know.
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
…ase pattern) Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| } catch (error) { | ||
| console.error("Error fetching DMG from R2:", error); | ||
| return new Response("Failed to fetch file", { status: 500 }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 S3 NoSuchKey exception returns 500 instead of 404 for missing file
When the staging DMG file doesn't exist in S3, users receive a 500 error instead of a 404.
Click to expand
Problem
The code at apps/web/src/routes/api/download/staging-dmg.ts:49-51 catches all errors from the S3 SDK and returns a generic 500 status:
catch (error) {
console.error("Error fetching DMG from R2:", error);
return new Response("Failed to fetch file", { status: 500 });
}When S3's GetObjectCommand is called for a non-existent key, the AWS SDK throws a NoSuchKey exception rather than returning a response with no body. This means the if (!response.Body) check at line 30-32 is never reached for missing files.
Actual vs Expected
- Actual: Missing file returns HTTP 500 "Failed to fetch file"
- Expected: Missing file should return HTTP 404 "File not found"
Impact
Users visiting /download/staging before a staging build has uploaded a DMG will see a misleading 500 server error instead of a proper 404 not found response.
Recommendation: Check if the error is a NoSuchKey exception and return 404 in that case:
catch (error) {
if (error instanceof Error && error.name === 'NoSuchKey') {
return new Response("File not found", { status: 404 });
}
console.error("Error fetching DMG from R2:", error);
return new Response("Failed to fetch file", { status: 500 });
}Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Adds S3 upload for staging builds and creates a web route to download the latest staging DMG.
Changes:
s3://hyprnote-build/desktop/staging/hyprnote-macos-{arch}.dmg/download/stagingroute that redirects to/api/download/staging-dmg, which proxies the file from R2CLOUDFLARE_R2_ENDPOINT_URL,CLOUDFLARE_R2_ACCESS_KEY_ID,CLOUDFLARE_R2_SECRET_ACCESS_KEY)@aws-sdk/client-s3for R2 accessNote: Staging builds only target aarch64 (Apple Silicon) per the existing workflow matrix.
Review & Testing Checklist for Human
CLOUDFLARE_R2_ENDPOINT_URL,CLOUDFLARE_R2_ACCESS_KEY_ID, andCLOUDFLARE_R2_SECRET_ACCESS_KEYenvironment variables. Without these, the API route will fail.s3://hyprnote-build/desktop/staging/hyprnote-macos-aarch64.dmghttps://hyprnote.com/download/stagingand verifying the DMG downloads correctlydesktop/staging/) is the desired location for staging buildsRecommended test plan:
/download/stagingon the deployed siteNotes
The API route uses lazy S3 client initialization (inside the handler) to avoid module-level failures if credentials are missing during build.
Link to Devin run: https://app.devin.ai/sessions/200b9df8164246f4bde8d562d6909986
Requested by: @yujonglee