chore: checkpoint admin restore state

This commit is contained in:
john
2026-06-30 20:26:33 +08:00
parent f2172322fd
commit f9a7584ad4
63 changed files with 7555 additions and 1030 deletions
+164
View File
@@ -0,0 +1,164 @@
const DEFAULT_TIMEOUT_MS = 10000;
function trimEnv(name) {
const value = process.env[name];
return typeof value === 'string' ? value.trim() : '';
}
function parseTimeout(value) {
const n = Number(value);
return Number.isFinite(n) && n > 0 ? n : DEFAULT_TIMEOUT_MS;
}
async function safeJson(response) {
const text = await response.text();
if (!text) return null;
try {
return JSON.parse(text);
} catch {
return text;
}
}
function responseMessage(payload, fallback) {
if (payload && typeof payload === 'object' && typeof payload.message === 'string' && payload.message.trim()) {
return payload.message.trim();
}
if (typeof payload === 'string' && payload.trim()) return payload.trim();
return fallback;
}
export function createPlanSyncService(logger = console) {
const baseUrl = trimEnv('PLAN_SYNC_TARGET_BASE_URL').replace(/\/$/, '');
const username = trimEnv('PLAN_SYNC_USERNAME');
const password = trimEnv('PLAN_SYNC_PASSWORD');
const timeoutMs = parseTimeout(trimEnv('PLAN_SYNC_TIMEOUT_MS'));
if (!baseUrl || !username || !password) {
return {
enabled: false,
reason: '未配置生产套餐同步环境变量',
async syncPlanUpsert() {
return { enabled: false, ok: false, message: '未配置生产套餐同步环境变量' };
},
async syncPlanDelete() {
return { enabled: false, ok: false, message: '未配置生产套餐同步环境变量' };
},
async syncAllPlans() {
return { enabled: false, ok: false, message: '未配置生产套餐同步环境变量', synced: 0, total: 0 };
},
};
}
async function request(path, init = {}) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
return await fetch(`${baseUrl}${path}`, { ...init, signal: controller.signal });
} finally {
clearTimeout(timer);
}
}
async function loginAndGetCookie() {
const response = await request('/auth/login', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ username, password }),
});
const payload = await safeJson(response);
if (!response.ok) {
throw new Error(`生产后台登录失败:${responseMessage(payload, `${response.status} ${response.statusText}`)}`);
}
const cookie = response.headers.get('set-cookie');
if (!cookie) throw new Error('生产后台登录成功,但未返回会话 Cookie');
return cookie.split(';', 1)[0];
}
async function syncRequest(path, init = {}) {
const cookie = await loginAndGetCookie();
const response = await request(path, {
...init,
headers: {
'content-type': 'application/json',
'x-plan-sync-hop': '1',
...(init.headers ?? {}),
cookie,
},
});
const payload = await safeJson(response);
if (!response.ok) {
throw new Error(responseMessage(payload, `${response.status} ${response.statusText}`));
}
return payload;
}
async function syncPlanUpsert(planType, plan) {
try {
await syncRequest(`/admin-api/subscriptions/plans/${encodeURIComponent(planType)}`, {
method: 'PUT',
body: JSON.stringify(plan),
});
return {
enabled: true,
ok: true,
message: `已同步到生产后台 ${baseUrl}`,
};
} catch (error) {
logger.warn?.('[plan-sync] upsert failed', { planType, error: String(error) });
return {
enabled: true,
ok: false,
message: error instanceof Error ? error.message : '同步生产后台失败',
};
}
}
async function syncPlanDelete(planType) {
try {
await syncRequest(`/admin-api/subscriptions/plans/${encodeURIComponent(planType)}`, {
method: 'DELETE',
});
return {
enabled: true,
ok: true,
message: `已同步删除生产后台套餐 ${planType}`,
};
} catch (error) {
logger.warn?.('[plan-sync] delete failed', { planType, error: String(error) });
return {
enabled: true,
ok: false,
message: error instanceof Error ? error.message : '同步生产后台失败',
};
}
}
async function syncAllPlans(plans) {
let synced = 0;
const failures = [];
for (const plan of plans) {
const result = await syncPlanUpsert(plan.planType, plan);
if (result.ok) synced += 1;
else failures.push(`${plan.planType}: ${result.message}`);
}
return {
enabled: true,
ok: failures.length === 0,
message: failures.length === 0
? `已同步 ${synced}/${plans.length} 个套餐到生产后台`
: `已同步 ${synced}/${plans.length} 个套餐,失败:${failures.join('')}`,
synced,
total: plans.length,
failures,
};
}
return {
enabled: true,
reason: '',
syncPlanUpsert,
syncPlanDelete,
syncAllPlans,
};
}