ai-chatbot/scripts/system-settings/restore-snapshot.ts
2026-05-29 17:22:32 +08:00

131 lines
3.5 KiB
TypeScript

import { config as loadEnv } from "dotenv";
import { eq } from "drizzle-orm";
loadEnv({ path: ".env.local" });
function readArg(name: string) {
const prefix = `${name}=`;
const match = process.argv.find((arg) => arg.startsWith(prefix));
return match ? match.slice(prefix.length) : null;
}
async function main() {
const snapshotId = readArg("--snapshot-id");
const reason = readArg("--reason") || "manual-snapshot-restore";
if (!snapshotId) {
throw new Error(
"Usage: pnpm tsx scripts/system-settings/restore-snapshot.ts --snapshot-id=<id> [--reason=<reason>]"
);
}
const dbModule = await import("../../lib/db");
const schemaModule = await import("../../lib/db/schema");
const snapshotModule = await import("../../lib/system-settings/snapshot");
const { db } = dbModule;
const { siteSettings, systemSettingHistory, systemSettingSnapshot, systemSettings } =
schemaModule;
const { readSystemSettingSnapshotData } = snapshotModule;
const [snapshot] = await db
.select({
id: systemSettingSnapshot.id,
scope: systemSettingSnapshot.scope,
data: systemSettingSnapshot.data,
})
.from(systemSettingSnapshot)
.where(eq(systemSettingSnapshot.id, snapshotId))
.limit(1);
if (!snapshot) {
throw new Error(`Snapshot not found: ${snapshotId}`);
}
const parsedSnapshot = readSystemSettingSnapshotData(
snapshot.scope as keyof typeof snapshotModule.SYSTEM_SETTING_SNAPSHOT_SCOPES,
snapshot.data
);
const keys = Object.keys(parsedSnapshot.systemSettings);
await db.transaction(async (tx) => {
for (const key of keys) {
const [existing] = await tx
.select({ value: systemSettings.value })
.from(systemSettings)
.where(eq(systemSettings.key, key))
.limit(1);
const nextValue = parsedSnapshot.systemSettings[key] ?? null;
await tx.insert(systemSettingHistory).values({
key,
previousValue: existing?.value ?? null,
nextValue,
reason,
changedAt: new Date(),
changedBy: null,
});
await tx
.insert(systemSettings)
.values({
key,
value: nextValue,
updatedAt: new Date(),
updatedBy: null,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: nextValue,
updatedAt: new Date(),
updatedBy: null,
},
});
}
if ("agentWorkflowDefaultModelId" in parsedSnapshot.siteSettings) {
const [existingSiteSettings] = await tx.select().from(siteSettings).limit(1);
const nextAgentWorkflowDefaultModelId =
String(parsedSnapshot.siteSettings.agentWorkflowDefaultModelId || "").trim() || null;
if (existingSiteSettings) {
await tx
.update(siteSettings)
.set({
agentWorkflowDefaultModelId: nextAgentWorkflowDefaultModelId,
updatedAt: new Date(),
updatedBy: null,
})
.where(eq(siteSettings.id, existingSiteSettings.id));
} else {
await tx.insert(siteSettings).values({
siteName: "AI Chatbot",
agentWorkflowDefaultModelId: nextAgentWorkflowDefaultModelId,
updatedAt: new Date(),
updatedBy: null,
});
}
}
});
console.log(
JSON.stringify(
{
snapshotId,
scope: snapshot.scope,
restoredKeyCount: keys.length,
reason,
},
null,
2
)
);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});