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
2 changes: 1 addition & 1 deletion lib/upload-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ export const uploadImageAssets = async (buffer: Buffer, key: string) => {
})
);

const publicUrl = `https://pub-6f0cf05705c7412b93a792350f3b3aa5.r2.dev/${key}`;
const publicUrl = `${process.env.R2_PUBLIC_URL}/${key}`;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Add validation and normalization for R2_PUBLIC_URL.

The code doesn't validate that R2_PUBLIC_URL is defined, which will result in URLs like "undefined/image.png" if the environment variable is missing. Additionally, if the URL has a trailing slash, the result will be malformed (e.g., "https://example.com//key").

Apply this diff to add validation and handle trailing slashes:

-  const publicUrl = `${process.env.R2_PUBLIC_URL}/${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;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const publicUrl = `${process.env.R2_PUBLIC_URL}/${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;
🤖 Prompt for AI Agents
In lib/upload-image.ts around line 26, the code builds publicUrl directly from
process.env.R2_PUBLIC_URL which may be undefined or contain a trailing slash;
update the code to first validate that process.env.R2_PUBLIC_URL is defined
(throw a clear error or return a failure if not), then normalize the value by
trimming whitespace and removing any trailing slash (or use the URL/URL
constructor to resolve paths) before concatenating the key so you never produce
"undefined/..." or double slashes; ensure the final join guarantees exactly one
slash between base URL and key.

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