Skip to content

feat: use GitHub API for desktop download links#91

Merged
AnthonyRonning merged 2 commits intomasterfrom
claude/issue-89-20250602_170246
Jun 2, 2025
Merged

feat: use GitHub API for desktop download links#91
AnthonyRonning merged 2 commits intomasterfrom
claude/issue-89-20250602_170246

Conversation

@AnthonyRonning
Copy link
Copy Markdown
Contributor

@AnthonyRonning AnthonyRonning commented Jun 2, 2025

Fixes #89

This PR updates the downloads page to use GitHub's latest release API instead of the NPM package.json version for constructing desktop download links.

Changes

  • Added githubRelease.ts utility to fetch latest GitHub release
  • Updated downloads page to use dynamic GitHub API data
  • Graceful fallback to package.json version if API fails
  • Loading indicator while fetching release information

Benefits

  • Ensures download links always point to actual latest desktop release
  • Prevents broken links when NPM version is bumped before desktop releases
  • Maintains reliability with fallback mechanism

Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • The downloads page now automatically displays the latest release version and download links, fetching this information directly from GitHub.
    • Release notes links are dynamically updated to point to the latest release.
  • Bug Fixes

    • Download links and version information will always reflect the most recent release, reducing the risk of outdated or incorrect links.
  • Refactor

    • Improved reliability and maintainability of the downloads page by fetching release data at runtime instead of relying on static versioning.

…on version

- Create githubRelease.ts utility to fetch latest release from GitHub API
- Update downloads page to use dynamic GitHub release data
- Add graceful fallback to package.json version if API fails
- Include loading indicator while fetching release info
- Fixes issue where NPM version bumps before desktop releases

Fixes #89

Co-authored-by: AnthonyRonning <AnthonyRonning@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2025

"""

Walkthrough

The download page logic was refactored to fetch the latest release version and download URLs for desktop platforms directly from GitHub at runtime, replacing the previous approach that used static URLs based on the local package version. A new utility module was added to handle GitHub API interactions and extract release information.

Changes

File(s) Change Summary
frontend/src/routes/downloads.tsx Refactored download page to fetch latest release info from GitHub, added state for URLs/version, updated UI logic.
frontend/src/utils/githubRelease.ts New module to fetch and process latest release info from GitHub, exposes utility functions and interfaces.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DownloadPage
    participant githubReleaseUtil as githubRelease.ts
    participant GitHubAPI

    User->>DownloadPage: Visit downloads page
    DownloadPage->>githubReleaseUtil: getLatestDownloadInfo()
    githubReleaseUtil->>GitHubAPI: Fetch latest release JSON
    GitHubAPI-->>githubReleaseUtil: Return release data
    githubReleaseUtil-->>DownloadPage: Return download URLs, version, release URL
    DownloadPage-->>User: Render download links and version info
Loading

Assessment against linked issues

Objective Addressed Explanation
Fetch latest desktop release info from GitHub for download links and version (#89)
Construct platform-specific download links using latest GitHub release, not local NPM version (#89)
Ignore signature checking, focus on download/version logic only (#89)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Possibly related PRs

  • Add download page #52: Introduced the static downloads page and route, which is directly refactored in this PR to use dynamic GitHub release info.

Poem

A bunny hopped to fetch the news,
Of downloads fresh for all to use!
Now links and versions, up-to-date,
Are fetched from GitHub—how first-rate!
With every click, the latest hop,
The download page is now tip-top!
🐇✨
"""


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6da262c and 1381e14.

📒 Files selected for processing (1)
  • frontend/src/utils/githubRelease.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/utils/githubRelease.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Cloudflare Pages
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

Added GitHub release API integration for accurate desktop download links, replacing NPM package version with dynamic latest release data.

  • Added frontend/src/utils/githubRelease.ts with typed interfaces and error handling for fetching release data
  • Updated frontend/src/routes/downloads.tsx to use dynamic GitHub API data with loading states and fallback logic
  • Implemented graceful fallback to package.json version if GitHub API fails
  • Added proper error handling and type safety for API responses
  • Structured download URL generation to support all desktop platforms consistently

2 file(s) reviewed, 3 comment(s)
Edit PR Review Bot Settings | Greptile

Comment thread frontend/src/utils/githubRelease.ts Outdated
Comment thread frontend/src/utils/githubRelease.ts
Comment thread frontend/src/routes/downloads.tsx
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
frontend/src/utils/githubRelease.ts (2)

66-71: Handle potential edge cases in download URL construction.

