Skip to content

07-playground - #5

Merged
simplygarvit merged 1 commit into
masterfrom
07-playground
Jul 23, 2026
Merged

simplygarvit merged 1 commit into
masterfrom
07-playground

Conversation

@simplygarvit

@simplygarvit simplygarvit commented Jul 23, 2026 •

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added dashboard actions for editing, deleting, and duplicating projects.
    • Added project favorite toggling with immediate status updates and feedback.
    • Added confirmation and editing dialogs with success/error notifications.
    • Google and GitHub sign-ins now redirect to the dashboard.
    • Enabled remote image loading across the application.
  • Bug Fixes

    • Improved dashboard refresh behavior after project and favorite changes.
    • Improved handling of project creation, editing, deletion, and duplication errors.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Dashboard project management now supports wired mutations, duplication, editing, deletion, and favorite toggling. Authentication callbacks and OAuth redirects are adjusted, while Next.js image and cross-origin settings are configured.

Changes

Dashboard project management

Layer / File(s) Summary
Dashboard data and star actions
modules/dashboard/types.ts, modules/dashboard/actions/index.ts
Project star-mark data is renamed and dashboard queries/mutations now scope star marks, map project users, revalidate the dashboard, and return or log failures.
Project mutation wiring
modules/dashboard/actions/index.ts, app/dashboard/page.tsx
Creation, deletion, editing, and duplication operations are updated and passed into ProjectTable.
Project table actions and favorites
modules/dashboard/components/marked-toggle.tsx, modules/dashboard/components/project-table.tsx
The table adds favorite toggling, project action handlers, dialogs, toasts, links, loading state, and updated row formatting.
Project creation flow
modules/dashboard/components/add-new-button.tsx
Project creation now uses TemplateSelectingModal, handles submission results with toasts, and routes successful creations to the playground.

Authentication callback and redirects

Layer / File(s) Summary
Authentication resolution and redirect
auth.ts, modules/auth/components/sign-in-form-client.tsx
JWT user lookup now uses token.sub, and Google/GitHub sign-ins explicitly redirect to /dashboard.

Next.js runtime configuration

Layer / File(s) Summary
Image and response configuration
next.config.js
Remote HTTPS images and COOP/COEP headers are configured, and React strict mode is disabled.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ProjectTable
  participant DashboardActions
  participant Database
  participant Dashboard
  User->>ProjectTable: select project action
  ProjectTable->>DashboardActions: invoke mutation
  DashboardActions->>Database: create, update, delete, or duplicate project
  Database-->>DashboardActions: mutation result
  DashboardActions->>Dashboard: revalidate /dashboard
  DashboardActions-->>ProjectTable: success or failure
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is too generic and does not describe the actual dashboard/auth/config changes in the pull request. Rename the PR to a concise, specific summary of the main change, such as the dashboard project management and auth updates.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 07-playground

Comment @coderabbitai help to get the list of available commands.

