Skip to content
Closed
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
145 changes: 87 additions & 58 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,94 @@
import Image from "next/image";
"use client";

import { useState } from "react";
import ReactMarkdown from "react-markdown";

export default function Home() {
const [url, setUrl] = useState("");
const [loading, setLoading] = useState(false);
const [markdown, setMarkdown] = useState("");
const [error, setError] = useState("");

const handleGenerate = async () => {
setLoading(true);
setError("");
setMarkdown("");

try {
const response = await fetch("/api/generate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url }),
});
Comment on lines +17 to +22
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for files containing "generate" in api-related paths
echo "=== Searching for generate files in api directories ==="
find . -type f \( -name "*generate*" -o -path "*/api/*generate*" \) 2>/dev/null | head -20

echo ""
echo "=== Searching for route.ts/route.js files in api directory ==="
find . -type d -name "api" 2>/dev/null | head -5

echo ""
echo "=== Looking for route handlers using rg ==="
rg "api/generate" --type ts --type tsx --type js 2>/dev/null | head -20

echo ""
echo "=== Searching for handler functions or exports in api context ==="
rg "export.*POST|export.*GET|Route.*generate" --type ts --type tsx 2>/dev/null | head -20

echo ""
echo "=== Listing app/api structure if it exists ==="
ls -la app/api 2>/dev/null || echo "app/api directory not found"

echo ""
echo "=== Looking for route files in common NextJS locations ==="
find . -path "*/api/*" -name "route.*" 2>/dev/null

Repository: BeyteFlow/ReadmeGenAI

Length of output: 432


🏁 Script executed:

#!/bin/bash
# Find and read app/page.tsx to confirm the fetch call
echo "=== Content of app/page.tsx (lines 17-25) ==="
cat -n app/page.tsx 2>/dev/null | sed -n '15,25p' || echo "File not found"

echo ""
echo "=== Search for any fetch/POST calls to api routes ==="
rg "fetch.*api" --type tsx --type ts 2>/dev/null

echo ""
echo "=== Check entire app directory structure ==="
find app -type f -name "*.ts" -o -name "*.tsx" 2>/dev/null | head -20

echo ""
echo "=== Check if there are any handlers in alternative locations ==="
find . -type f \( -name "*.api.ts" -o -name "*.api.tsx" \) 2>/dev/null

Repository: BeyteFlow/ReadmeGenAI

Length of output: 642


The /api/generate route is missing from the codebase and must be created.

The component at line 18 makes a POST request to /api/generate, but no API route file exists. The app/api directory and corresponding route handler are required for this feature to function.

🤖 Prompt for AI Agents
In `@app/page.tsx` around lines 17 - 22, The page component calls
fetch("/api/generate") but that API route is missing; add a Next.js route
handler that exports an async POST function to handle the request, parse and
validate JSON body for { url }, perform the generation logic (or delegate to the
existing generator function/module), and return a JSON response with appropriate
status codes and error handling; specifically create an endpoint that accepts
POST, reads await request.json(), checks url is a non-empty string, calls the
generator (or returns a helpful error if generation fails), and responds with
new Response(JSON.stringify(result), { status: 200, headers: { "Content-Type":
"application/json" } }) or suitable error statuses.


const data = await response.json();

if (!response.ok) throw new Error(data.error || "Failed to generate");
Comment on lines +24 to +26
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

response.json() will throw an unhelpful error if the server returns non-JSON (e.g., an HTML 500 page).

If the API route is missing or the server returns a non-JSON response, response.json() throws a syntax error before you reach the response.ok check.

Proposed fix: check status before parsing
-      const data = await response.json();
-
-      if (!response.ok) throw new Error(data.error || "Failed to generate");
+      if (!response.ok) {
+        const data = await response.json().catch(() => ({}));
+        throw new Error(data.error || `Request failed (${response.status})`);
+      }
+
+      const data = await response.json();
📝 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 data = await response.json();
if (!response.ok) throw new Error(data.error || "Failed to generate");
if (!response.ok) {
const data = await response.json().catch(() => ({}));
throw new Error(data.error || `Request failed (${response.status})`);
}
const data = await response.json();
🤖 Prompt for AI Agents
In `@app/page.tsx` around lines 24 - 26, The code calls response.json()
unconditionally which throws on non-JSON responses (e.g., HTML 500) before you
check response.ok; change the flow in app/page.tsx so you first check
response.ok on the fetched response variable, and if !response.ok read the raw
response.text() (or include response.status) and throw an Error with that
text/status, otherwise call response.json() to parse into data; update the error
throw to include the server text or status and only parse JSON when the response
is successful.


setMarkdown(data.markdown);
} catch (err: unknown) {
if (err instanceof Error) {
setError(err.message);
} else {
setError(String(err));
}
} finally {
setLoading(false);
}
};

const copyToClipboard = () => {
navigator.clipboard.writeText(markdown);
alert("Copied to clipboard!");
};

return (
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the page.tsx file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{" "}
center.
</p>
<main className="min-h-screen bg-slate-950 text-slate-50 p-8">
<div className="max-w-4xl mx-auto space-y-8">
{/* Header */}
<div className="text-center space-y-2">
<h1 className="text-4xl font-bold tracking-tight text-blue-400">ReadmeGenAI</h1>
<p className="text-slate-400">Turn any GitHub URL into a professional README in seconds.</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={16}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"

{/* Input Section */}
<div className="flex gap-4">
<input
type="text"
placeholder="https://github.com/username/repo"
className="flex-1 bg-slate-900 border border-slate-800 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
value={url}
onChange={(e) => setUrl(e.target.value)}
/>
<button
onClick={handleGenerate}
disabled={loading || !url}
className="bg-blue-600 hover:bg-blue-500 disabled:opacity-50 px-6 py-2 rounded-lg font-medium transition-all"
>
Documentation
</a>
{loading ? "Generating..." : "Generate"}
</button>
</div>
</main>
</div>

{error && <div className="p-4 bg-red-900/20 border border-red-900 text-red-400 rounded-lg">{error}</div>}

{/* Output Section */}
{markdown && (
<div className="space-y-4 animate-in fade-in duration-700">
<div className="flex justify-between items-center">
<h2 className="text-xl font-semibold text-slate-300">Preview</h2>
<button
onClick={copyToClipboard}
className="text-sm bg-slate-800 hover:bg-slate-700 px-3 py-1 rounded border border-slate-700"
>
Copy Markdown
</button>
</div>
<div className="prose prose-invert max-w-none bg-slate-900 p-6 rounded-xl border border-slate-800 shadow-xl">
<ReactMarkdown>{markdown}</ReactMarkdown>
</div>
</div>
)}
</div>
</main>
);
}
}
Loading