Files
OpenClaw-bot-review/app/api/config-backup/route.ts
T
Dan LeeandClaude Sonnet 4.6 c826424add feat: openclaw.json 自動備份、偵測損毀與還原 UI
## 備份機制
- 新增 lib/config-backup.ts:以 SHA-256 hash 偵測 openclaw.json 變更,自動備份
- Hash 持久化至 ~/.openclaw/backups/config/.last-hash,Next.js 重啟後仍能正確偵測變更
- 備份保留策略:滾動 8 個 + 昨天錨點 + 上週錨點(各取最後一個正常備份,≥ 1 KB)
- 新增 API:GET /api/config-backup(列出備份)、POST /api/config-backup(還原)

## Dashboard 偵測與還原 UI(gateway-status.tsx)
- Gateway 第一次失敗即觸發備份清單抓取,不等 30 秒
- 備份清單顯示大小、[建議] / [可能損毀] 標籤,並自動推薦第一個正常備份
- 還原後自動重啟 Gateway,並倒數 5 秒後自動重新整理頁面
- 提示使用者點選機器人卡片「測試」確認是否正常
- 「查看錯誤日誌」按鈕固定顯示於面板,可展開/收起最後 30 行 log
- config 損毀導致頁面載入失敗時,錯誤頁仍顯示 GatewayStatus 還原入口

## 多語系支援
- 所有新增文字支援繁中/简中/English(i18n.tsx 新增 8 個 key)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 10:15:35 +08:00

62 lines
1.3 KiB
TypeScript

import { NextResponse, NextRequest } from "next/server";
import {
listBackupFiles,
restoreFromBackup,
getBackupDir,
} from "@/lib/config-backup";
/**
* GET /api/config-backup
* 列出所有可用的 openclaw.json 備份
*/
export async function GET() {
try {
const backups = listBackupFiles();
return NextResponse.json({
backupDir: getBackupDir(),
backups,
});
} catch (err: any) {
return NextResponse.json(
{ error: err.message },
{ status: 500 }
);
}
}
/**
* POST /api/config-backup
* 從指定備份還原 openclaw.json
*
* Request body: { filename: "openclaw.2026-03-15T08-30-00.json" }
*/
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { filename } = body;
if (!filename || typeof filename !== "string") {
return NextResponse.json(
{ error: "Missing or invalid 'filename' in request body" },
{ status: 400 }
);
}
const result = restoreFromBackup(filename);
if (!result.success) {
return NextResponse.json(
{ error: result.message },
{ status: 400 }
);
}
return NextResponse.json(result);
} catch (err: any) {
return NextResponse.json(
{ error: err.message },
{ status: 500 }
);
}
}