← back to ClawCoder
src/app/api/files/[id]/route.ts
82 lines
import { NextRequest, NextResponse } from 'next/server'
import fs from 'fs'
import { authenticateRequest } from '@/lib/auth'
import { CLAUDE_MD_PATHS, ALLOWED_PATHS } from '../route'
function decodePath(id: string): string | null {
try {
const decoded = Buffer.from(decodeURIComponent(id), 'base64').toString('utf-8')
// Security: only allow paths in the allowlist
if (!ALLOWED_PATHS.has(decoded)) return null
return decoded
} catch {
return null
}
}
function getProject(filePath: string): string {
const entry = CLAUDE_MD_PATHS.find(e => e.path === filePath)
return entry?.project ?? 'Unknown'
}
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const auth = authenticateRequest(request)
if (auth instanceof NextResponse) return auth
const { id } = await params
const filePath = decodePath(id)
if (!filePath) {
return NextResponse.json({ error: 'Invalid or disallowed file path' }, { status: 403 })
}
try {
const content = fs.readFileSync(filePath, 'utf-8')
const stat = fs.statSync(filePath)
return NextResponse.json({
path: filePath,
project: getProject(filePath),
content,
lines: content.split('\n').length,
lastModified: stat.mtime.toISOString(),
})
} catch {
return NextResponse.json({ error: 'File not found or unreadable' }, { status: 404 })
}
}
export async function PUT(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const auth = authenticateRequest(request)
if (auth instanceof NextResponse) return auth
const { id } = await params
const filePath = decodePath(id)
if (!filePath) {
return NextResponse.json({ error: 'Invalid or disallowed file path' }, { status: 403 })
}
try {
const { content } = await request.json()
if (typeof content !== 'string') {
return NextResponse.json({ error: 'Content must be a string' }, { status: 400 })
}
fs.writeFileSync(filePath, content, 'utf-8')
const lines = content.split('\n').length
return NextResponse.json({
ok: true,
path: filePath,
lines,
})
} catch (err) {
const message = err instanceof Error ? err.message : 'Write failed'
return NextResponse.json({ error: message }, { status: 500 })
}
}