387a1c26e3
清理已跟踪原始日志与个人本地配置 修复前后端有效门禁、测试和构建问题 补齐生产 Jenkins、SpacetimeDB 本地命令与文档约束 收紧图片编辑器状态、附件与媒体引用测试 排除已下线旧创作入口测试并清理 warning
138 lines
3.9 KiB
JavaScript
138 lines
3.9 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { writeFile } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
|
|
import {
|
|
callSpacetimeProcedure,
|
|
callSpacetimeProcedureViaCli,
|
|
createSpacetimeWebIdentity,
|
|
ensureParentDir,
|
|
ensureProcedureOk,
|
|
parseArgs,
|
|
resolveBootstrapSecret,
|
|
} from './spacetime-migration-common.mjs';
|
|
|
|
try {
|
|
const options = parseArgs(process.argv.slice(2));
|
|
if (!options.out) {
|
|
throw new Error('必须传入 --out。');
|
|
}
|
|
|
|
const input = {
|
|
include_tables: options.includeTables,
|
|
};
|
|
const webOptions = await prepareWebExportOptions(options);
|
|
let result;
|
|
try {
|
|
result = await callSpacetimeProcedure(webOptions, 'export_database_migration_to_file', input);
|
|
} finally {
|
|
await revokeTemporaryWebIdentity(webOptions);
|
|
}
|
|
ensureProcedureOk(result);
|
|
|
|
if (typeof result.migration_json !== 'string' || result.migration_json.trim() === '') {
|
|
throw new Error('导出 procedure 没有返回 migration_json。');
|
|
}
|
|
|
|
const outPath = path.resolve(options.out);
|
|
await ensureParentDir(outPath);
|
|
await writeFile(outPath, result.migration_json, 'utf8');
|
|
|
|
console.log(`[spacetime:migration:export] 已写入 ${outPath}`);
|
|
printTableStats(result.table_stats);
|
|
printMigrationWarnings(result.warnings);
|
|
} catch (error) {
|
|
console.error(
|
|
`[spacetime:migration:export] ${error instanceof Error ? error.message : String(error)}`,
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
async function prepareWebExportOptions(options) {
|
|
if (options.token) {
|
|
return { ...options, useHttp: true };
|
|
}
|
|
|
|
const identity = await createSpacetimeWebIdentity(options);
|
|
console.log(
|
|
`[spacetime:migration:export] 已通过 Web API 创建临时 identity: ${identity.identity}`,
|
|
);
|
|
|
|
try {
|
|
const authorizeResult = await callSpacetimeProcedureViaCli(
|
|
options,
|
|
'authorize_database_migration_operator',
|
|
{
|
|
bootstrap_secret: await resolveBootstrapSecret(options),
|
|
operator_identity_hex: identity.identity,
|
|
note: options.note || 'temporary web api migration export',
|
|
},
|
|
);
|
|
ensureProcedureOk(authorizeResult);
|
|
} catch (error) {
|
|
throw new Error(
|
|
`授权临时 Web API identity 失败。当前 spacetime CLI identity 必须已经是迁移操作员;如果旧库迁移操作员表不为空,bootstrap secret 不会越权授权新的操作员。可先用已有迁移操作员授权当前部署机 identity,或为导出脚本提供已有迁移操作员的 --token。原始错误: ${
|
|
error instanceof Error ? error.message : String(error)
|
|
}`,
|
|
);
|
|
}
|
|
console.log(`[spacetime:migration:export] 已授权临时 Web API identity`);
|
|
|
|
return {
|
|
...options,
|
|
token: identity.token,
|
|
temporaryWebIdentity: identity.identity,
|
|
useHttp: true,
|
|
};
|
|
}
|
|
|
|
async function revokeTemporaryWebIdentity(options) {
|
|
if (!options.temporaryWebIdentity) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const revokeResult = await callSpacetimeProcedure(
|
|
options,
|
|
'revoke_database_migration_operator',
|
|
{ operator_identity_hex: options.temporaryWebIdentity },
|
|
);
|
|
ensureProcedureOk(revokeResult);
|
|
console.log(`[spacetime:migration:export] 已撤销临时 Web API identity`);
|
|
} catch (error) {
|
|
console.warn(
|
|
`[spacetime:migration:export] 撤销临时 Web API identity 失败: ${
|
|
error instanceof Error ? error.message : String(error)
|
|
}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
function printTableStats(tableStats) {
|
|
if (!Array.isArray(tableStats) || tableStats.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const rows = tableStats.map((stat) => ({
|
|
table: stat.table_name,
|
|
exported: stat.exported_row_count,
|
|
}));
|
|
console.table(rows);
|
|
}
|
|
|
|
function printMigrationWarnings(warnings) {
|
|
if (!Array.isArray(warnings) || warnings.length === 0) {
|
|
return;
|
|
}
|
|
|
|
console.warn('[spacetime:migration:export] 迁移告警:');
|
|
console.table(
|
|
warnings.map((warning) => ({
|
|
table: warning.table_name,
|
|
kind: warning.warning_kind,
|
|
message: warning.message,
|
|
})),
|
|
);
|
|
}
|