diff --git a/src/app/api/files/browse/route.ts b/src/app/api/files/browse/route.ts index d51674b..7744041 100644 --- a/src/app/api/files/browse/route.ts +++ b/src/app/api/files/browse/route.ts @@ -1,16 +1,16 @@ import { NextRequest, NextResponse } from 'next/server'; -import fs from 'fs'; +import fs from 'fs/promises'; import path from 'path'; import os from 'os'; import type { ErrorResponse } from '@/types'; -function getWindowsDrives(): string[] { +async function getWindowsDrives(): Promise { if (process.platform !== 'win32') return []; const drives: string[] = []; for (let i = 65; i <= 90; i++) { const drive = String.fromCharCode(i) + ':\\'; try { - fs.accessSync(drive); + await fs.access(drive); drives.push(drive); } catch { // drive not available @@ -26,7 +26,9 @@ export async function GET(request: NextRequest) { const resolvedDir = path.resolve(dir); - if (!fs.existsSync(resolvedDir)) { + try { + await fs.access(resolvedDir); + } catch { return NextResponse.json( { error: 'Directory does not exist' }, { status: 404 } @@ -34,7 +36,7 @@ export async function GET(request: NextRequest) { } try { - const entries = fs.readdirSync(resolvedDir, { withFileTypes: true }); + const entries = await fs.readdir(resolvedDir, { withFileTypes: true }); const directories = entries .filter((e) => e.isDirectory() && !e.name.startsWith('.')) .map((e) => ({ @@ -43,7 +45,7 @@ export async function GET(request: NextRequest) { })) .sort((a, b) => a.name.localeCompare(b.name)); - const drives = getWindowsDrives(); + const drives = await getWindowsDrives(); return NextResponse.json({ current: resolvedDir, diff --git a/src/app/api/files/preview/route.ts b/src/app/api/files/preview/route.ts index d764828..83cdf37 100644 --- a/src/app/api/files/preview/route.ts +++ b/src/app/api/files/preview/route.ts @@ -1,4 +1,6 @@ import { NextRequest, NextResponse } from 'next/server'; +import path from 'path'; +import os from 'os'; import { readFilePreview, isPathSafe } from '@/lib/files'; import type { FilePreviewResponse, ErrorResponse } from '@/types'; @@ -14,8 +16,6 @@ export async function GET(request: NextRequest) { ); } - const path = require('path'); - const os = require('os'); const resolvedPath = path.resolve(filePath); const homeDir = os.homedir(); @@ -52,7 +52,7 @@ export async function GET(request: NextRequest) { } try { - const preview = readFilePreview(resolvedPath, Math.min(maxLines, 1000)); + const preview = await readFilePreview(resolvedPath, Math.min(maxLines, 1000)); return NextResponse.json({ preview }); } catch (error) { return NextResponse.json( diff --git a/src/app/api/files/raw/route.ts b/src/app/api/files/raw/route.ts index 7d4bfa9..120b33b 100644 --- a/src/app/api/files/raw/route.ts +++ b/src/app/api/files/raw/route.ts @@ -1,5 +1,5 @@ import { NextRequest } from 'next/server'; -import fs from 'fs'; +import fs from 'fs/promises'; import path from 'path'; import os from 'os'; import { isPathSafe } from '@/lib/files'; @@ -104,14 +104,16 @@ export async function GET(request: NextRequest) { }); } - if (!fs.existsSync(resolved)) { + try { + await fs.access(resolved); + } catch { return new Response(JSON.stringify({ error: 'File not found' }), { status: 404, headers: { 'Content-Type': 'application/json' }, }); } - const stat = fs.statSync(resolved); + const stat = await fs.stat(resolved); if (!stat.isFile()) { return new Response(JSON.stringify({ error: 'Not a file' }), { status: 400, @@ -119,7 +121,7 @@ export async function GET(request: NextRequest) { }); } - const buffer = fs.readFileSync(resolved); + const buffer = await fs.readFile(resolved); const ext = path.extname(resolved).toLowerCase(); const contentType = MIME_TYPES[ext] || 'application/octet-stream'; diff --git a/src/app/api/files/route.ts b/src/app/api/files/route.ts index be731a1..ff000ab 100644 --- a/src/app/api/files/route.ts +++ b/src/app/api/files/route.ts @@ -1,4 +1,6 @@ import { NextRequest, NextResponse } from 'next/server'; +import path from 'path'; +import os from 'os'; import { scanDirectory, isPathSafe } from '@/lib/files'; import type { FileTreeResponse, ErrorResponse } from '@/types'; @@ -14,8 +16,6 @@ export async function GET(request: NextRequest) { ); } - const path = require('path'); - const os = require('os'); const resolvedDir = path.resolve(dir); const homeDir = os.homedir(); @@ -52,7 +52,7 @@ export async function GET(request: NextRequest) { } try { - const tree = scanDirectory(resolvedDir, Math.min(depth, 5)); + const tree = await scanDirectory(resolvedDir, Math.min(depth, 5)); return NextResponse.json({ tree, root: resolvedDir }); } catch (error) { return NextResponse.json( diff --git a/src/app/api/uploads/route.ts b/src/app/api/uploads/route.ts index 78119c3..f93b159 100644 --- a/src/app/api/uploads/route.ts +++ b/src/app/api/uploads/route.ts @@ -1,5 +1,5 @@ import { NextRequest } from 'next/server'; -import fs from 'fs'; +import fs from 'fs/promises'; import path from 'path'; export const runtime = 'nodejs'; @@ -42,14 +42,16 @@ export async function GET(request: NextRequest) { }); } - if (!fs.existsSync(resolved)) { + try { + await fs.access(resolved); + } catch { return new Response(JSON.stringify({ error: 'File not found' }), { status: 404, headers: { 'Content-Type': 'application/json' }, }); } - const buffer = fs.readFileSync(resolved); + const buffer = await fs.readFile(resolved); const ext = path.extname(resolved).toLowerCase(); const contentType = MIME_TYPES[ext] || 'application/octet-stream'; diff --git a/src/lib/files.ts b/src/lib/files.ts index d898a83..f83ea3d 100644 --- a/src/lib/files.ts +++ b/src/lib/files.ts @@ -1,4 +1,4 @@ -import fs from 'fs'; +import fs from 'fs/promises'; import path from 'path'; import type { FileTreeNode, FilePreview } from '@/types'; @@ -74,22 +74,24 @@ export function isPathSafe(basePath: string, targetPath: string): boolean { return resolvedTarget.startsWith(resolvedBase + path.sep) || resolvedTarget === resolvedBase; } -export function scanDirectory(dir: string, depth: number = 3): FileTreeNode[] { +export async function scanDirectory(dir: string, depth: number = 3): Promise { const resolvedDir = path.resolve(dir); - if (!fs.existsSync(resolvedDir)) { + try { + await fs.access(resolvedDir); + } catch { return []; } return scanDirectoryRecursive(resolvedDir, depth); } -function scanDirectoryRecursive(dir: string, depth: number): FileTreeNode[] { +async function scanDirectoryRecursive(dir: string, depth: number): Promise { if (depth <= 0) return []; - let entries: fs.Dirent[]; + let entries: import('fs').Dirent[]; try { - entries = fs.readdirSync(dir, { withFileTypes: true }); + entries = await fs.readdir(dir, { withFileTypes: true }); } catch { return []; } @@ -114,7 +116,7 @@ function scanDirectoryRecursive(dir: string, depth: number): FileTreeNode[] { if (entry.isDirectory()) { if (IGNORED_DIRS.has(entry.name)) continue; - const children = scanDirectoryRecursive(fullPath, depth - 1); + const children = await scanDirectoryRecursive(fullPath, depth - 1); nodes.push({ name: entry.name, path: fullPath, @@ -125,7 +127,7 @@ function scanDirectoryRecursive(dir: string, depth: number): FileTreeNode[] { const ext = path.extname(entry.name).replace(/^\./, ''); let size: number | undefined; try { - const stat = fs.statSync(fullPath); + const stat = await fs.stat(fullPath); size = stat.size; } catch { // Skip files we can't stat @@ -144,20 +146,22 @@ function scanDirectoryRecursive(dir: string, depth: number): FileTreeNode[] { return nodes; } -export function readFilePreview(filePath: string, maxLines: number = 200): FilePreview { +export async function readFilePreview(filePath: string, maxLines: number = 200): Promise { const resolvedPath = path.resolve(filePath); - if (!fs.existsSync(resolvedPath)) { + try { + await fs.access(resolvedPath); + } catch { throw new Error(`File not found: ${filePath}`); } - const stat = fs.statSync(resolvedPath); + const stat = await fs.stat(resolvedPath); if (!stat.isFile()) { throw new Error(`Not a file: ${filePath}`); } // Read the file content, limiting to maxLines - const content = fs.readFileSync(resolvedPath, 'utf-8'); + const content = await fs.readFile(resolvedPath, 'utf-8'); const lines = content.split('\n'); const truncated = lines.slice(0, maxLines).join('\n');