The current implementation assumes specific asset naming patterns but doesn't handle cases where assets might be missing or have different names.

Consider making the URL construction more robust by checking the actual assets in the release:

 export async function getLatestDownloadInfo(): Promise<DownloadInfo | null> {
   const release = await fetchLatestRelease();
   
   if (!release) {
     return null;
   }
+
+  // Fetch full release data with assets if needed
+  const fullRelease = await fetch(`https://api.github.com/repos/OpenSecretCloud/Maple/releases/latest`);
+  const releaseData = await fullRelease.json();
+  
+  // Find actual asset URLs instead of constructing them
+  const findAsset = (pattern: RegExp) => 
+    releaseData.assets?.find(asset => pattern.test(asset.name))?.browser_download_url;
   
   // Extract version number from tag (remove 'v' prefix if present)
   const version = release.tag_name.startsWith("v") 
     ? release.tag_name.slice(1) 
     : release.tag_name;
   
   const baseDownloadUrl = `https://github.com/OpenSecretCloud/Maple/releases/download/${release.tag_name}`;
   
   return {
     version,
     tagName: release.tag_name,
     downloadUrls: {
-      macOS: `${baseDownloadUrl}/Maple_${version}_universal.dmg`,
-      linuxAppImage: `${baseDownloadUrl}/Maple_${version}_amd64.AppImage`,
-      linuxDeb: `${baseDownloadUrl}/Maple_${version}_amd64.deb`,
-      linuxRpm: `${baseDownloadUrl}/Maple-${version}-1.x86_64.rpm`,
+      macOS: findAsset(/Maple_.*_universal\.dmg$/) || `${baseDownloadUrl}/Maple_${version}_universal.dmg`,
+      linuxAppImage: findAsset(/Maple_.*_amd64\.AppImage$/) || `${baseDownloadUrl}/Maple_${version}_amd64.AppImage`,
+      linuxDeb: findAsset(/Maple_.*_amd64\.deb$/) || `${baseDownloadUrl}/Maple_${version}_amd64.deb`,
+      linuxRpm: findAsset(/Maple-.*\.x86_64\.rpm$/) || `${baseDownloadUrl}/Maple-${version}-1.x86_64.rpm`,
     },
     releaseUrl: release.html_url,
   };
 }

5-10: Consider adding more fields to GitHubRelease interface.

The interface is minimal but functional. Consider adding fields that might be useful for future enhancements.

 interface GitHubRelease {
   tag_name: string;
   name: string;
   published_at: string;
   html_url: string;
+  prerelease: boolean;
+  draft: boolean;
+  assets?: Array<{
+    name: string;
+    browser_download_url: string;
+    size: number;
+  }>;
 }
frontend/src/routes/downloads.tsx (3)

31-36: Consider consolidating related state into a single object.

Multiple related state variables can lead to synchronization issues and make the code harder to maintain.

Consider consolidating the download-related state:

-  const [downloadUrls, setDownloadUrls] = useState<DownloadUrls>(FALLBACK_URLS);
-  const [currentVersion, setCurrentVersion] = useState<string>(FALLBACK_VERSION);
-  const [releaseUrl, setReleaseUrl] = useState<string>(
-    `https://github.com/OpenSecretCloud/Maple/releases/tag/${FALLBACK_TAG}`
-  );
-  const [isLoading, setIsLoading] = useState<boolean>(true);
+  const [releaseState, setReleaseState] = useState({
+    downloadUrls: FALLBACK_URLS,
+    currentVersion: FALLBACK_VERSION,
+    releaseUrl: `https://github.com/OpenSecretCloud/Maple/releases/tag/${FALLBACK_TAG}`,
+    isLoading: true,
+    error: null as string | null
+  });

Then update the useEffect accordingly:

         if (downloadInfo) {
-          setDownloadUrls(downloadInfo.downloadUrls);
-          setCurrentVersion(downloadInfo.version);
-          setReleaseUrl(downloadInfo.releaseUrl);
+          setReleaseState(prev => ({
+            ...prev,
+            downloadUrls: downloadInfo.downloadUrls,
+            currentVersion: downloadInfo.version,
+            releaseUrl: downloadInfo.releaseUrl,
+            error: null
+          }));
         }
       } catch (error) {
         console.error("Failed to load latest release info:", error);
-        // Keep fallback values
+        setReleaseState(prev => ({
+          ...prev,
+          error: "Failed to load latest release information"
+        }));
       } finally {
-        setIsLoading(false);
+        setReleaseState(prev => ({ ...prev, isLoading: false }));
       }

