diff --git a/docs/multi-step-integration-guide.md b/docs/multi-step-integration-guide.md
new file mode 100644
index 0000000..84e271f
--- /dev/null
+++ b/docs/multi-step-integration-guide.md
@@ -0,0 +1,491 @@
+# Multi-Step README Generation Pipeline - Integration Guide
+
+This guide provides complete instructions for integrating the multi-step README generation pipeline into an existing Next.js application, specifically for the ReadmeGenAI project.
+
+## ๐ Overview
+
+The new pipeline solves the token limit issues by:
+- **Section-by-section generation**: Each section is generated individually within token limits
+- **Retry logic**: Failed sections are automatically retried with simplified prompts
+- **Smart dependency management**: Sections are generated in optimal order based on dependencies
+- **Continuation support**: Truncated content can be automatically completed
+- **Fallback mechanisms**: Critical sections always have fallback content
+
+## ๐ Quick Integration
+
+### 1. Install Dependencies
+
+```bash
+npm install @google/generative-ai @octokit/rest
+```
+
+### 2. Replace Existing API Route
+
+Replace the content of `src/app/api/generate/route.ts`:
+
+```typescript
+import { handleReadmeGeneration } from '@/lib/multi-step-readme-generator';
+
+export async function POST(request: Request) {
+ return handleReadmeGeneration(request);
+}
+```
+
+### 3. Environment Variables
+
+Ensure these environment variables are set:
+
+```env
+GEMINI_API_KEY=your_gemini_api_key
+GITHUB_TOKEN=your_github_token # Optional but recommended for higher rate limits
+```
+
+### 4. Update Frontend (Optional)
+
+Enhance the frontend to show generation progress:
+
+```typescript
+// In your component
+const [generationStats, setGenerationStats] = useState(null);
+
+const handleGenerate = async (githubUrl: string) => {
+ setIsLoading(true);
+
+ try {
+ const response = await fetch('/api/generate', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ githubUrl }),
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ setReadme(result.readme);
+ setGenerationStats(result.stats);
+ } else {
+ setError(result.error);
+ }
+ } catch (error) {
+ setError('Generation failed');
+ } finally {
+ setIsLoading(false);
+ }
+};
+```
+
+## ๐ง Advanced Configuration
+
+### Custom Configuration
+
+You can customize the generation behavior:
+
+```typescript
+import { MultiStepReadmeGenerator } from '@/lib/multi-step-readme-generator';
+
+const generator = new MultiStepReadmeGenerator(
+ process.env.GEMINI_API_KEY!,
+ process.env.GITHUB_TOKEN,
+ {
+ maxRetries: 5, // Increase retries for better reliability
+ maxTokensPerSection: 1000, // Allow longer sections
+ temperature: 0.5, // More conservative generation
+ concurrentSections: 2, // Reduce concurrency to avoid rate limits
+ enableContinuation: true, // Enable automatic continuation
+ }
+);
+```
+
+### Custom Section Planning
+
+Define custom sections for specific project types:
+
+```typescript
+import { SectionPlanner, ReadmeSection } from '@/lib/multi-step-readme-generator';
+
+// Custom sections for a specific project type
+const customSections: ReadmeSection[] = [
+ {
+ id: 'header',
+ title: 'Project Header',
+ priority: 'critical',
+ order: 1,
+ estimatedTokens: 200,
+ dependencies: [],
+ },
+ {
+ id: 'quick-start',
+ title: 'Quick Start',
+ priority: 'high',
+ order: 2,
+ estimatedTokens: 400,
+ dependencies: ['header'],
+ },
+ // ... more sections
+];
+
+const result = await assembler.generateCompleteReadme(
+ metadata,
+ structure,
+ customSections
+);
+```
+
+## ๐ Monitoring and Analytics
+
+### Generation Stats
+
+The new pipeline provides detailed statistics:
+
+```typescript
+interface GenerationStats {
+ sectionsGenerated: number; // How many sections were successfully generated
+ sectionsTotal: number; // Total sections planned
+ tokensUsed: number; // Total tokens consumed
+ timeElapsed: number; // Generation time in milliseconds
+}
+```
+
+### Error Handling
+
+Comprehensive error information:
+
+```typescript
+interface GenerationResult {
+ success: boolean;
+ readme?: string;
+ stats: GenerationStats;
+ errors: string[]; // Detailed error messages
+}
+```
+
+### Logging Integration
+
+Add logging to track generation performance:
+
+```typescript
+// In your API route
+const result = await generator.generateReadme(githubUrl);
+
+// Log metrics
+console.log(`README generated for ${githubUrl}:`, {
+ success: result.success,
+ sectionsGenerated: result.stats.sectionsGenerated,
+ timeElapsed: result.stats.timeElapsed,
+ tokensUsed: result.stats.tokensUsed,
+});
+
+// Log errors for debugging
+if (result.errors.length > 0) {
+ console.error('Generation errors:', result.errors);
+}
+```
+
+## ๐ Migration from Existing Implementation
+
+### Step 1: Backup Current Implementation
+
+```bash
+# Backup current generate route
+cp src/app/api/generate/route.ts src/app/api/generate/route.ts.backup
+```
+
+### Step 2: Gradual Migration
+
+Implement a feature flag for gradual rollout:
+
+```typescript
+// src/app/api/generate/route.ts
+import { handleReadmeGeneration as newHandler } from '@/lib/multi-step-readme-generator';
+import { handleReadmeGeneration as oldHandler } from '@/lib/old-readme-generator';
+
+export async function POST(request: Request) {
+ const useNewPipeline = process.env.USE_NEW_README_PIPELINE === 'true';
+
+ if (useNewPipeline) {
+ return newHandler(request);
+ } else {
+ return oldHandler(request);
+ }
+}
+```
+
+### Step 3: A/B Testing
+
+Compare old vs new implementation:
+
+```typescript
+export async function POST(request: Request) {
+ const body = await request.json();
+ const { githubUrl, useNewPipeline } = body;
+
+ if (useNewPipeline) {
+ return handleReadmeGeneration(request);
+ } else {
+ // Use old implementation
+ return oldReadmeGeneration(request);
+ }
+}
+```
+
+## ๐ ๏ธ Troubleshooting
+
+### Common Issues and Solutions
+
+#### 1. Token Limit Exceeded
+
+**Problem**: Even individual sections exceed token limits
+**Solution**: Reduce `maxTokensPerSection` or simplify prompts
+
+```typescript
+const generator = new MultiStepReadmeGenerator(apiKey, githubToken, {
+ maxTokensPerSection: 600, // Reduce from default 800
+});
+```
+
+#### 2. Rate Limiting
+
+**Problem**: API rate limits exceeded
+**Solution**: Reduce concurrency and add delays
+
+```typescript
+const generator = new MultiStepReadmeGenerator(apiKey, githubToken, {
+ concurrentSections: 1, // Generate one section at a time
+});
+```
+
+#### 3. GitHub API Rate Limits
+
+**Problem**: Repository analysis fails due to rate limits
+**Solution**: Provide GitHub token and implement caching
+
+```typescript
+// Implement simple caching
+const cache = new Map();
+
+class CachedRepositoryAnalyzer extends RepositoryAnalyzer {
+ async analyzeRepository(owner: string, repo: string) {
+ const key = `${owner}/${repo}`;
+
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+
+ const result = await super.analyzeRepository(owner, repo);
+ cache.set(key, result);
+
+ return result;
+ }
+}
+```
+
+#### 4. Incomplete Sections
+
+**Problem**: Some sections are consistently incomplete
+**Solution**: Increase retries or customize prompts
+
+```typescript
+// Custom prompt for problematic section
+const customPrompts = {
+ installation: `Generate concise installation instructions for "${metadata.name}".
+
+ Context: ${structure.techStack.primary} project
+
+ Requirements:
+ - Prerequisites (if any)
+ - Single command installation
+ - Verification step
+
+ Keep it under 300 words. Return only markdown.`,
+};
+```
+
+### Debug Mode
+
+Enable detailed logging:
+
+```typescript
+// Set environment variable
+process.env.DEBUG_README_GENERATION = 'true';
+
+// In the generator
+if (process.env.DEBUG_README_GENERATION === 'true') {
+ console.log('Section generation details:', {
+ sectionId,
+ prompt: prompt.substring(0, 200) + '...',
+ result: result.success ? 'success' : 'failed',
+ tokensUsed: result.tokensUsed,
+ });
+}
+```
+
+## ๐ Performance Optimizations
+
+### 1. Caching Strategy
+
+Implement Redis caching for repository analysis:
+
+```typescript
+import Redis from 'ioredis';
+
+const redis = new Redis(process.env.REDIS_URL);
+
+class CachedAnalyzer extends RepositoryAnalyzer {
+ async analyzeRepository(owner: string, repo: string) {
+ const key = `repo:${owner}:${repo}`;
+ const cached = await redis.get(key);
+
+ if (cached) {
+ return JSON.parse(cached);
+ }
+
+ const result = await super.analyzeRepository(owner, repo);
+ await redis.setex(key, 3600, JSON.stringify(result)); // 1 hour cache
+
+ return result;
+ }
+}
+```
+
+### 2. Background Processing
+
+For large repositories, use background jobs:
+
+```typescript
+import Bull from 'bull';
+
+const readmeQueue = new Bull('readme generation');
+
+// API route for immediate response
+export async function POST(request: Request) {
+ const { githubUrl } = await request.json();
+
+ const job = await readmeQueue.add('generate', { githubUrl });
+
+ return Response.json({
+ jobId: job.id,
+ status: 'queued',
+ });
+}
+
+// Background worker
+readmeQueue.process('generate', async (job) => {
+ const { githubUrl } = job.data;
+ const generator = new MultiStepReadmeGenerator(...);
+
+ return generator.generateReadme(githubUrl);
+});
+```
+
+### 3. Streaming Responses
+
+Stream sections as they're generated:
+
+```typescript
+export async function POST(request: Request) {
+ const { githubUrl } = await request.json();
+
+ const stream = new ReadableStream({
+ async start(controller) {
+ const generator = new MultiStepReadmeGenerator(...);
+
+ // Override assembler to stream results
+ const originalAssembler = generator.assembler;
+ generator.assembler.generateSectionsInBatches = async (...args) => {
+ // Stream each section as it's completed
+ // Implementation details...
+ };
+
+ const result = await generator.generateReadme(githubUrl);
+ controller.close();
+ },
+ });
+
+ return new Response(stream, {
+ headers: {
+ 'Content-Type': 'text/event-stream',
+ 'Cache-Control': 'no-cache',
+ 'Connection': 'keep-alive',
+ },
+ });
+}
+```
+
+## ๐งช Testing
+
+### Unit Tests
+
+```typescript
+// __tests__/readme-generator.test.ts
+import { MultiStepReadmeGenerator, RepositoryAnalyzer } from '@/lib/multi-step-readme-generator';
+
+describe('MultiStepReadmeGenerator', () => {
+ it('should generate complete README for public repository', async () => {
+ const generator = new MultiStepReadmeGenerator(
+ process.env.GEMINI_API_KEY,
+ process.env.GITHUB_TOKEN
+ );
+
+ const result = await generator.generateReadme(
+ 'https://github.com/octocat/Hello-World'
+ );
+
+ expect(result.success).toBe(true);
+ expect(result.readme).toContain('# Hello-World');
+ expect(result.stats.sectionsGenerated).toBeGreaterThan(0);
+ });
+});
+```
+
+### Integration Tests
+
+```typescript
+describe('API Integration', () => {
+ it('should handle README generation request', async () => {
+ const response = await fetch('/api/generate', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ githubUrl: 'https://github.com/octocat/Hello-World'
+ }),
+ });
+
+ const result = await response.json();
+
+ expect(response.status).toBe(200);
+ expect(result.success).toBe(true);
+ expect(result.readme).toBeDefined();
+ });
+});
+```
+
+## ๐ API Reference
+
+### Main Classes
+
+- **`MultiStepReadmeGenerator`**: Main orchestrator class
+- **`RepositoryAnalyzer`**: Analyzes GitHub repositories
+- **`SectionPlanner`**: Plans optimal README sections
+- **`SectionGenerator`**: Generates individual sections
+- **`ReadmeAssembler`**: Assembles and validates final README
+
+### Configuration Options
+
+```typescript
+interface GenerationConfig {
+ maxRetries: number; // Default: 3
+ maxTokensPerSection: number; // Default: 800
+ temperature: number; // Default: 0.7
+ concurrentSections: number; // Default: 3
+ enableContinuation: boolean; // Default: true
+}
+```
+
+### Section Types
+
+- **Critical**: `header`, `description`, `installation`
+- **High**: `features`, `usage`, `api`
+- **Medium**: `configuration`, `development`, `contributing`, `deployment`
+- **Low**: `testing`, `examples`
+
+This comprehensive integration guide provides everything needed to successfully implement the multi-step README generation pipeline in the ReadmeGenAI project, solving the token limit issues while providing a more robust and reliable generation process.
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 9a1c38a..770db20 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,8 @@
"@radix-ui/react-slot": "^1.2.4",
"@vercel/analytics": "^2.0.1",
"lucide-react": "^0.577.0",
- "next": "16.2.3",
+ "next": "^16.2.4",
+ "next-auth": "^4.24.14",
"octokit": "^5.0.5",
"react": "19.2.4",
"react-dom": "19.2.4",
@@ -91,6 +92,7 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -269,7 +271,6 @@
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
"integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -341,9 +342,9 @@
"license": "MIT"
},
"node_modules/@emnapi/core": {
- "version": "1.9.2",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz",
- "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -353,9 +354,9 @@
}
},
"node_modules/@emnapi/runtime": {
- "version": "1.9.2",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz",
- "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1092,9 +1093,9 @@
}
},
"node_modules/@next/env": {
- "version": "16.2.3",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.3.tgz",
- "integrity": "sha512-ZWXyj4uNu4GCWQw9cjRxWlbD+33mcDszIo9iQxFnBX3Wmgq9ulaSJcl6VhuWx5pCWqqD+9W6Wfz7N0lM5lYPMA==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.4.tgz",
+ "integrity": "sha512-dKkkOzOSwFYe5RX6y26fZgkSpVAlIOJKQHIiydQcrWH6y/97+RceSOAdjZ14Qa3zLduVUy0TXcn+EiM6t4rPgw==",
"license": "MIT"
},
"node_modules/@next/eslint-plugin-next": {
@@ -1108,9 +1109,9 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "16.2.3",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.3.tgz",
- "integrity": "sha512-u37KDKTKQ+OQLvY+z7SNXixwo4Q2/IAJFDzU1fYe66IbCE51aDSAzkNDkWmLN0yjTUh4BKBd+hb69jYn6qqqSg==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.4.tgz",
+ "integrity": "sha512-OXTFFox5EKN1Ym08vfrz+OXxmCcEjT4SFMbNRsWZE99dMqt2Kcusl5MqPXcW232RYkMLQTy0hqgAMEsfEd/l2A==",
"cpu": [
"arm64"
],
@@ -1124,9 +1125,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "16.2.3",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.3.tgz",
- "integrity": "sha512-gHjL/qy6Q6CG3176FWbAKyKh9IfntKZTB3RY/YOJdDFpHGsUDXVH38U4mMNpHVGXmeYW4wj22dMp1lTfmu/bTQ==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.4.tgz",
+ "integrity": "sha512-XhpVnUfmYWvD3YrXu55XdcAkQtOnvaI6wtQa8fuF5fGoKoxIUZ0kWPtcOfqJEWngFF/lOS9l3+O9CcownhiQxQ==",
"cpu": [
"x64"
],
@@ -1140,9 +1141,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "16.2.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.3.tgz",
- "integrity": "sha512-U6vtblPtU/P14Y/b/n9ZY0GOxbbIhTFuaFR7F4/uMBidCi2nSdaOFhA0Go81L61Zd6527+yvuX44T4ksnf8T+Q==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.4.tgz",
+ "integrity": "sha512-Mx/tjlNA3G8kg14QvuGAJ4xBwPk1tUHq56JxZ8CXnZwz1Etz714soCEzGQQzVMz4bEnGPowzkV6Xrp6wAkEWOQ==",
"cpu": [
"arm64"
],
@@ -1156,9 +1157,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "16.2.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.3.tgz",
- "integrity": "sha512-/YV0LgjHUmfhQpn9bVoGc4x4nan64pkhWR5wyEV8yCOfwwrH630KpvRg86olQHTwHIn1z59uh6JwKvHq1h4QEw==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.4.tgz",
+ "integrity": "sha512-iVMMp14514u7Nup2umQS03nT/bN9HurK8ufylC3FZNykrwjtx7V1A7+4kvhbDSCeonTVqV3Txnv0Lu+m2oDXNg==",
"cpu": [
"arm64"
],
@@ -1172,9 +1173,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "16.2.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.3.tgz",
- "integrity": "sha512-/HiWEcp+WMZ7VajuiMEFGZ6cg0+aYZPqCJD3YJEfpVWQsKYSjXQG06vJP6F1rdA03COD9Fef4aODs3YxKx+RDQ==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.4.tgz",
+ "integrity": "sha512-EZOvm1aQWgnI/N/xcWOlnS3RQBk0VtVav5Zo7n4p0A7UKyTDx047k8opDbXgBpHl4CulRqRfbw3QrX2w5UOXMQ==",
"cpu": [
"x64"
],
@@ -1188,9 +1189,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "16.2.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.3.tgz",
- "integrity": "sha512-Kt44hGJfZSefebhk/7nIdivoDr3Ugp5+oNz9VvF3GUtfxutucUIHfIO0ZYO8QlOPDQloUVQn4NVC/9JvHRk9hw==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.4.tgz",
+ "integrity": "sha512-h9FxsngCm9cTBf71AR4fGznDEDx1hS7+kSEiIRjq5kO1oXWm07DxVGZjCvk0SGx7TSjlUqhI8oOyz7NfwAdPoA==",
"cpu": [
"x64"
],
@@ -1204,9 +1205,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "16.2.3",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.3.tgz",
- "integrity": "sha512-O2NZ9ie3Tq6xj5Z5CSwBT3+aWAMW2PIZ4egUi9MaWLkwaehgtB7YZjPm+UpcNpKOme0IQuqDcor7BsW6QBiQBw==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.4.tgz",
+ "integrity": "sha512-3NdJV5OXMSOeJYijX+bjaLge3mJBlh4ybydbT4GFoB/2hAojWHtMhl3CYlYoMrjPuodp0nzFVi4Tj2+WaMg+Ow==",
"cpu": [
"arm64"
],
@@ -1220,9 +1221,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "16.2.3",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.3.tgz",
- "integrity": "sha512-Ibm29/GgB/ab5n7XKqlStkm54qqZE8v2FnijUPBgrd67FWrac45o/RsNlaOWjme/B5UqeWt/8KM4aWBwA1D2Kw==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.4.tgz",
+ "integrity": "sha512-kMVGgsqhO5YTYODD9IPGGhA6iprWidQckK3LmPeW08PIFENRmgfb4MjXHO+p//d+ts2rpjvK5gXWzXSMrPl9cw==",
"cpu": [
"x64"
],
@@ -1394,6 +1395,7 @@
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz",
"integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@octokit/auth-token": "^6.0.0",
"@octokit/graphql": "^9.0.3",
@@ -1634,6 +1636,15 @@
"url": "https://github.com/sponsors/Boshen"
}
},
+ "node_modules/@panva/hkdf": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz",
+ "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
@@ -2327,7 +2338,6 @@
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
@@ -2348,7 +2358,6 @@
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"dequal": "^2.0.3"
}
@@ -2424,8 +2433,7 @@
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@types/aws-lambda": {
"version": "8.10.160",
@@ -2526,6 +2534,7 @@
"integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"undici-types": "~7.19.0"
}
@@ -2535,6 +2544,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -2545,6 +2555,7 @@
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
@@ -2600,6 +2611,7 @@
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.56.1",
"@typescript-eslint/types": "8.56.1",
@@ -3121,6 +3133,7 @@
"integrity": "sha512-x7FptB5oDruxNPDNY2+S8tCh0pcq7ymCe1gTHcsp733jYjrJl8V1gMUlVysuCD9Kz46Xz9t1akkv08dPcYDs1w==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@bcoe/v8-coverage": "^1.0.2",
"@vitest/utils": "4.1.4",
@@ -3265,6 +3278,7 @@
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3305,7 +3319,6 @@
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=8"
}
@@ -3604,9 +3617,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz",
- "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==",
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+ "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3649,6 +3662,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -3823,6 +3837,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -4048,8 +4071,7 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/dunder-proto": {
"version": "1.0.1",
@@ -4319,6 +4341,7 @@
"integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.2",
@@ -4404,9 +4427,9 @@
"license": "MIT"
},
"node_modules/eslint-config-next/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
+ "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4455,6 +4478,7 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -4590,9 +4614,9 @@
}
},
"node_modules/eslint-config-next/node_modules/minimatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz",
- "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -4943,9 +4967,9 @@
}
},
"node_modules/flatted": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
- "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true,
"license": "ISC"
},
@@ -6051,6 +6075,15 @@
"jiti": "lib/jiti-cli.mjs"
}
},
+ "node_modules/jose": {
+ "version": "4.15.9",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
+ "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -6490,7 +6523,6 @@
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@@ -7519,12 +7551,13 @@
"license": "MIT"
},
"node_modules/next": {
- "version": "16.2.3",
- "resolved": "https://registry.npmjs.org/next/-/next-16.2.3.tgz",
- "integrity": "sha512-9V3zV4oZFza3PVev5/poB9g0dEafVcgNyQ8eTRop8GvxZjV2G15FC5ARuG1eFD42QgeYkzJBJzHghNP8Ad9xtA==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/next/-/next-16.2.4.tgz",
+ "integrity": "sha512-kPvz56wF5frc+FxlHI5qnklCzbq53HTwORaWBGdT0vNoKh1Aya9XC8aPauH4NJxqtzbWsS5mAbctm4cr+EkQ2Q==",
"license": "MIT",
+ "peer": true,
"dependencies": {
- "@next/env": "16.2.3",
+ "@next/env": "16.2.4",
"@swc/helpers": "0.5.15",
"baseline-browser-mapping": "^2.9.19",
"caniuse-lite": "^1.0.30001579",
@@ -7538,14 +7571,14 @@
"node": ">=20.9.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "16.2.3",
- "@next/swc-darwin-x64": "16.2.3",
- "@next/swc-linux-arm64-gnu": "16.2.3",
- "@next/swc-linux-arm64-musl": "16.2.3",
- "@next/swc-linux-x64-gnu": "16.2.3",
- "@next/swc-linux-x64-musl": "16.2.3",
- "@next/swc-win32-arm64-msvc": "16.2.3",
- "@next/swc-win32-x64-msvc": "16.2.3",
+ "@next/swc-darwin-arm64": "16.2.4",
+ "@next/swc-darwin-x64": "16.2.4",
+ "@next/swc-linux-arm64-gnu": "16.2.4",
+ "@next/swc-linux-arm64-musl": "16.2.4",
+ "@next/swc-linux-x64-gnu": "16.2.4",
+ "@next/swc-linux-x64-musl": "16.2.4",
+ "@next/swc-win32-arm64-msvc": "16.2.4",
+ "@next/swc-win32-x64-msvc": "16.2.4",
"sharp": "^0.34.5"
},
"peerDependencies": {
@@ -7571,6 +7604,38 @@
}
}
},
+ "node_modules/next-auth": {
+ "version": "4.24.14",
+ "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.14.tgz",
+ "integrity": "sha512-YRz6xFDXKUwiXSMMChbrBEWyFktZ1qZXEgeSHQQ3nsy08B4c/xLk6REeutRsIFwkjY/1+ShHnu07DN3JeJguig==",
+ "license": "ISC",
+ "dependencies": {
+ "@babel/runtime": "^7.20.13",
+ "@panva/hkdf": "^1.0.2",
+ "cookie": "^0.7.0",
+ "jose": "^4.15.5",
+ "oauth": "^0.9.15",
+ "openid-client": "^5.4.0",
+ "preact": "^10.6.3",
+ "preact-render-to-string": "^5.1.19",
+ "uuid": "^8.3.2"
+ },
+ "peerDependencies": {
+ "@auth/core": "0.34.3",
+ "next": "^12.2.5 || ^13 || ^14 || ^15 || ^16",
+ "nodemailer": "^7.0.7",
+ "react": "^17.0.2 || ^18 || ^19",
+ "react-dom": "^17.0.2 || ^18 || ^19"
+ },
+ "peerDependenciesMeta": {
+ "@auth/core": {
+ "optional": true
+ },
+ "nodemailer": {
+ "optional": true
+ }
+ }
+ },
"node_modules/next-sitemap": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-4.2.3.tgz",
@@ -7660,6 +7725,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/oauth": {
+ "version": "0.9.15",
+ "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
+ "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==",
+ "license": "MIT"
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -7670,6 +7741,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/object-hash": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
+ "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
@@ -7816,6 +7896,48 @@
"node": ">= 20"
}
},
+ "node_modules/oidc-token-hash": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.2.0.tgz",
+ "integrity": "sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw==",
+ "license": "MIT",
+ "engines": {
+ "node": "^10.13.0 || >=12.0.0"
+ }
+ },
+ "node_modules/openid-client": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz",
+ "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==",
+ "license": "MIT",
+ "dependencies": {
+ "jose": "^4.15.9",
+ "lru-cache": "^6.0.0",
+ "object-hash": "^2.2.0",
+ "oidc-token-hash": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
+ "node_modules/openid-client/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/openid-client/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "license": "ISC"
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -7962,9 +8084,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -8027,6 +8149,35 @@
"node": ">=4"
}
},
+ "node_modules/preact": {
+ "version": "10.29.1",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz",
+ "integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==",
+ "license": "MIT",
+ "peer": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/preact-render-to-string": {
+ "version": "5.2.6",
+ "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz",
+ "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==",
+ "license": "MIT",
+ "dependencies": {
+ "pretty-format": "^3.8.0"
+ },
+ "peerDependencies": {
+ "preact": ">=10"
+ }
+ },
+ "node_modules/preact-render-to-string/node_modules/pretty-format": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
+ "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==",
+ "license": "MIT"
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -8043,7 +8194,6 @@
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -8059,7 +8209,6 @@
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=10"
},
@@ -8072,8 +8221,7 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/prop-types": {
"version": "15.8.1",
@@ -8133,6 +8281,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -8142,6 +8291,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -8996,7 +9146,8 @@
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
"integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/tailwindcss-animate": {
"version": "1.0.7",
@@ -9075,11 +9226,12 @@
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -9268,6 +9420,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -9508,6 +9661,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/vfile": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
@@ -9556,6 +9718,7 @@
"integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"lightningcss": "^1.32.0",
"picomatch": "^4.0.4",
@@ -9647,6 +9810,7 @@
"integrity": "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vitest/expect": "4.1.4",
"@vitest/mocker": "4.1.4",
@@ -9732,9 +9896,9 @@
}
},
"node_modules/vitest/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -9912,6 +10076,7 @@
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
diff --git a/package.json b/package.json
index 44aa724..fc09f48 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,8 @@
"@radix-ui/react-slot": "^1.2.4",
"@vercel/analytics": "^2.0.1",
"lucide-react": "^0.577.0",
- "next": "16.2.3",
+ "next": "^16.2.4",
+ "next-auth": "^4.24.14",
"octokit": "^5.0.5",
"react": "19.2.4",
"react-dom": "19.2.4",
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..8603b53
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,9 @@
+# *
+User-agent: *
+Allow: /
+
+# Host
+Host: https://readmegen-ai.vercel.app
+
+# Sitemaps
+Sitemap: https://readmegen-ai.vercel.app/sitemap.xml
diff --git a/public/sitemap-0.xml b/public/sitemap-0.xml
new file mode 100644
index 0000000..6ac8e51
--- /dev/null
+++ b/public/sitemap-0.xml
@@ -0,0 +1,8 @@
+
+
+https://readmegen-ai.vercel.app2026-04-04T09:31:17.224Zweekly1
+https://readmegen-ai.vercel.app/docs2026-04-04T09:31:17.224Zmonthly0.8
+https://readmegen-ai.vercel.app/examples2026-04-04T09:31:17.224Zmonthly0.8
+https://readmegen-ai.vercel.app/features2026-04-04T09:31:17.224Zmonthly0.8
+https://readmegen-ai.vercel.app/generate2026-04-04T09:31:17.224Zweekly0.9
+
\ No newline at end of file
diff --git a/public/sitemap.xml b/public/sitemap.xml
new file mode 100644
index 0000000..b3a9e11
--- /dev/null
+++ b/public/sitemap.xml
@@ -0,0 +1,4 @@
+
+
+https://readmegen-ai.vercel.app/sitemap-0.xml
+
\ No newline at end of file
diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts
new file mode 100644
index 0000000..7b38c1b
--- /dev/null
+++ b/src/app/api/auth/[...nextauth]/route.ts
@@ -0,0 +1,6 @@
+import NextAuth from "next-auth";
+import { authOptions } from "@/lib/auth";
+
+const handler = NextAuth(authOptions);
+
+export { handler as GET, handler as POST };
diff --git a/src/app/api/generate/route.ts b/src/app/api/generate/route.ts
index acb17e5..5c51aa9 100644
--- a/src/app/api/generate/route.ts
+++ b/src/app/api/generate/route.ts
@@ -1,40 +1,41 @@
-import { NextResponse } from "next/server";
+import { getToken } from "next-auth/jwt";
+import { NextRequest, NextResponse } from "next/server";
import { getGeminiModel } from "@/lib/gemini";
-import { getRepoData, getRepoContents } from "@/lib/octokit";
-import { SUPPORTED_LANGUAGES } from "@/constants/languages";
+import { getRepoSnapshot, RepoAccessError } from "@/lib/octokit";
export const dynamic = "force-dynamic";
/**
- * AI README Generation Endpoint
- * Optimized for data accuracy, clean prompt interpolation, and multi-language support.
+ * Enhanced Multi-Step README Generation Endpoint
*
- * @param {Request} req - The incoming Next.js/standard Web API Request object containing the repo URL and optional language.
+ * @param {NextRequest} req - The incoming Next.js request object containing the repo URL and optional language.
* @returns {Promise} A JSON response containing the generated Markdown or an error message.
*/
-export async function POST(req: Request) {
+export async function POST(req: NextRequest) {
let rawUrl: string;
let language: string;
+ let ackPrivateRepo = false;
try {
const body = await req.json();
rawUrl = body.url;
language = body.language || "English";
+ ackPrivateRepo = Boolean(body.ackPrivateRepo);
} catch {
return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });
}
- try {
- const trimmedUrl = rawUrl?.trim();
- if (!trimmedUrl) {
+ // Validate required fields
+ if (!githubUrl) {
return NextResponse.json(
{ error: "GitHub URL is required" },
{ status: 400 },
);
}
+ // Validate GitHub URL format
let parsedUrl: URL;
try {
- parsedUrl = new URL(trimmedUrl);
+ parsedUrl = new URL(githubUrl.trim());
} catch {
return NextResponse.json(
{ error: "Please provide a valid URL" },
@@ -63,13 +64,34 @@ export async function POST(req: Request) {
);
}
- const [repoInfo, repoContents] = await Promise.all([
- getRepoData(owner, repo),
- getRepoContents(owner, repo),
- ]);
+ const token = await getToken({
+ req,
+ secret: process.env.NEXTAUTH_SECRET,
+ });
+ const accessToken =
+ typeof token?.accessToken === "string" ? token.accessToken : undefined;
+
+ const { repoInfo, repoContents } = await getRepoSnapshot(
+ owner,
+ repo,
+ accessToken,
+ );
+
+ const isPrivateRepo = Boolean(repoInfo?.private);
+ if (isPrivateRepo && !ackPrivateRepo) {
+ return NextResponse.json(
+ {
+ error: "private_repo_consent_required",
+ message:
+ "This repository appears to be private. Confirm consent to send private repository data to the AI model by re-submitting with { ackPrivateRepo: true }.",
+ authRequired: Boolean(accessToken),
+ },
+ { status: 403 },
+ );
+ }
const files = Array.isArray(repoContents)
- ? repoContents.map((f: { name: string }) => f.name)
+ ? repoContents.map((f: { path: string }) => f.path)
: [];
const fileListString =
files.length > 0 ? files.join(", ") : "Standard repository structure";
@@ -158,12 +180,50 @@ export async function POST(req: Request) {
return NextResponse.json({ markdown: cleanMarkdown });
} catch (error: unknown) {
+ if (error instanceof RepoAccessError) {
+ return NextResponse.json(
+ {
+ error: error.message,
+ authRequired: error.code === "AUTH_REQUIRED",
+ },
+ { status: error.status },
+ );
+ }
+
const message =
error instanceof Error ? error.message : "Internal Server Error";
console.error("README Generation Failed:", message);
+ // Return successful result with enhanced metadata
+ return NextResponse.json({
+ success: true,
+ markdown: result.readme, // Keep 'markdown' key for compatibility with existing frontend
+ stats: {
+ sectionsGenerated: result.stats.sectionsGenerated,
+ sectionsTotal: result.stats.sectionsTotal,
+ tokensUsed: result.stats.tokensUsed,
+ timeElapsed: result.stats.timeElapsed,
+ generationMethod: "multi-step", // Indicate the method used
+ },
+ metadata: {
+ name: result.metadata?.name,
+ description: result.metadata?.description,
+ language: result.metadata?.language,
+ stars: result.metadata?.stars,
+ license: result.metadata?.license,
+ projectType: result.structure?.projectType,
+ techStack: result.structure?.techStack.primary,
+ frameworks: result.structure?.techStack.frameworks,
+ },
+ warnings: result.errors.length > 0 ? result.errors : undefined,
+ });
+ } catch (error) {
+ console.error("Multi-step README generation API error:", error);
return NextResponse.json(
- { error: "Failed to generate README. Check your URL and try again." },
+ {
+ error: "Internal server error in multi-step README generation",
+ message: error instanceof Error ? error.message : "Unknown error",
+ },
{ status: 500 },
);
}
diff --git a/src/app/api/generate/route.ts.backup b/src/app/api/generate/route.ts.backup
new file mode 100644
index 0000000..acb17e5
--- /dev/null
+++ b/src/app/api/generate/route.ts.backup
@@ -0,0 +1,170 @@
+import { NextResponse } from "next/server";
+import { getGeminiModel } from "@/lib/gemini";
+import { getRepoData, getRepoContents } from "@/lib/octokit";
+import { SUPPORTED_LANGUAGES } from "@/constants/languages";
+
+export const dynamic = "force-dynamic";
+
+/**
+ * AI README Generation Endpoint
+ * Optimized for data accuracy, clean prompt interpolation, and multi-language support.
+ *
+ * @param {Request} req - The incoming Next.js/standard Web API Request object containing the repo URL and optional language.
+ * @returns {Promise} A JSON response containing the generated Markdown or an error message.
+ */
+export async function POST(req: Request) {
+ let rawUrl: string;
+ let language: string;
+ try {
+ const body = await req.json();
+ rawUrl = body.url;
+ language = body.language || "English";
+ } catch {
+ return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });
+ }
+
+ try {
+ const trimmedUrl = rawUrl?.trim();
+ if (!trimmedUrl) {
+ return NextResponse.json(
+ { error: "GitHub URL is required" },
+ { status: 400 },
+ );
+ }
+
+ let parsedUrl: URL;
+ try {
+ parsedUrl = new URL(trimmedUrl);
+ } catch {
+ return NextResponse.json(
+ { error: "Please provide a valid URL" },
+ { status: 400 },
+ );
+ }
+
+ if (
+ parsedUrl.hostname !== "github.com" &&
+ parsedUrl.hostname !== "www.github.com"
+ ) {
+ return NextResponse.json(
+ { error: "Only GitHub URLs are supported" },
+ { status: 400 },
+ );
+ }
+
+ const pathSegments = parsedUrl.pathname.split("/").filter(Boolean);
+ const owner = pathSegments[0];
+ const repo = pathSegments[1];
+
+ if (!owner || !repo) {
+ return NextResponse.json(
+ { error: "URL must include owner and repository name" },
+ { status: 400 },
+ );
+ }
+
+ const [repoInfo, repoContents] = await Promise.all([
+ getRepoData(owner, repo),
+ getRepoContents(owner, repo),
+ ]);
+
+ const files = Array.isArray(repoContents)
+ ? repoContents.map((f: { name: string }) => f.name)
+ : [];
+ const fileListString =
+ files.length > 0 ? files.join(", ") : "Standard repository structure";
+
+ // Tech Stack detection logic
+ const hasNode = files.includes("package.json");
+ const hasPython =
+ files.includes("requirements.txt") || files.includes("setup.py");
+ const hasDocker =
+ files.includes("Dockerfile") || files.includes("docker-compose.yml");
+
+ // Fix: Cleanly joined Tech Stack labels
+ const stackLabels =
+ [
+ hasNode && "Node.js Environment",
+ hasPython && "Python Environment",
+ hasDocker && "Containerized",
+ ]
+ .filter(Boolean)
+ .join(", ") || "Generic Software Environment";
+
+ // Fix: Dynamic License detection
+ const licenseName =
+ repoInfo?.license?.name ||
+ repoInfo?.license?.spdx_id ||
+ "the repository's license file";
+
+ const model = getGeminiModel();
+
+ // Fix: Prompt updated with neutral fallbacks and dynamic license
+ const prompt = `
+**Role**: You are a Principal Solutions Architect and World-Class Technical Writer.
+**Task**: Generate a professional, high-conversion README.md for the GitHub repository: "${repo}" in the following language: **${language}**.
+
+---
+### 1. PROJECT CONTEXT (VERIFIED DATA)
+- **Project Name**: ${repo}
+- **Description**: ${repoInfo?.description || "No description provided."}
+- **Primary Language**: ${repoInfo?.language || "Language unknown"}
+- **Detected Root Files**: ${fileListString}
+- **Tech Stack Context**: ${stackLabels}
+
+---
+### 2. STRICT README STRUCTURE REQUIREMENTS
+
+1. **Visual Header**:
+ - Center-aligned H1 with project name.
+ - A compelling 1-sentence tagline describing the **Value Proposition**.
+ - A centered row of Shields.io badges (Build, License, PRs Welcome, Stars).
+
+2. **The Strategic "Why" (Overview)**:
+ - **The Problem**: Use a blockquote to describe the real-world pain point this project solves.
+ - **The Solution**: Explain how this project provides a superior outcome for the user.
+
+3. **Key Features**:
+ - Minimum 5 features. Use emojis and focus on **User Benefits**.
+
+4. **Technical Architecture**:
+ - Provide a table of the tech stack: | Technology | Purpose | Key Benefit |.
+ - Create a tree-style directory structure code block using ๐ for folders and ๐ for files based on the file manifest provided.
+
+5. **Operational Setup**:
+ - **Prerequisites**: List required runtimes.
+ - **Installation**: Provide step-by-step terminal commands.
+ ${hasNode ? "- Use npm/yarn/pnpm since package.json was detected." : ""}
+ ${hasPython ? "- Use pip/venv since Python markers were detected." : ""}
+ - **Environment**: If any .env or config files are in the manifest, include a configuration section.
+
+6. **Community & Governance**:
+ - Professional "Contributing" section (Fork -> Branch -> PR).
+ - Detailed "License" section: Reference ${licenseName} and provide a summary of permissions.
+
+---
+### 3. TONE & STYLE
+- **Tone**: Authoritative, polished, and developer-centric.
+- **Visuals**: Extensive use of Markdown formatting.
+- **Constraint**: Return ONLY the raw Markdown. No conversational filler.
+ `;
+
+ const result = await model.generateContent(prompt);
+ const response = await result.response;
+ const markdown = response.text().trim();
+ const cleanMarkdown = markdown
+ .replace(/^```(markdown|md)?\n/, "")
+ .replace(/\n```$/, "");
+
+ return NextResponse.json({ markdown: cleanMarkdown });
+ } catch (error: unknown) {
+ const message =
+ error instanceof Error ? error.message : "Internal Server Error";
+ console.error("README Generation Failed:", message);
+
+ return NextResponse.json(
+ { error: "Failed to generate README. Check your URL and try again." },
+ { status: 500 },
+ );
+ }
+}
diff --git a/src/app/generate/GeneratePageClient.tsx b/src/app/generate/GeneratePageClient.tsx
index b430b3e..a36f842 100644
--- a/src/app/generate/GeneratePageClient.tsx
+++ b/src/app/generate/GeneratePageClient.tsx
@@ -15,6 +15,10 @@ interface GeneratePageProps {
export default function GeneratePageClient({ repoSlug }: GeneratePageProps) {
const [markdown, setMarkdown] = useState("");
const [isLoading, setIsLoading] = useState(false);
+ const [errorMessage, setErrorMessage] = useState(null);
+ const [authRequired, setAuthRequired] = useState(false);
+ const [privateRepoConsentRequired, setPrivateRepoConsentRequired] =
+ useState(false);
// Optional: Update document title for SPA navigation
useEffect(() => {
@@ -29,28 +33,37 @@ export default function GeneratePageClient({ repoSlug }: GeneratePageProps) {
const handleGenerate = async (
githubUrl: string,
language: string = "English",
+ ackPrivateRepo: boolean = false,
) => {
setIsLoading(true);
setMarkdown("");
+ setErrorMessage(null);
+ setAuthRequired(false);
+ setPrivateRepoConsentRequired(false);
try {
const response = await fetch("/api/generate", {
method: "POST",
headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ url: githubUrl, language }),
+ body: JSON.stringify({ url: githubUrl, language, ackPrivateRepo }),
});
if (!response.ok) {
const errorText = await response.text();
let errorMessage: string;
+ let requiresAuth = false;
try {
const errorData = JSON.parse(errorText);
errorMessage = errorData.error || errorData.message || errorText;
+ requiresAuth = Boolean(errorData.authRequired);
+ setPrivateRepoConsentRequired(
+ errorData.error === "private_repo_consent_required",
+ );
} catch {
errorMessage = errorText || response.statusText;
}
- throw new Error(
- `[${response.status} ${response.statusText}]: ${errorMessage}`,
- );
+
+ setAuthRequired(requiresAuth);
+ throw new Error(errorMessage);
}
const data = await response.json();
@@ -64,7 +77,9 @@ export default function GeneratePageClient({ repoSlug }: GeneratePageProps) {
}
} catch (error: unknown) {
console.error("Generation Error:", error);
- alert(error instanceof Error ? error.message : "Something went wrong");
+ setErrorMessage(
+ error instanceof Error ? error.message : "Something went wrong",
+ );
} finally {
setIsLoading(false);
}
@@ -85,6 +100,9 @@ export default function GeneratePageClient({ repoSlug }: GeneratePageProps) {
isLoading={isLoading}
initialValue={repoSlug ? `https://github.com/${repoSlug}` : ""}
ariaLabel="Enter GitHub repository URL to generate README"
+ serverError={errorMessage}
+ authRequired={authRequired}
+ privateRepoConsentRequired={privateRepoConsentRequired}
/>
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 1db0de7..e69260f 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { Analytics } from "@vercel/analytics/next";
import pkg from "../../package.json";
+import { Providers } from "./providers";
import "./globals.css";
const geistSans = Geist({
@@ -117,7 +118,6 @@ export default function RootLayout({
return (
- {/* JSON-LD structured data */}