Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ R2_UPLOAD_IMAGE_ACCESS_KEY_ID=
R2_UPLOAD_IMAGE_SECRET_ACCESS_KEY=
CLOUDFLARE_ACCOUNT_ID=
R2_UPLOAD_IMAGE_BUCKET_NAME=images
R2_PUBLIC_URL=

# Auth
BETTER_AUTH_SECRET=
Expand Down
8 changes: 7 additions & 1 deletion lib/upload-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export const uploadImageAssets = async (buffer: Buffer, key: string) => {
})
);

const publicUrl = `https://pub-6f0cf05705c7412b93a792350f3b3aa5.r2.dev/${key}`;
const baseUrl = process.env.R2_PUBLIC_URL;
if (!baseUrl) {
throw new Error("R2_PUBLIC_URL environment variable is not configured");
}
const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
const publicUrl = `${normalizedBase}/${key}`;
return publicUrl;
return publicUrl;
};
2 changes: 1 addition & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const nextConfig: NextConfig = {
remotePatterns: [
{
protocol: "https",
hostname: "pub-6f0cf05705c7412b93a792350f3b3aa5.r2.dev",
hostname: process.env.R2_PUBLIC_URL?.replace(/^https?:\/\//, "") || "",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Improve hostname extraction and handle missing R2_PUBLIC_URL.

The current implementation has several issues:

  1. The empty string fallback will create an invalid remotePatterns entry when R2_PUBLIC_URL is not set, potentially causing Next.js configuration errors.
  2. The regex approach doesn't handle URLs with path segments (e.g., https://example.com/bucket → invalid hostname example.com/bucket).
  3. If the URL lacks a protocol, the regex has no effect, which could lead to an invalid hostname.

Apply this diff to properly parse the hostname using the URL API:

+const getR2Hostname = () => {
+  const url = process.env.R2_PUBLIC_URL;
+  if (!url) {
+    console.warn("R2_PUBLIC_URL is not configured. R2 image optimization will not work.");
+    return undefined;
+  }
+  try {
+    // Ensure URL has protocol for parsing
+    const fullUrl = url.startsWith('http') ? url : `https://${url}`;
+    return new URL(fullUrl).hostname;
+  } catch (error) {
+    console.error("Invalid R2_PUBLIC_URL format:", url);
+    return undefined;
+  }
+};
+
 const nextConfig: NextConfig = {
   /* config options here */
   reactStrictMode: false,
   typescript: {
     ignoreBuildErrors: true,
   },
   images: {
-    remotePatterns: [
+    remotePatterns: [
+      ...(getR2Hostname() ? [{
-      {
         protocol: "https",
-        hostname: process.env.R2_PUBLIC_URL?.replace(/^https?:\/\//, "") || "",
-      },
+        hostname: getR2Hostname()!,
+      }] : []),
       {
         protocol: "https",
         hostname: "jdj14ctwppwprnqu.public.blob.vercel-storage.com",

This approach:

  • Uses the URL API for robust hostname extraction
  • Handles missing protocol gracefully
  • Excludes the pattern entirely if R2_PUBLIC_URL is not configured (rather than using an empty string)
  • Provides helpful warnings in the console

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In next.config.ts around line 13, the hostname extraction from R2_PUBLIC_URL is
brittle and can produce invalid remotePatterns entries; update the code to:
check if process.env.R2_PUBLIC_URL is set, if not omit the R2_REMOTE pattern
entirely and emit a console.warn; if set, ensure the value has a protocol
(prepend "https://" if missing), parse it with the URL constructor to extract
only the hostname (no path or port), and use that hostname in remotePatterns so
Next.js never receives an empty or path-containing host; also catch and warn on
URL parsing errors and fall back to omitting the pattern.

},
{
protocol: "https",
Expand Down