fix(backup): 手动备份按服冷却、每服保留上限与独立保留期,容量驱逐不再删除回收世界的唯一副本
This commit is contained in:
30 files changed
+801
-42
No files matched your search
@@ -5,7 +5,7 @@
|
||||
"not_yours_title": "No permission to access backups",
|
||||
"not_yours_body": "Only the owner or an admin can view and restore this server's backups.",
|
||||
"latest_title": "Latest backup",
|
||||
"history_note": "Historical backups can be used for restore before they expire. They are automatically cleaned up when they expire.",
|
||||
"history_note": "Backups can be restored until they expire, then they are cleaned up automatically. Each server keeps only its most recent manual backups; older manual backups are removed once a new one finishes.",
|
||||
"reason_inactive": "Idle archive",
|
||||
"reason_manual": "Manual backup",
|
||||
"reason_label": "Reason: {{reason}}",
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
"not_stopped": "Stop the server completely before restoring — a restore overwrites the live world volume.",
|
||||
"maintenance_in_progress": "This server's world is busy with a restore, backup or file write — try again once it finishes, usually within a minute or two.",
|
||||
"no_world_volume": "This server has no world volume yet — start it once so it is created, then retry.",
|
||||
"backup_cooldown": "This server was backed up moments ago, and manual backups have a cooldown — try again in a few minutes.",
|
||||
"backup_store_full": "The backup store is full, so manual backups are paused — ask an administrator to free space.",
|
||||
"restore_unavailable": "Restore isn't available right now — try again later.",
|
||||
"session_expired": "Your session expired — please sign in again.",
|
||||
"forbidden": "You are not allowed to do that.",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"not_yours_title": "无权访问备份",
|
||||
"not_yours_body": "只有所有者或管理员才能查看并恢复该服务器的备份。",
|
||||
"latest_title": "最新备份",
|
||||
"history_note": "历史备份在过期前均可用于恢复。到期后系统会自动清理,无需手动删除或管理。",
|
||||
"history_note": "历史备份在过期前均可用于恢复,到期后自动清理。手动备份每台服务器只保留最近几份,新备份完成后会自动删除更早的手动备份。",
|
||||
"reason_inactive": "闲置自动回收",
|
||||
"reason_manual": "手动备份",
|
||||
"reason_label": "原因:{{reason}}",
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
"not_stopped": "回档会覆盖世界的实时存储卷,请先把服务器完全停止再回档。",
|
||||
"maintenance_in_progress": "这台服务器的世界正在回档、备份或写入文件——等它完成后再试,通常不超过一两分钟。",
|
||||
"no_world_volume": "这台服务器还没有世界卷——先启动一次让它创建,然后再试。",
|
||||
"backup_cooldown": "这台服务器刚备份过,手动备份之间有冷却时间——请过几分钟再试。",
|
||||
"backup_store_full": "备份存储已满,暂时无法手动备份——请联系管理员清理空间。",
|
||||
"restore_unavailable": "回档功能当前不可用,请稍后再试。",
|
||||
"session_expired": "会话已过期——请重新登录。",
|
||||
"forbidden": "你无权执行此操作。",
|
||||
|
||||
@@ -390,6 +390,12 @@ describe("api access-control wire shapes", () => {
|
||||
expect(humanizeError({ code: "not_running" })).toMatch(/running|wake/i);
|
||||
expect(humanizeError({ code: "console_unavailable" })).toMatch(/console/i);
|
||||
});
|
||||
|
||||
it("maps the backup rationing codes to their own copy", async () => {
|
||||
const { humanizeError } = await import("./api");
|
||||
expect(humanizeError({ code: "backup_cooldown" })).toMatch(/cooldown/i);
|
||||
expect(humanizeError({ code: "backup_store_full" })).toMatch(/store is full/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("image whitelist and builds wire shapes", () => {
|
||||
|
||||
@@ -739,6 +739,12 @@ export function humanizeError(e: unknown): string {
|
||||
return t("maintenance_in_progress");
|
||||
case "no_world_volume":
|
||||
return t("no_world_volume");
|
||||
// On-demand backup rationing (data-durability-9): one per server per
|
||||
// cooldown, none while the shared backup store is at its cap.
|
||||
case "backup_cooldown":
|
||||
return t("backup_cooldown");
|
||||
case "backup_store_full":
|
||||
return t("backup_store_full");
|
||||
case "restore_unavailable":
|
||||
return t("restore_unavailable");
|
||||
// Server create/edit (spec §22): the portability regex + reservation list are
|
||||
|
||||
Reference in new issue
Block a user