@simplygarvit
simplygarvit merged commit 4a50205 into master Jul 23, 2026
1 check was pending

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@modules/dashboard/actions/index.ts`:
- Around line 121-187: Update deleteProjectById, editProjectById, and
duplicateProjectById to obtain currentUser().id and require an authenticated
user before accessing the database. Scope each playground lookup, update,
delete, and duplication source query by both the provided project id and the
authenticated user’s id, including templateFiles reads, so actions only operate
on projects owned by that user.

In `@modules/dashboard/components/add-new-button.tsx`:
- Around line 24-44: The template modal’s handleCreateProject currently closes
before project creation completes. Update handleCreateProject in
template-selecting-modal.tsx to be async, await onSubmit, and close only when
submission succeeds; make onSubmit return a success result from handleSubmit in
add-new-button.tsx, and disable the modal’s submit button while the request is
in flight to prevent duplicate creations.

In `@modules/dashboard/components/project-table.tsx`:
- Around line 229-268: The project action controls in the dropdown menu should
be the menu items themselves rather than nested MarkedToggleButton or Link
elements. Update the relevant DropdownMenuItem instances in the project table to
use their polymorphic render support for the toggle button and both project
links, preserving their existing labels, icons, destinations, and handlers while
avoiding nested interactive controls.

In `@next.config.js`:
- Around line 3-12: Update the remotePatterns configuration in next.config.js to
replace the wildcard hostname with only the specific hosts used by the
application, or remove the remote pattern entirely when remote images are not
required. Preserve HTTPS and the existing pathname behavior for the retained
hosts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1cd62d41-cde7-408c-bb1d-7408b67a044e

📥 Commits

Reviewing files that changed from the base of the PR and between 1ce8b97 and c98a7b0.

📒 Files selected for processing (9)
  • app/dashboard/page.tsx
  • auth.ts
  • modules/auth/components/sign-in-form-client.tsx
  • modules/dashboard/actions/index.ts
  • modules/dashboard/components/add-new-button.tsx
  • modules/dashboard/components/marked-toggle.tsx
  • modules/dashboard/components/project-table.tsx
  • modules/dashboard/types.ts
  • next.config.js
💤 Files with no reviewable changes (1)
  • modules/dashboard/types.ts

Comment on lines +121 to +187
export const deleteProjectById = async (id: string) => {
try {
await db.playground.delete({
where: {
id,
},
});
revalidatePath("/dashboard");
} catch (error) {
console.log(error);
}
};

export const editProjectById = async (
id: string,
data: { title: string; description: string }
) => {
try {
await db.playground.update({
where: {
id,
},
data: data,
});
revalidatePath("/dashboard");
} catch (error) {
console.log(error);
}
};

export const duplicateProjectById = async (id: string) => {
const user = await currentUser();
if (!user?.id) {
throw new Error("User must be logged in to create a playground");
}
try {
const originalPlayground = await db.playground.findUnique({
where: { id },
include: {
templateFiles: true,
},
});
if (!originalPlayground) {
throw new Error("Original playground not found");
}

const duplicatedPlayground = await db.playground.create({
data: {
title: `${originalPlayground.title} (Copy)`,
description: originalPlayground.description,
template: originalPlayground.template,
userId: user.id,

templateFiles: {
create: originalPlayground.templateFiles.map((file) => ({
content: file.content ?? {},
})),
},
},
});

revalidatePath("/dashboard");
return duplicatedPlayground;
} catch (error) {
console.error("Error duplicating project:", error);
}
}; No newline at end of file
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
git ls-files 'modules/dashboard/actions/index.ts' 'modules/dashboard/**' | sed -n '1,120p'

printf '\n== outline index.ts ==\n'
ast-grep outline modules/dashboard/actions/index.ts --view expanded || true

printf '\n== relevant search ==\n'
rg -n "deleteProjectById|editProjectById|duplicateProjectById|toggleStarMarked|createPlayground|getAllPlaygroundForUser|currentUser\\(" modules/dashboard -S

printf '\n== target slice ==\n'
sed -n '1,260p' modules/dashboard/actions/index.ts

Repository: simplygarvit/project

Length of output: 6403


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== schema matches ==\n'
rg -n "model Playground|model TemplateFile|templateFiles|userId|starMark" prisma . -S

printf '\n== prisma schema slice ==\n'
for f in $(git ls-files 'prisma/*.prisma' 'schema.prisma' 'modules/**/schema.prisma'); do
  echo "--- $f ---"
  sed -n '1,260p' "$f"
done

Repository: simplygarvit/project

Length of output: 6717


Add ownership checks to playground actions

deleteProjectById and editProjectById operate on arbitrary IDs, and duplicateProjectById can read and clone any playground’s templateFiles. Scope all three to currentUser().id before mutating or reading so one signed-in user can’t delete, edit, or duplicate another user’s project.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modules/dashboard/actions/index.ts` around lines 121 - 187, Update
deleteProjectById, editProjectById, and duplicateProjectById to obtain
currentUser().id and require an authenticated user before accessing the
database. Scope each playground lookup, update, delete, and duplication source
query by both the provided project id and the authenticated user’s id, including
templateFiles reads, so actions only operate on projects owned by that user.

