GitHub Actions
Deploy from GitHub Actions [dev] - 2025-10-31 07:28:50
68f7925
import fs from 'fs/promises';
import { NextRequest, NextResponse } from 'next/server';
import path from 'path';
const DATA_ROOT = '/data';
interface FileInfo {
name: string;
type: 'file' | 'directory';
size: number;
lastModified: string;
path: string;
}
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const relativePath = searchParams.get('path') || '';
// パストラバーサル対策
const normalizedPath = path.normalize(relativePath).replace(/^(\.\.(\/|\\|$))+/, '');
const targetPath = path.join(DATA_ROOT, normalizedPath);
// /data配下であることを確認
if (!targetPath.startsWith(DATA_ROOT)) {
return NextResponse.json({ error: 'Invalid path' }, { status: 400 });
}
try {
// ディレクトリの存在確認
await fs.access(targetPath);
const stat = await fs.stat(targetPath);
if (!stat.isDirectory()) {
return NextResponse.json({ error: 'Path is not a directory' }, { status: 400 });
}
// ディレクトリ内容を取得
const entries = await fs.readdir(targetPath, { withFileTypes: true });
const fileInfos: FileInfo[] = await Promise.all(
entries.map(async (entry) => {
const fullPath = path.join(targetPath, entry.name);
const fileStat = await fs.stat(fullPath);
const relativePath = path.relative(DATA_ROOT, fullPath);
return {
name: entry.name,
type: entry.isDirectory() ? 'directory' : 'file',
size: fileStat.size,
lastModified: fileStat.mtime.toISOString(),
path: `/${relativePath}`,
} as FileInfo;
}),
);
// ディレクトリを先に、その後ファイルを名前順にソート
fileInfos.sort((a, b) => {
if (a.type !== b.type) {
return a.type === 'directory' ? -1 : 1;
}
return a.name.localeCompare(b.name);
});
return NextResponse.json({
path: `/${normalizedPath}`,
items: fileInfos,
});
} catch (error) {
// /dataディレクトリが存在しない場合
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
return NextResponse.json(
{
path: `/${normalizedPath}`,
items: [],
message: '/dataディレクトリが存在しません(ローカル環境の場合は正常です)',
},
{ status: 200 },
);
}
throw error;
}
} catch (error) {
console.error('[API /admin/data/list] Error:', error);
return NextResponse.json({ error: 'Failed to read directory' }, { status: 500 });
}
}