Conversation
adding motion!! animations!! and edited the main image viewer, video viewer is not coming tho, and markdown view is still in beta
Dokploy Preview Deployment
|
|
Warning Rate limit exceeded@hpware has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 6 minutes and 1 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
WalkthroughThis PR makes release/versioning changes (treating all versions as stable), removes several GitHub Actions release/build workflows, adds a motion dependency and UI/markdown enhancements, introduces server_owner and displayVersion settings, updates app version to 0.1.14, and modifies a DB migration value. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45–60 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
apps/web/src/app/c/[slug]/page.tsx (2)
36-39: Add error handling for missing user.The code accesses
getUserInfo[0]without verifying the array is non-empty. If the user referenced bycontent[0].byUserdoesn't exist in the database, this will throw a runtime error.Apply this diff to add error handling:
const getUserInfo = await db .select() .from(auth_schema.user) .where(dorm.eq(auth_schema.user.id, content[0].byUser)); + +if (getUserInfo.length === 0) { + notFound(); +}
74-77: Add error handling for missing user in generateMetadata.Same issue as in the Page component—
getUserInfo[0]is accessed without checking if the array is empty.Apply this diff:
const getUserInfo = await db .select() .from(auth_schema.user) .where(dorm.eq(auth_schema.user.id, content[0].byUser)); + +if (getUserInfo.length === 0) { + return { + title: "Undefined", + }; +}apps/web/src/app/dashboard/settings/clientComponents.tsx (1)
56-56: Typo in Content-Type header.
"appilcation/json"should be"application/json". This may cause the request to fail or be misinterpreted by the server.headers: { - "Content-Type": "appilcation/json", + "Content-Type": "application/json", },.github/workflows/auto-update-version.yml.disabled (1)
1-65: Disabled workflow file has been recently modified—clarify intent.The
.disabledextension prevents GitHub Actions from executing this workflow, yet it contains recently updated trigger configuration (pull_requestinstead ofpush). This mismatch suggests unclear intent:
- If intentionally disabled, the trigger changes are unnecessary and waste maintenance effort.
- If meant to be active, rename the file to
.github/workflows/auto-update-version.ymlto enable execution.Remove the
.disabledextension if this workflow should be enabled, or revert the recent trigger modifications if it should remain disabled.
♻️ Duplicate comments (1)
apps/web/src/components/navigation.tsx (1)
50-54: Type mismatch in feature gating logic.The disabled logic compares
feature_status.homeandfeature_status.searchagainsttrue, but the API returns strings (seeroute.tsline 29-30). This will cause the buttons to be incorrectly disabled.This is already flagged in the
route.tsreview. Please ensure the types are consistent between the API and consumer.Also applies to: 65-69
🧹 Nitpick comments (8)
apps/web/src/app/c/[slug]/page.tsx (2)
8-14: Remove unused imports.The imports for
Suspense,CalendarPlusIcon,CalendarSyncIcon,DotIcon,Link, andBadgeare no longer used in this component after the refactoring.Apply this diff to remove unused imports:
-import { Suspense } from "react"; import { auth } from "@devlogs_hosting/auth"; import { headers } from "next/headers"; import type { Metadata } from "next"; -import { CalendarPlusIcon, CalendarSyncIcon, DotIcon } from "lucide-react"; -import Link from "next/link"; -import { Badge } from "@/components/ui/badge"; import Client from "./client";
27-39: Consider extracting duplicate query logic.The same database queries are executed in both the
Pagecomponent andgenerateMetadata. This duplication can lead to maintenance issues and potential inconsistencies. Consider extracting the query logic into a shared function wrapped with React'scache()to ensure the queries are deduplicated during the same render.Example implementation:
import { cache } from 'react'; const getCollectionData = cache(async (slug: string) => { const content = await db .select() .from(main_schema.collections) .where(dorm.eq(main_schema.collections.id, slug)); if (content.length === 0) { return null; } const getUserInfo = await db .select() .from(auth_schema.user) .where(dorm.eq(auth_schema.user.id, content[0].byUser)); if (getUserInfo.length === 0) { return null; } return { content: content[0], userInfo: getUserInfo[0] }; });Then use this function in both
PageandgenerateMetadata.Also applies to: 64-77
apps/web/src/app/c/[slug]/client.tsx (1)
9-29: Most data props are currently unused.The component receives
userInfo,slug,createdAt, andupdatedAtbut only rendersdata.title. While this may be intentional for an incremental implementation, ensure these props are utilized or removed to maintain a clean API surface.apps/web/src/components/navigation.tsx (1)
77-83: Handle loading state for dynamic footer content.The footer displays dynamic content (
copyright_owner,version) but doesn't show a loading state. During initial load, empty strings will be displayed.Consider adding a loading skeleton:
<span className="text-sm mt-1"> - © {new Date().getFullYear()}{" "} - {querySystemData.data?.copyright_owner || ""}{" "} - {querySystemData.data?.optionalExposeVersion === true - ? `| v${querySystemData.data?.version}` - : null} + {querySystemData.isLoading ? ( + <span className="animate-pulse">Loading...</span> + ) : ( + <> + © {new Date().getFullYear()}{" "} + {querySystemData.data?.copyright_owner || ""}{" "} + {querySystemData.data?.optionalExposeVersion === true + ? `| v${querySystemData.data?.version}` + : null} + </> + )} </span>apps/web/package.json (1)
35-35: Duplicate motion dependency in workspace and root.The
motionlibrary (v12.23.26) is declared in both the rootpackage.jsonandapps/web/package.json. In a monorepo structure, this can lead to:
- Version drift if updated in one location but not the other
- Increased bundle size if both versions are installed
- Dependency management complexity
Choose one approach:
- Keep in workspace package only (recommended if only used in web app)
- Keep in root only if shared across multiple workspaces
- Use workspace catalog (add to
catalogsection in root package.json)If using workspace catalog:
// In root package.json "catalog": { "motion": "^12.23.26", // ... } // In apps/web/package.json "dependencies": { "motion": "catalog:", // ... }apps/web/src/components/publicPostsAndVideos.tsx (1)
170-185: Add exit animation for consistent user experience.The
AnimatePresencewrapper enables entry animation (fade-in) but lacks anexitprop on themotion.div, causing the ImageView to disappear abruptly when closed instead of fading out smoothly.Apply this diff to add a fade-out exit animation:
{imageViewSys.previewOn ? ( <motion.div key="box" initial={{ opacity: 0 }} animate={{ opacity: 1 }} + exit={{ opacity: 0 }} >apps/web/src/components/imageView.tsx (1)
36-42: Consider restoring Next.js Image component for optimization benefits.Switching from the Next.js
Imagecomponent to a standard<img>tag loses automatic optimizations including WebP conversion, responsive sizing, lazy loading, and blur placeholders. Note that theImageimport on Line 3 is now unused.If there's no specific reason requiring a standard img tag, apply this diff to restore the optimized Image component:
- <img + <Image src={imageSrc} alt="Preview Image" width={500} height={500} className="rounded-lg" />apps/web/src/components/markdownRender.tsx (1)
4-4: Remove unused font import.The
Ultrafont is imported but never used in this file, adding unnecessary bytes to the bundle.Apply this diff to remove the unused import:
-import { Ultra } from "next/font/google";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (20)
.github/scripts/increment-version.js(1 hunks).github/workflows/auto-update-version.yml.disabled(1 hunks).github/workflows/build_docker_image.yml.disabled(0 hunks).github/workflows/production-release.yml(0 hunks).github/workflows/version-and-build.yml(0 hunks)apps/web/package.json(1 hunks)apps/web/projectData.ts(1 hunks)apps/web/src/app/api/data/settings/route.ts(10 hunks)apps/web/src/app/api/data/system_info/route.ts(1 hunks)apps/web/src/app/c/[slug]/client.tsx(1 hunks)apps/web/src/app/c/[slug]/page.tsx(4 hunks)apps/web/src/app/dashboard/settings/clientComponents.tsx(14 hunks)apps/web/src/app/dashboard/settings/page.tsx(1 hunks)apps/web/src/app/i/[slug]/page.tsx(3 hunks)apps/web/src/components/imageView.tsx(2 hunks)apps/web/src/components/markdownRender.tsx(2 hunks)apps/web/src/components/navigation.tsx(3 hunks)apps/web/src/components/publicPostsAndVideos.tsx(2 hunks)package.json(1 hunks)packages/db/src/migrations/0014_reflective_roughhouse.sql(1 hunks)
💤 Files with no reviewable changes (3)
- .github/workflows/production-release.yml
- .github/workflows/version-and-build.yml
- .github/workflows/build_docker_image.yml.disabled
🧰 Additional context used
🧬 Code graph analysis (4)
apps/web/src/components/publicPostsAndVideos.tsx (1)
apps/web/src/components/imageView.tsx (1)
ImageView(6-48)
apps/web/src/app/c/[slug]/page.tsx (2)
packages/db/src/index.ts (1)
db(5-7)apps/web/src/app/c/[slug]/client.tsx (1)
Client(9-29)
apps/web/src/components/navigation.tsx (2)
apps/web/src/components/mode-toggle.tsx (1)
ModeToggle(14-39)apps/web/src/components/user-menu.tsx (1)
UserMenu(15-59)
apps/web/src/app/api/data/settings/route.ts (1)
packages/db/src/index.ts (1)
db(5-7)
🔇 Additional comments (10)
packages/db/src/migrations/0014_reflective_roughhouse.sql (1)
2-3: Verify the value formatting matches the expected storage format.The
copyrightOwnervalue is now stored as'"Default Owner"'(a string containing double quotes), whileexposeVersionis stored as'false'(a plain string without inner quotes). This suggests thevaluecolumn stores JSON-formatted values, where:
- JSON strings require quotes:
"Default Owner"- JSON booleans don't:
falseHowever, if the column stores JSON, consider whether
'false'(string literal) should instead be a proper JSON boolean or if the application expects string representations.Run the following script to verify the schema and how these values are used:
#!/bin/bash # Description: Check kv_data table schema and usage patterns # Check the kv_data table schema echo "=== Checking kv_data table schema ===" rg -n "CREATE TABLE.*kv_data" -A 10 # Check how copyrightOwner values are retrieved/parsed echo -e "\n=== Checking copyrightOwner usage ===" rg -n "copyrightOwner" -C 3 # Check how exposeVersion values are retrieved/parsed echo -e "\n=== Checking exposeVersion usage ===" rg -n "exposeVersion" -C 3 # Look for JSON parsing of kv_data values echo -e "\n=== Checking for JSON parsing patterns ===" rg -n "JSON\\.parse.*kv_data|parse.*kv_data.*value" -C 2apps/web/src/app/c/[slug]/page.tsx (1)
41-55: LGTM—Data structure correctly passed to Client component.The data object structure matches the type definition in the Client component, ensuring type safety between the server and client components.
apps/web/src/app/c/[slug]/client.tsx (2)
1-4: Type imports are correctly structured.The imports are already using the
import typesyntax, which is optimal for type-only imports and ensures they're stripped during compilation.
1-29: File naming convention is misleading; no client-side features are required.The component doesn't use any client-side features (no state, effects, event handlers, or browser APIs), so the
"use client"directive is not necessary. The file is being called from a Server Component and serves only as a presentational component. While the filenameclient.tsxsuggests client-side functionality, the directive is only required when actually using client-side features. Consider renaming the file to reflect its actual behavior (e.g.,collection-display.tsx) to avoid confusion with the naming convention used elsewhere in the codebase.Likely an incorrect or invalid review comment.
apps/web/src/app/api/data/settings/route.ts (1)
65-73: LGTM!The
server_ownerpersistence and simplified response format are correctly implemented.apps/web/src/app/dashboard/settings/clientComponents.tsx (1)
154-171: LGTM!The new Server Owner input field is correctly wired to the state and follows the existing pattern for the other input fields.
apps/web/projectData.ts (1)
2-2: LGTM! Version bumped to stable release.The version has been updated from
0.1.13-canary-1to0.1.14, marking a stable release. This aligns with the simplified version management changes in the PR.apps/web/src/app/i/[slug]/page.tsx (1)
98-98: Good practice: lazy loading attribute added.Adding
loading="lazy"to the user avatar image improves page performance by deferring image loads until they're near the viewport.apps/web/src/components/navigation.tsx (1)
31-31: QueryClientProvider is properly configured.The
Providerscomponent is correctly imported and used in the root layout (apps/web/src/app/layout.tsx), wrapping the entire application tree. This ensures thatuseQueryClient()in the navigation component has access to the query client context.apps/web/src/components/markdownRender.tsx (1)
79-95: LGTM! List rendering implementation is solid.The list and listitem renderer methods correctly handle both ordered and unordered lists with appropriate styling and attributes. The start parameter for ordered lists is properly handled with a sensible default.
| const displayVersion = ( | ||
| await db | ||
| .select() | ||
| .from(main_schema.kvData) | ||
| .where(dorm.eq(main_schema.kvData.key, "exposeVersion")) | ||
| )[0].value; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n "exposeVersion" --type tsRepository: hpware/log
Length of output: 164
🏁 Script executed:
fd -e "seed" -e "migration" -e "init" --type f | head -20Repository: hpware/log
Length of output: 36
🏁 Script executed:
sed -n '80,115p' apps/web/src/app/api/data/settings/route.ts | cat -nRepository: hpware/log
Length of output: 1514
Potential runtime error if exposeVersion key doesn't exist.
The code accesses [0].value without verifying the query returned results. If the exposeVersion key is missing from kvData, this will throw a TypeError. While other queries in this block (lines 82-105) follow the same pattern, applying it to newly added code continues an unsafe practice.
Add null safety:
const displayVersion = (
await db
.select()
.from(main_schema.kvData)
.where(dorm.eq(main_schema.kvData.key, "exposeVersion"))
- )[0].value;
+ )[0]?.value ?? false;🤖 Prompt for AI Agents
In apps/web/src/app/api/data/settings/route.ts around lines 106 to 111, the code
assumes the query returns an entry and uses [0].value directly which will throw
if the "exposeVersion" key is missing; change the code to capture the query
result into a variable, check whether a row was returned before accessing
.value, and then either use a sensible default (e.g., null or an explicit
default string) or return/throw a clear error/log message; ensure you handle
this the same way other kvData lookups in the file handle missing keys for
consistency.
| const content: (typeof main_schema.collections.$inferSelect)[] = await db | ||
| .select() | ||
| .from(main_schema.collections) | ||
| .where(dorm.eq(main_schema.userPosts.postId, slug)); |
There was a problem hiding this comment.
Critical: Incorrect table reference in WHERE clause.
The query selects from main_schema.collections but filters using main_schema.userPosts.postId. This appears to be incorrect—the WHERE clause should likely reference main_schema.collections.id to match against the slug parameter.
Apply this diff to fix the table reference:
const content: (typeof main_schema.collections.$inferSelect)[] = await db
.select()
.from(main_schema.collections)
- .where(dorm.eq(main_schema.userPosts.postId, slug));
+ .where(dorm.eq(main_schema.collections.id, slug));📝 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.
| const content: (typeof main_schema.collections.$inferSelect)[] = await db | |
| .select() | |
| .from(main_schema.collections) | |
| .where(dorm.eq(main_schema.userPosts.postId, slug)); | |
| const content: (typeof main_schema.collections.$inferSelect)[] = await db | |
| .select() | |
| .from(main_schema.collections) | |
| .where(dorm.eq(main_schema.collections.id, slug)); |
🤖 Prompt for AI Agents
In apps/web/src/app/c/[slug]/page.tsx around lines 27 to 30, the WHERE clause is
referencing main_schema.userPosts.postId while selecting from
main_schema.collections; replace that reference with the correct collections
column (e.g., main_schema.collections.id) so the filter compares collections.id
to the slug (i.e., use dorm.eq(main_schema.collections.id, slug)). Ensure the
imported schema names are correct and adjust types if necessary.
| const content: (typeof main_schema.collections.$inferSelect)[] = await db | ||
| .select() | ||
| .from(main_schema.collections) | ||
| .where(dorm.eq(main_schema.userPosts.postId, resolvedParams.slug)); |
There was a problem hiding this comment.
Critical: Same incorrect table reference in generateMetadata.
The same database query error exists here—main_schema.userPosts.postId should be main_schema.collections.id.
Apply this diff:
const content: (typeof main_schema.collections.$inferSelect)[] = await db
.select()
.from(main_schema.collections)
- .where(dorm.eq(main_schema.userPosts.postId, resolvedParams.slug));
+ .where(dorm.eq(main_schema.collections.id, resolvedParams.slug));📝 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.
| const content: (typeof main_schema.collections.$inferSelect)[] = await db | |
| .select() | |
| .from(main_schema.collections) | |
| .where(dorm.eq(main_schema.userPosts.postId, resolvedParams.slug)); | |
| const content: (typeof main_schema.collections.$inferSelect)[] = await db | |
| .select() | |
| .from(main_schema.collections) | |
| .where(dorm.eq(main_schema.collections.id, resolvedParams.slug)); |
🤖 Prompt for AI Agents
In apps/web/src/app/c/[slug]/page.tsx around lines 64 to 67, the query in
generateMetadata uses the wrong table/column reference
(main_schema.userPosts.postId); change the where clause to compare the
collections primary key instead, e.g. use dorm.eq(main_schema.collections.id,
resolvedParams.slug) so the query selects from main_schema.collections by its
id; ensure the comparison uses the correct column (collections.id) and data type
matching resolvedParams.slug.
| <div className="pl-2"> | ||
| <Markdown renderer={renderer}>{content[0].textData ?? ""}</Markdown> | ||
| </div> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find the markdownRender component
fd -t f "markdownRender" --extension ts --extension tsx --extension js --extension jsxRepository: hpware/log
Length of output: 96
🏁 Script executed:
# Also search for the file more broadly
find . -type f -name "*markdown*" | grep -i renderRepository: hpware/log
Length of output: 98
🏁 Script executed:
# Check the exact file being reviewed to understand the context
cat -n "apps/web/src/app/i/[slug]/page.tsx" | head -80Repository: hpware/log
Length of output: 3131
🏁 Script executed:
cat -n "apps/web/src/components/markdownRender.tsx"Repository: hpware/log
Length of output: 3058
🏁 Script executed:
# Also check if DOMPurify or similar sanitization libraries are installed
rg "dompurify|sanitize|xss" --type=ts --type=tsx --type=json -iRepository: hpware/log
Length of output: 81
🏁 Script executed:
# Check package.json for security-related dependencies
cat apps/web/package.json | grep -A 50 "dependencies"Repository: hpware/log
Length of output: 1634
🏁 Script executed:
# Search for marked-react usage and configuration
rg "marked-react" -A 5 -B 5 -t ts -t tsxRepository: hpware/log
Length of output: 81
🏁 Script executed:
# Check if there are any security configurations in next.config or similar
find . -type f \( -name "next.config.*" -o -name ".eslintrc*" -o -name "tsconfig.json" \) -exec grep -l "marked\|security\|sanitize" {} \;Repository: hpware/log
Length of output: 36
🏁 Script executed:
# Check for any middleware or security headers configuration
rg "Content-Security-Policy\|helmet\|security" -t ts -t tsx -t jsRepository: hpware/log
Length of output: 81
🏁 Script executed:
# Search more broadly for marked-react usage
rg "marked-react" --max-count 20Repository: hpware/log
Length of output: 571
🏁 Script executed:
# Check the exact Markdown component usage in the page
rg "Markdown" apps/web/src/app/i/\[slug\]/page.tsx -A 3 -B 3Repository: hpware/log
Length of output: 601
🏁 Script executed:
# Look for any marked configuration or security settings
rg "marked\|Markdown" apps/web/src -l | head -20Repository: hpware/log
Length of output: 36
🏁 Script executed:
# Check if there's a marked configuration file
find . -type f -name "marked.config.*" -o -name ".markedrc*"Repository: hpware/log
Length of output: 36
🏁 Script executed:
# Check the promoBlock component to see how it uses Markdown (to compare usage patterns)
cat apps/web/src/app/dashboard/settings/about/promoBlock.tsxRepository: hpware/log
Length of output: 1587
🏁 Script executed:
# Search for any URL validation or sanitization functions in the codebase
rg "javascript:|data:|sanitize|validate.*url|safe.*url" --max-count 20Repository: hpware/log
Length of output: 3000
🏁 Script executed:
# Check if React Link component or next/link has any built-in URL validation
rg "as Route" -B 3 -A 3 | head -30Repository: hpware/log
Length of output: 2641
🏁 Script executed:
# Check marked-react npm documentation or source for default options
# Search for any HTML-related configuration in the codebase
rg "gfm|breaks|pedantic|mangle|smartypants|html.*true" apps/webRepository: hpware/log
Length of output: 36
🏁 Script executed:
# Verify the exact behavior by checking if marked-react passes any options
rg "Markdown" apps/web/src/components -A 2 -B 2Repository: hpware/log
Length of output: 36
🏁 Script executed:
# Check marked version from lock file
rg "marked.*:" bun.lock | head -5Repository: hpware/log
Length of output: 513
🏁 Script executed:
# Check marked library behavior by looking for any default options or configuration
# Search for how Markdown component is called throughout the app
rg "Markdown" apps/web/src --max-count 30Repository: hpware/log
Length of output: 506
🏁 Script executed:
# Check if there's any URL validation happening in the renderer or elsewhere
rg "href.*javascript|javascript.*href|validateUrl|isValidUrl|isSafeUrl" apps/webRepository: hpware/log
Length of output: 36
🏁 Script executed:
# Let me check the CodeRender component to see if there's any security pattern there
cat apps/web/src/components/markdownCodeBlock.tsxRepository: hpware/log
Length of output: 1543
🏁 Script executed:
# Check the exact behavior of Next.js Link with javascript: URLs and marked-react HTML handling
# Look for any security-related issues or discussions in the codebase
rg "XSS|security|vulnerability|sanitize" apps/web/src -iRepository: hpware/log
Length of output: 36
🏁 Script executed:
# Check if marked has any options being used via marked-react
# Look at how marked-react handles HTML by default
node -e "console.log(require('marked').defaults)" 2>/dev/null || echo "Check npm package for marked defaults"Repository: hpware/log
Length of output: 91
🏁 Script executed:
# Search for any utility functions that might validate URLs or prevent malicious protocols
rg "protocol|javascript:|data:" apps/web/src -iRepository: hpware/log
Length of output: 4061
🏁 Script executed:
# Check if there's any Content Security Policy configured
rg "csp|Content-Security-Policy" apps/webRepository: hpware/log
Length of output: 36
🏁 Script executed:
# Verify if Next.js Link component handles javascript: URLs safely
# Check if there's any protection against malicious protocols in the codebase
rg "normalizeUrl|sanitizeUrl|href.*http|startsWith.*http" apps/web/src -iRepository: hpware/log
Length of output: 484
🏁 Script executed:
# Check Next.js version to understand Link component security
cat apps/web/package.json | grep '"next"'Repository: hpware/log
Length of output: 77
🏁 Script executed:
# Check if there's a utility function for URL validation that should be reused
rg "startsWith.*http" apps/web/src -B 5 -A 5 | head -40Repository: hpware/log
Length of output: 1038
🏁 Script executed:
# Verify if Next.js 16 Link component has built-in protections
# Check if there are any security tests or validations related to Link component
rg "javascript:|protocol" apps/web -iRepository: hpware/log
Length of output: 36
🏁 Script executed:
# Final check: see if the renderer is used with any options or wrappers that add security
grep -A 10 "renderer={renderer}" apps/web/src/app/i/\[slug\]/page.tsxRepository: hpware/log
Length of output: 471
Add URL validation to the Markdown link handler to prevent javascript: protocol URLs.
User-generated markdown is rendered with a custom renderer, and while React auto-escapes text content and marked-react doesn't parse raw HTML by default, the link() handler in markdownRender.tsx does not validate URLs. Markdown containing malicious links like [click](javascript:alert(1)) will render as clickable links that may execute JavaScript.
The codebase already validates URLs elsewhere (e.g., clientComponents.tsx checks for https:// or http://). Apply similar validation to the markdown renderer's link handler:
link(href: string, text: string) {
// Only allow http, https, and relative URLs
const isValidUrl = href.startsWith("http://") ||
href.startsWith("https://") ||
href.startsWith("/");
if (!isValidUrl) return <span>{text}</span>;
return (
<Link
href={href as Route}
className="..."
target="_blank"
key={crypto.randomUUID()}
>
{text}
</Link>
);
}🤖 Prompt for AI Agents
In apps/web/src/app/i/[slug]/page.tsx around lines 69 to 71, the Markdown
renderer's link handler currently does not validate hrefs and can render
javascript: or other dangerous protocols; update the renderer's link(href, text)
to only allow http://, https://, or relative (starting with "/") URLs, returning
a plain span with the link text when validation fails, and otherwise render the
Link component (keep target and other props) so malicious javascript: links are
not clickable.
| const querySystemData = useQuery({ | ||
| queryFn: async () => { | ||
| const req = await fetch("/api/data/system_info"); | ||
| const res = await req.json(); | ||
| return res; | ||
| }, | ||
| queryKey: ["system_info"], | ||
| }); |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add error handling for the system info query.
The query lacks error handling. If the API request fails, the component will render without showing any error state to the user.
Add error handling:
const querySystemData = useQuery({
queryFn: async () => {
const req = await fetch("/api/data/system_info");
+ if (!req.ok) {
+ throw new Error(`Failed to fetch system info: ${req.status}`);
+ }
const res = await req.json();
return res;
},
queryKey: ["system_info"],
});Consider displaying an error state in the UI:
if (querySystemData.isError) {
console.error("Failed to load system info:", querySystemData.error);
// Optionally render error UI or fallback to default behavior
}🤖 Prompt for AI Agents
In apps/web/src/components/navigation.tsx around lines 32 to 39, the system_info
useQuery has no error handling; update the queryFn to detect failed fetches
(check response.ok and throw an Error with response status/text or include
caught network errors) so react-query receives errors, and in the component add
an isError branch to log the error (console.error("Failed to load system info:",
querySystemData.error)) and render an appropriate fallback UI or default values;
optionally set sensible query options (e.g., retry, staleTime) to control retry
behavior.
| "dependencies": { | ||
| "dotenv": "^17.2.3", | ||
| "geist": "^1.5.1", | ||
| "motion": "^12.23.26", |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
motion library latest version React animation 2025
💡 Result:
Do you mean the "Motion" package (motion.dev) or "framer-motion"? I can list both — which do you want?
🏁 Script executed:
# Check the root package.json and apps/web/package.json to understand the dependency structure
cat -n package.json | head -50Repository: hpware/log
Length of output: 1671
🏁 Script executed:
# Look for apps/web/package.json and check if motion is also there
find . -name "package.json" -type f | head -20Repository: hpware/log
Length of output: 148
🌐 Web query:
npm motion package v12.23.26 React animation library
💡 Result:
Yes — "motion" is a React (and JS/Vue) animation library (motion.dev). The package's current release series is 12.x and the latest published release is v12.23.26. Install with:
npm install motion
import { motion } from "motion/react"
Motion requires React 18.2+ and provides springs, keyframes, layout/shared layout animations, gestures, scroll/SVG support, exit animations, SSR, etc. [1][2][3]
Sources:
[1] Motion docs (install / React requirements).
[2] Package metadata showing latest version 12.23.26.
[3] motion GitHub repository / README.
🏁 Script executed:
# Check apps/web/package.json to see if motion is also declared there
cat -n ./apps/web/package.jsonRepository: hpware/log
Length of output: 2258
Remove motion from root dependencies — it's already in apps/web/package.json.
Version 12.23.26 is the latest release for the motion animation library and is correct. However, the dependency is unnecessarily declared in both the root package.json and apps/web/package.json at line 35. Since motion is only used by the web app, remove it from the root and keep it only in apps/web/package.json to avoid duplication and simplify dependency management in the monorepo.
🤖 Prompt for AI Agents
In package.json around line 35, the root package declares "motion": "^12.23.26"
which duplicates the dependency already declared in apps/web/package.json;
remove the "motion" entry from the root dependencies block so the package is
only declared in apps/web/package.json, then run the package manager's
install/lockfile update (e.g., npm/yarn pnpm install) to refresh the lockfile
and ensure no stale references remain.
Summary by CodeRabbit
New Features
Improvements
Chores
✏️ Tip: You can customize this high-level summary in your review settings.