Comment on lines +24 to 44
const handleSubmit = async (data: {
title: string;
template: "REACT" | "NEXTJS" | "EXPRESS" | "VUE" | "HONO" | "ANGULAR";
description?: string;
}) => {
try {
setIsLoading(true);
const newProject = await createPlayground(data);
toast.success("Playground created successfully!");
setIsModalOpen(false);
if (newProject?.id) {
router.push(`/playground/${newProject.id}`);
setSelectedTemplate(data);

const res = await createPlayground(data);
if (res?.id) {
toast.success("Playground created successfully!");
setIsModalOpen(false);
router.push(`/playground/${res.id}`);
} else {
router.refresh();
toast.error("Failed to create playground.");
}
} catch (error) {
console.error("Error creating playground:", error);
toast.error("Failed to create playground. Please try again.");
} finally {
setIsLoading(false);
console.error(error);
toast.error("Failed to create playground.");
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm whether TemplateSelectingModal awaits onSubmit before calling onClose()
ast-grep outline modules/dashboard/components/template-selecting-modal.tsx --items all
rg -n "onClose|onSubmit|handleCreateProject" modules/dashboard/components/template-selecting-modal.tsx -A5 -B5

Repository: simplygarvit/project

Length of output: 3669


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the submit handler and any loading/submit guards in the button component
ast-grep outline modules/dashboard/components/add-new-button.tsx --items all
rg -n "handleSubmit|isSubmitting|isLoading|createPlayground|setSelectedTemplate|disabled|Button" modules/dashboard/components/add-new-button.tsx -A6 -B6

# Inspect the modal submit flow to confirm whether onSubmit is awaited or followed by synchronous close/reset
sed -n '175,205p' modules/dashboard/components/template-selecting-modal.tsx

Repository: simplygarvit/project

Length of output: 4015


Keep the template modal open until project creation succeeds

In modules/dashboard/components/template-selecting-modal.tsx, handleCreateProject calls onSubmit(...) and then onClose() immediately, so the dialog dismisses before createPlayground finishes. Make this flow async, await the submit, and only close on success; also disable the submit button while the request is in flight to avoid duplicate creates.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modules/dashboard/components/add-new-button.tsx` around lines 24 - 44, The
template modal’s handleCreateProject currently closes before project creation
completes. Update handleCreateProject in template-selecting-modal.tsx to be
async, await onSubmit, and close only when submission succeeds; make onSubmit
return a success result from handleSubmit in add-new-button.tsx, and disable the
modal’s submit button while the request is in flight to prevent duplicate
creations.

Comment on lines +229 to +268
<MarkedToggleButton
markedForRevision={project.starMarks?.[0]?.isMarked ?? false}
id={project.id}
/>
</DropdownMenuItem>
<DropdownMenuItem>
<Link
href={`/playground/${project.id}`}
className="flex items-center w-full"
>
<Eye className="h-4 w-4 mr-2" />
Open Project
</Link>
</DropdownMenuItem>
<DropdownMenuItem>
<Link href={`/playground/${project.id}`} target="_blank" className="flex items-center w-full">
<Link
href={`/playground/${project.id}`}
target="_blank"
className="flex items-center w-full"
>
<ExternalLink className="h-4 w-4 mr-2" />
Open in New Tab
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => handleEditClick(project)}>
<DropdownMenuItem
onClick={() => handleEditClick(project)}
>
<Edit3 className="h-4 w-4 mr-2" />
Edit Project
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleDuplicateProject(project)}>
<DropdownMenuItem
onClick={() => handleDuplicateProject(project)}
>
<Copy className="h-4 w-4 mr-2" />
Duplicate
</DropdownMenuItem>
<DropdownMenuItem onClick={() => copyProjectUrl(project.id)}>
<DropdownMenuItem
onClick={() => copyProjectUrl(project.id)}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the dropdown-menu primitive backing library and its onSelect/keydown handling
ast-grep outline components/ui/dropdown-menu.tsx --items all
rg -n "MenuPrimitive" components/ui/dropdown-menu.tsx -A3 -B3

Repository: simplygarvit/project

Length of output: 6549


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the local dropdown menu wrapper and the project-table usage context.
ast-grep outline components/ui/dropdown-menu.tsx --items all
ast-grep outline modules/dashboard/components/project-table.tsx --items all

# Read the relevant slices around DropdownMenuItem usage and MarkedToggleButton definition/imports.
rg -n "MarkedToggleButton|DropdownMenuItem|DropdownMenuItem asChild|href=.*playground|handleEditClick|handleDuplicateProject|copyProjectUrl" modules/dashboard/components/project-table.tsx -A6 -B6
rg -n "function DropdownMenuItem|export .*DropdownMenuItem" components/ui/dropdown-menu.tsx -A20 -B4
rg -n "function Button|export .*Button|asChild" components/ui/button.tsx -A30 -B8

Repository: simplygarvit/project

Length of output: 9385


🌐 Web query:

@base-ui/react/menu MenuPrimitive.Item nested button link keyboard Enter Space onSelect child interactive element

💡 Result:

In @base-ui/react/menu, Menu.Item is designed to handle user interaction primarily through the onClick event, as it renders as a native HTML element (often a button or a link) [1][2][3][4]. Key points regarding keyboard interaction, nested elements, and event handling include: 1. Interaction and Events: Unlike some other component libraries that use an onSelect prop to normalize mouse and keyboard events, Base UI relies on standard HTML event propagation [4]. Consequently, providing an onClick handler is the standard way to capture interactions from both mouse clicks and keyboard activation (Enter/Space) [2][4]. 2. Keyboard Activation: - When Menu.Item renders as a button, standard browser behavior ensures that both Enter and Space trigger the click event. - When Menu.Item is customized to render as a link (e.g., via Menu.LinkItem or by passing a custom component), there have been known issues where Enter key activation might not trigger the navigation as expected due to preventDefault behavior in the underlying button logic [5]. This has been addressed in recent versions to ensure links behave correctly [5]. - Regarding the Space key, standard web accessibility guidelines note that using Space to activate links can be problematic because Space is often used for scrolling the viewport [6]. As a result, Base UI does not natively treat Space as a trigger for navigation links within a menu [6]. 3. Nested Interactive Elements: Nesting interactive elements (like a button or link) inside a Menu.Item is generally discouraged in terms of accessibility, as it creates nested focusable elements within a single menu item, which violates the expected flat structure of the ARIA menu role [1][7]. If you need to render a custom interactive component, ensure it is passed correctly to the render prop, and if you are replacing the default element with a button, you may need to specify the nativeButton prop to ensure proper event handling and SSR compatibility [2]. 4. Best Practices: Always prioritize standard HTML tags (button for actions, a for links) and rely on the onClick event [2][4]. If you require complex custom behavior or need to prevent the menu from closing on selection, you may need to use event.preventDefault within your onClick handler, though you should check the latest documentation for specific Base UI event handling utilities if standard prevention does not suffice [6][8][9].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline components/ui/button.tsx --items all
ast-grep outline modules/dashboard/components/marked-toggle.tsx --items all

rg -n "return \\(|<Button|ButtonPrimitive|DropdownMenuItem|Link" components/ui/button.tsx modules/dashboard/components/marked-toggle.tsx -A24 -B8

Repository: simplygarvit/project

Length of output: 9174


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the marked toggle to determine whether it nests a real button inside the menu item.
ast-grep outline modules/dashboard/components/marked-toggle.tsx --items all
sed -n '1,220p' modules/dashboard/components/marked-toggle.tsx | cat -n

Repository: simplygarvit/project

Length of output: 3381


🌐 Web query:

@base-ui/react/menu Menu.Item docs render prop button link nested interactive elements

💡 Result:

In @base-ui/react, the Menu.Item component is designed for interactive items within a menu and defaults to rendering a div element [1][2][3]. To customize the rendered element—such as turning a menu item into a link or another interactive element—you can use the render prop [4][5]. This prop allows you to override the default element and is the recommended way to handle polymorphism, such as rendering an a tag [4][5]. For example, to render a Menu.Item as a link: <Menu.Item render={}> Navigate to Example </Menu.Item> Regarding nested interactive elements: 1. Polymorphism: If you use the render prop to change the Menu.Item into an anchor tag () or another interactive element, Base UI manages the composition by merging event handlers and props [4][6]. 2. Nesting Restrictions: Generally, nesting interactive elements (e.g., placing a button inside a Menu.Item) is discouraged and often invalid HTML/accessibility practice. Because Menu.Item is itself an interactive component intended to be the focusable target, you should avoid placing other interactive elements (like buttons or native inputs) as children inside it. If you need a link, use the render prop technique above rather than wrapping a link around or inside a standard Menu.Item [4]. 3. Composition: Base UI's composition system via the render prop is specifically designed to prevent conflicts by merging incoming props (like onClick) with internal behavior [6]. When using the render prop, ensure the provided element is compatible with the attributes the component injects [6].

Citations:


Render these actions as the menu item itself, not as nested controls. MenuPrimitive.Item is the interactive target here; nesting MarkedToggleButton/Link inside it can interfere with keyboard activation and event handling. Use the item’s polymorphic render support for the button/link cases instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modules/dashboard/components/project-table.tsx` around lines 229 - 268, The
project action controls in the dropdown menu should be the menu items themselves
rather than nested MarkedToggleButton or Link elements. Update the relevant
DropdownMenuItem instances in the project table to use their polymorphic render
support for the toggle button and both project links, preserving their existing
labels, icons, destinations, and handlers while avoiding nested interactive
controls.

Comment thread next.config.js
Comment on lines +3 to +12
images: {
remotePatterns: [
{
protocol: "https",
hostname: "*",
port: "",
pathname: "/**",
},
],
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the config plus any image usage references.
git ls-files | rg '^next\.config\.js$|(^|/)next\.config\.|next\.config\.js$|(^|/)Image\.' || true

echo '--- next.config.js ---'
cat -n next.config.js

echo '--- search for next/image and remotePatterns references ---'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/.next/**' 'remotePatterns|next/image|images:' .

Repository: simplygarvit/project

Length of output: 1818


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the files that use next/image and look for remote URL sources.
for f in \
  modules/home/header.tsx \
  app/\(root\)/page.tsx \
  modules/dashboard/components/project-table.tsx \
  modules/dashboard/components/add-repo.tsx \
  modules/dashboard/components/dashboard-sidebar.tsx \
  modules/dashboard/components/add-new-button.tsx \
  modules/dashboard/components/template-selecting-modal.tsx \
  app/\(auth\)/auth/sign-in/page.tsx
do
  echo "--- $f ---"
  sed -n '1,220p' "$f"
  echo
done

echo '--- remote URL scan ---'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/.next/**' 'src\s*=\s*["'\'']https?://|new URL\(|https?://' app modules .

Repository: simplygarvit/project

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the image sources used by the files that import next/image.
for f in \
  modules/home/header.tsx \
  app/\(root\)/page.tsx \
  modules/dashboard/components/project-table.tsx \
  modules/dashboard/components/add-repo.tsx \
  modules/dashboard/components/dashboard-sidebar.tsx \
  modules/dashboard/components/add-new-button.tsx \
  modules/dashboard/components/template-selecting-modal.tsx \
  app/\(auth\)/auth/sign-in/page.tsx
do
  echo "--- $f ---"
  rg -n 'src\s*=|import\s+Image|from\s+"next/image"|from\s+'\''next/image'\''' "$f" || true
  sed -n '1,220p' "$f" | sed -n '1,120p'
  echo
done

echo '--- remote URL scan ---'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/.next/**' 'https?://|new URL\(' app modules .

Repository: simplygarvit/project

Length of output: 50377


🌐 Web query:

Next.js remotePatterns hostname wildcard "*" search query parameter omitted semantics

💡 Result:

In Next.js, when the search property is omitted from a remotePatterns configuration object, the default behavior is that no query string is allowed in the image URL [1][2]. Specifically, if search is omitted, the matching logic strictly expects the source URL to have no query parameters [1][3]. If an image URL is provided that contains a query string while search is missing from the configuration, the request will fail with a 400 Bad Request error [1][2][3]. Key points regarding this behavior include: 1. Strict Matching: Each part of the image URL—including protocol, hostname, port, pathname, and search—is matched strictly against your defined remotePatterns [2]. 2. Omission Implication: While the wildcard is automatically implied for omitted protocol, port, or pathname properties in some contexts, the omission of the search property specifically enforces an empty query string requirement, rather than acting as a wildcard for any search parameter [1][2][3]. 3. Security: This design is intentional to prevent malicious actors from optimizing unauthorized URLs, such as those with unexpected query strings [1][3]. 4. Allowing Query Strings: If you need to allow query strings, you must explicitly define the search property. However, note that globs (wildcards) are not supported for the search property; it requires an exact match of the query string, including the leading question mark (e.g., search: '?v=123') [2][4]. To summarize, omitting the search property is the safest configuration because it denies all query parameters by default [1][3]. If your remote image URLs include dynamic query parameters, you must provide an exact string match in the search configuration, or the image will be blocked [2][4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Trace where `user.image` and project/user records are populated.
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/.next/**' 'user\.image|image:\s*|avatar|profile image|github avatar|google avatar|session.*image|picture' app modules prisma middleware.ts

echo '--- prisma schema ---'
cat -n prisma/schema.prisma

echo '--- auth-related files ---'
for f in middleware.ts modules/auth/components/sign-in-form-client* modules/auth/**/* app/api/**/* auth.ts auth.config.*; do
  [ -e "$f" ] && { echo "--- $f ---"; cat -n "$f"; echo; }
done

Repository: simplygarvit/project

Length of output: 15035


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect NextAuth provider configuration to see which remote image hosts are actually needed.
for f in auth.config.ts auth.config.js auth.ts modules/auth/**/*; do
  [ -e "$f" ] && {
    echo "--- $f ---"
    cat -n "$f"
    echo
  }
done

echo '--- auth config file list ---'
git ls-files | rg '^(auth\.config\.(ts|js)|auth\.(ts|js)|modules/auth/.*\.(ts|tsx|js|jsx))$'

Repository: simplygarvit/project

Length of output: 9430


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the dashboard action that persists `user.image` and the nearby auth/session code.
cat -n modules/dashboard/actions/index.ts | sed -n '1,180p'

Repository: simplygarvit/project

Length of output: 5324


🌐 Web query:

Next.js remotePatterns hostname wildcard syntax "*" valid docs

💡 Result:

Yes, wildcard syntax is officially supported for the hostname property within remotePatterns in Next.js [1][2]. The supported syntax for hostname wildcard matching is as follows: - *: Matches a single path segment or subdomain [1][2]. - : Matches any number of subdomains at the beginning of the hostname [1][2]. Important implementation details include: - The syntax cannot be used in the middle of a pattern [1][2]. - Matching is strict and case-sensitive [3]. - If you omit properties like protocol, port, pathname, or search in a pattern object, they default to `` (matching anything), though this is discouraged for security reasons as it may inadvertently allow unauthorized image sources [1][2]. - Newer versions of Next.js also allow defining remotePatterns using `new URL()` objects, which support these same wildcard patterns within the URL string [3][4]. Example configuration for subdomains: js module.exports = { images: { remotePatterns: [ { protocol: 'https', hostname: '.example.com', // Matches example.com and any subdomains like img.example.com }, ], }, }

Citations:


Restrict the image allowlist in next.config.js

hostname: "*" with pathname: "/**" is broader than needed for the current image sources. Narrow it to the specific hosts you use, or remove the remote pattern if remote images aren’t expected. search is already empty by default, so it doesn’t widen matching.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@next.config.js` around lines 3 - 12, Update the remotePatterns configuration
in next.config.js to replace the wildcard hostname with only the specific hosts
used by the application, or remove the remote pattern entirely when remote
images are not required. Preserve HTTPS and the existing pathname behavior for
the retained hosts.

This was referenced Jul 25, 2026
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.

1 participant