163-164: Enhance the loading indicator for better UX.

The current loading indicator is subtle and might not be noticeable to users. Consider making it more prominent or replacing it with a skeleton loader.

             <p className="text-sm">
-              Current version: <span className="font-mono text-foreground">{currentVersion}</span>
-              {isLoading && <span className="text-[hsl(var(--marketing-text-muted))]"> (loading...)</span>} •{" "}
+              Current version: {isLoading ? (
+                <span className="inline-block w-16 h-4 bg-[hsl(var(--marketing-text-muted))]/20 rounded animate-pulse"></span>
+              ) : (
+                <span className="font-mono text-foreground">{currentVersion}</span>
+              )} •{" "}
               <a
                 href={releaseUrl}
                 className="text-[hsl(var(--purple))] hover:underline"
                 target="_blank"
                 rel="noopener noreferrer"
               >
-                Release notes
+                {isLoading ? "Loading..." : "Release notes"}
               </a>
             </p>

47-49: Consider showing error messages to users.

Currently, API errors are only logged to the console. Users won't know if something went wrong and might assume the fallback URLs are the latest.

Add error state and display it to users:

       } catch (error) {
         console.error("Failed to load latest release info:", error);
-        // Keep fallback values
+        setReleaseState(prev => ({
+          ...prev,
+          error: "Unable to fetch latest release information. Showing fallback version."
+        }));
       } finally {

Then display the error message in the UI:

           <div className="text-center mt-8 space-y-2 text-[hsl(var(--marketing-text-muted))] max-w-2xl mx-auto">
+            {error && (
+              <p className="text-orange-500 text-sm mb-2">
+                ⚠️ {error}
+              </p>
+            )}
             <p>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3c596c and 6da262c.

📒 Files selected for processing (2)
  • frontend/src/routes/downloads.tsx (6 hunks)
  • frontend/src/utils/githubRelease.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: build-ios
  • GitHub Check: build-macos (universal-apple-darwin)
  • GitHub Check: build-linux
  • GitHub Check: browseruse-tests
🔇 Additional comments (3)
frontend/src/utils/githubRelease.ts (1)

61-71:

Details

✅ Verification successful

Verify download URL patterns match actual GitHub release assets.

The constructed download URLs follow specific naming patterns. Ensure these patterns match the actual file names in your GitHub releases.

Please verify that these URL patterns are correct by checking a recent release:


🏁 Script executed:

#!/bin/bash
# Description: Verify that the constructed download URLs match actual GitHub release assets

# Fetch the latest release data and extract asset names
echo "Fetching latest release assets..."
gh api repos/OpenSecretCloud/Maple/releases/latest --jq '.assets[].name'

echo -e "\nExpected patterns based on the code:"
echo "- Maple_VERSION_universal.dmg (macOS)"
echo "- Maple_VERSION_amd64.AppImage (Linux AppImage)"
echo "- Maple_VERSION_amd64.deb (Linux Deb)"
echo "- Maple-VERSION-1.x86_64.rpm (Linux RPM)"

Length of output: 807


Download URL patterns verified
Confirmed that for the latest release (v1.0.5), the generated URLs for macOS (.dmg), Linux AppImage (.AppImage), .deb, and RPM exactly match the asset names on GitHub. No changes required.

frontend/src/routes/downloads.tsx (2)

8-9: Good addition of required imports.

The imports for React hooks and the new GitHub release utility are correctly added.


19-28: Excellent fallback mechanism implementation.

The fallback constants provide a robust safety net if the GitHub API fails, ensuring users can still download the application.

Comment thread frontend/src/utils/githubRelease.ts
Comment thread frontend/src/routes/downloads.tsx
Add runtime validation to ensure the GitHub releases API response
contains the expected fields before casting to GitHubRelease interface.
This prevents runtime errors from malformed API responses and provides
better error messages for debugging.

Co-authored-by: AnthonyRonning <AnthonyRonning@users.noreply.github.com>
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Jun 2, 2025

Deploying maple with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1381e14
Status: ✅  Deploy successful!
Preview URL: https://66c81b31.maple-ca8.pages.dev
Branch Preview URL: https://claude-issue-89-20250602-170.maple-ca8.pages.dev

View logs

@AnthonyRonning AnthonyRonning merged commit 9d772dc into master Jun 2, 2025
10 checks passed
@AnthonyRonning AnthonyRonning deleted the claude/issue-89-20250602_170246 branch June 2, 2025 17:42
@coderabbitai coderabbitai Bot mentioned this pull request Jun 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Desktop download logic

1 participant