diff --git a/next.config.js b/next.config.js index 3e09550..11b2902 100644 --- a/next.config.js +++ b/next.config.js @@ -1,8 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - experimental: { - appDir: true, - }, + // App directory is now stable in Next.js 14, no longer experimental } module.exports = nextConfig; diff --git a/package.json b/package.json index 69614d2..878ef15 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "next dev -p 3002", "build": "next build", - "start": "next start", + "start": "next start -p 3002", "lint": "next lint", "type-check": "tsc --noEmit", "test:db": "node scripts/test-db.js", diff --git a/scripts/migrate-packages-version-length.sql b/scripts/migrate-packages-version-length.sql new file mode 100644 index 0000000..3027fe8 --- /dev/null +++ b/scripts/migrate-packages-version-length.sql @@ -0,0 +1,10 @@ +-- Migration: increase packages.version length to 255 +-- Run this against your existing database (PostgreSQL) + +ALTER TABLE packages + ALTER COLUMN version TYPE VARCHAR(255); + +-- Optional: verify +SELECT column_name, data_type, character_maximum_length +FROM information_schema.columns +WHERE table_name = 'packages' AND column_name = 'version'; diff --git a/src/app/api/debug-packages/route.ts b/src/app/api/debug-packages/route.ts deleted file mode 100644 index 28242f2..0000000 --- a/src/app/api/debug-packages/route.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { NextRequest, NextResponse } from 'next/server' -import { PackageService } from '@/services/packageService' - -export async function GET(request: NextRequest) { - try { - const { searchParams } = new URL(request.url) - const platform_id = searchParams.get('platform_id') || 'debian' - - console.log('๐Ÿ› Debug: Fetching packages for platform:', platform_id) - - // Test 1: Simple query without filters - const result1 = await PackageService.getMany({ - platform_id, - limit: 10 - }) - - console.log('๐Ÿ› Debug: Simple query result:', { - total: result1.total, - packageCount: result1.packages.length, - firstPackage: result1.packages[0]?.name || 'None' - }) - - // Test 2: Query with search - const result2 = await PackageService.getMany({ - platform_id, - search: 'firefox', - limit: 10 - }) - - console.log('๐Ÿ› Debug: Search query result:', { - total: result2.total, - packageCount: result2.packages.length, - firstPackage: result2.packages[0]?.name || 'None' - }) - - // Test 3: Raw SQL query - const rawQuery = ` - SELECT COUNT(*) as total, - MIN(p.name) as first_package - FROM packages p - WHERE p.platform_id = $1 AND p.is_active = true - ` - - const rawResult = await query(rawQuery, [platform_id]) - console.log('๐Ÿ› Debug: Raw SQL result:', rawResult.rows[0]) - - return NextResponse.json({ - simpleQuery: { - total: result1.total, - packages: result1.packages.slice(0, 3).map(p => ({ - id: p.id, - name: p.name, - version: p.version - })) - }, - searchQuery: { - total: result2.total, - packages: result2.packages.slice(0, 3).map(p => ({ - id: p.id, - name: p.name, - version: p.version - })) - }, - rawSql: rawResult.rows[0] - }) - - } catch (error) { - console.error('๐Ÿ› Debug: Error:', error) - return NextResponse.json({ - error: error instanceof Error ? error.message : 'Unknown error', - stack: error instanceof Error ? error.stack : undefined - }, { status: 500 }) - } -} diff --git a/src/app/api/sync-progress/route.ts b/src/app/api/sync-progress/route.ts index a44f20e..a8d7c94 100644 --- a/src/app/api/sync-progress/route.ts +++ b/src/app/api/sync-progress/route.ts @@ -1,9 +1,17 @@ -import { NextRequest } from 'next/server' +import { NextRequest, NextResponse } from 'next/server' import { SimplePackageFetcher } from '@/services/simplePackageFetcher' import { PlatformInitializer } from '@/services/platformInitializer' -import { setSyncInProgress, setSyncProgress } from '@/app/api/sync-status/route' +import { setSyncInProgress, setSyncProgress } from '@/lib/sync/status' + +export const dynamic = 'force-dynamic' +export const revalidate = 0 export async function GET(request: NextRequest) { + // Skip any heavy sync work during static generation/build unless explicitly enabled + if (process.env.ENABLE_SYNC_DURING_BUILD !== 'true') { + // Return a lightweight JSON response so build doesn't hang + return NextResponse.json({ disabled: true, reason: 'Sync disabled during build' }) + } const encoder = new TextEncoder() let cancelled = false diff --git a/src/app/api/sync-status/route.ts b/src/app/api/sync-status/route.ts index 905a087..df20bb8 100644 --- a/src/app/api/sync-status/route.ts +++ b/src/app/api/sync-status/route.ts @@ -1,14 +1,8 @@ import { NextRequest, NextResponse } from 'next/server' - -// Global sync state (in production, use Redis or database) -let syncInProgress = false -let syncProgress = { message: '', progress: 0, total: 100 } +import { getSyncStatus, setSyncInProgress, setSyncProgress } from '@/lib/sync/status' export async function GET() { - return NextResponse.json({ - inProgress: syncInProgress, - progress: syncProgress - }) + return NextResponse.json(getSyncStatus()) } export async function POST(request: NextRequest) { @@ -16,25 +10,16 @@ export async function POST(request: NextRequest) { const { action } = body if (action === 'cancel') { - syncInProgress = false - syncProgress = { message: 'Sync cancelled', progress: 0, total: 100 } + setSyncInProgress(false) + setSyncProgress('Sync cancelled', 0, 100) return NextResponse.json({ message: 'Sync cancelled successfully' }) } if (action === 'start') { - syncInProgress = true - syncProgress = { message: 'Starting sync...', progress: 0, total: 100 } + setSyncInProgress(true) + setSyncProgress('Starting sync...', 0, 100) return NextResponse.json({ message: 'Sync started' }) } return NextResponse.json({ error: 'Invalid action' }, { status: 400 }) } - -// Export functions for other endpoints to use -export function setSyncProgress(message: string, progress?: number, total?: number) { - syncProgress = { message, progress: progress || 0, total: total || 100 } -} - -export function setSyncInProgress(inProgress: boolean) { - syncInProgress = inProgress -} diff --git a/src/app/api/test-sync/route.ts b/src/app/api/test-sync/route.ts deleted file mode 100644 index 6888554..0000000 --- a/src/app/api/test-sync/route.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { NextRequest, NextResponse } from 'next/server' -import { PackageFetcherV2 } from '@/services/packageFetcherV2' -import { PlatformInitializer } from '@/services/platformInitializer' - -export async function GET() { - try { - console.log('๐Ÿงช Starting test sync...') - - // Test 1: Initialize platforms - await PlatformInitializer.initializePlatforms() - console.log('โœ… Platforms initialized') - - // Test 2: Try to fetch a small sample - console.log('๐Ÿ”„ Testing Debian package fetch...') - - // Just test the fetch and parse, don't store in DB - const response = await fetch('https://packages.debian.org/stable/allpackages?format=txt.gz', { - headers: { - 'Accept-Encoding': 'gzip, deflate', - 'User-Agent': 'RepoHub-Package-Fetcher/1.0' - } - }) - - if (!response.ok) { - throw new Error(`Failed to fetch: ${response.statusText}`) - } - - console.log('โœ… Response received, size:', response.headers.get('content-length')) - - const buffer = await response.arrayBuffer() - console.log('โœ… Buffer received, size:', buffer.byteLength) - - // Check magic bytes - const bytes = new Uint8Array(buffer.slice(0, 2)) - console.log('๐Ÿ” Magic bytes:', bytes[0].toString(16), bytes[1].toString(16)) - - // Try decompression - const { gunzip } = await import('zlib') - const decompressed = await new Promise((resolve, reject) => { - gunzip(new Uint8Array(buffer), (err, result) => { - if (err) { - console.error('โŒ Gunzip error:', err) - reject(err) - } else { - console.log('โœ… Gunzip successful, size:', result.length) - resolve(result) - } - }) - }) - - const text = decompressed.toString('utf-8') - console.log('โœ… Text decoded, length:', text.length) - - // Parse first 10 lines - const lines = text.split('\n').slice(0, 20) - console.log('๐Ÿ“‹ First 20 lines:') - lines.forEach((line, i) => console.log(`${i + 1}: ${line}`)) - - // Test parsing - const samplePackages = PackageFetcherV2['parseDebianPackageList'](text) - console.log('๐Ÿ“Š Sample packages parsed:', samplePackages.length) - - if (samplePackages.length > 0) { - console.log('๐Ÿ“ฆ First package:', samplePackages[0]) - } - - return NextResponse.json({ - success: true, - message: 'Test completed successfully', - bufferSize: buffer.byteLength, - textSize: text.length, - samplePackages: samplePackages.length, - firstPackage: samplePackages[0] || null - }) - - } catch (error) { - console.error('โŒ Test failed:', error) - return NextResponse.json({ - success: false, - error: error instanceof Error ? error.message : 'Unknown error', - stack: error instanceof Error ? error.stack : undefined - }, { status: 500 }) - } -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8ccec1b..3b7b594 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,7 @@ import './globals.css' import type { Metadata } from 'next' import { Inter } from 'next/font/google' +import { LocaleProvider } from '@/contexts/LocaleContext' const inter = Inter({ subsets: ['latin'] }) @@ -16,7 +17,11 @@ export default function RootLayout({ }) { return ( - {children} + + + {children} + + ) } diff --git a/src/lib/database/schema.sql b/src/lib/database/schema.sql index f9a11f0..2609ad0 100644 --- a/src/lib/database/schema.sql +++ b/src/lib/database/schema.sql @@ -32,7 +32,7 @@ CREATE TABLE packages ( id VARCHAR(100) PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT, - version VARCHAR(50), + version VARCHAR(255), platform_id VARCHAR(50) NOT NULL REFERENCES platforms(id), category_id INTEGER REFERENCES categories(id), license_id INTEGER REFERENCES licenses(id), diff --git a/src/lib/sync/status.ts b/src/lib/sync/status.ts new file mode 100644 index 0000000..21eb3c2 --- /dev/null +++ b/src/lib/sync/status.ts @@ -0,0 +1,19 @@ +// Global sync state (in production, use Redis or database) +let syncInProgress = false +let syncProgress = { message: '', progress: 0, total: 100 } + +// Export functions for other endpoints to use +export function setSyncProgress(message: string, progress?: number, total?: number) { + syncProgress = { message, progress: progress || 0, total: total || 100 } +} + +export function setSyncInProgress(inProgress: boolean) { + syncInProgress = inProgress +} + +export function getSyncStatus() { + return { + inProgress: syncInProgress, + progress: syncProgress + } +}