fix: import migration via web api body
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-27 16:46:01 +08:00
parent 3178c26095
commit 9aae7afb2e
3 changed files with 124 additions and 18 deletions

View File

@@ -4,7 +4,9 @@ import { readFile } from 'node:fs/promises';
import path from 'node:path';
import {
assertReadableFile,
callSpacetimeProcedureAuto,
callSpacetimeProcedure,
callSpacetimeProcedureViaCli,
createSpacetimeWebIdentity,
ensureProcedureOk,
parseArgs,
} from './spacetime-migration-common.mjs';
@@ -22,17 +24,13 @@ try {
throw new Error(`迁移文件为空: ${inPath}`);
}
const input = {
migration_json: migrationJson,
include_tables: options.includeTables,
replace_existing: options.replaceExisting === true,
dry_run: options.dryRun === true,
};
const result = await callSpacetimeProcedureAuto(
options,
'import_database_migration_from_file',
input,
);
const webOptions = await prepareWebImportOptions(options);
let result;
try {
result = await importMigrationJsonDirect(webOptions, migrationJson);
} finally {
await revokeTemporaryWebIdentity(webOptions);
}
ensureProcedureOk(result);
console.log(
@@ -46,6 +44,68 @@ try {
process.exit(1);
}
async function prepareWebImportOptions(options) {
if (options.token) {
return { ...options, useHttp: true };
}
const identity = await createSpacetimeWebIdentity(options);
console.log(
`[spacetime:migration:import] 已通过 Web API 创建临时 identity: ${identity.identity}`,
);
const authorizeResult = await callSpacetimeProcedureViaCli(
options,
'authorize_database_migration_operator',
{
bootstrap_secret: options.bootstrapSecret || '',
operator_identity_hex: identity.identity,
note: options.note || 'temporary web api migration import',
},
);
ensureProcedureOk(authorizeResult);
console.log(`[spacetime:migration:import] 已授权临时 Web API identity`);
return {
...options,
token: identity.token,
temporaryWebIdentity: identity.identity,
useHttp: true,
};
}
async function importMigrationJsonDirect(options, migrationJson) {
const input = {
migration_json: migrationJson,
include_tables: options.includeTables,
replace_existing: options.replaceExisting === true,
dry_run: options.dryRun === true,
};
return callSpacetimeProcedure(options, 'import_database_migration_from_file', input);
}
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:import] 已撤销临时 Web API identity`);
} catch (error) {
console.warn(
`[spacetime:migration:import] 撤销临时 Web API identity 失败: ${
error instanceof Error ? error.message : String(error)
}`,
);
}
}
function printTableStats(tableStats) {
if (!Array.isArray(tableStats) || tableStats.length === 0) {
return;

View File

@@ -133,6 +133,42 @@ export async function callSpacetimeProcedure(options, procedureName, input) {
return parseProcedureResult(text);
}
export async function createSpacetimeWebIdentity(options) {
const serverUrl = resolveServerUrl(options).replace(/\/+$/u, '');
const url = `${serverUrl}/v1/identity`;
let response;
try {
response = await fetch(url, { method: 'POST' });
} catch (error) {
throw new Error(
`SpacetimeDB identity 请求失败: ${url}; ${error instanceof Error ? error.message : String(error)}`,
);
}
const text = await response.text();
if (!response.ok) {
throw new Error(`SpacetimeDB identity HTTP ${response.status}: ${trimPreview(text)}`);
}
let payload;
try {
payload = JSON.parse(text);
} catch (error) {
throw new Error(
`SpacetimeDB identity 响应不是合法 JSON: ${error instanceof Error ? error.message : String(error)}`,
);
}
const identity =
payload.identity ?? payload.Identity ?? payload.identity_hex ?? payload.identityHex;
const token = payload.token ?? payload.Token;
if (typeof identity !== 'string' || typeof token !== 'string') {
throw new Error(`SpacetimeDB identity 响应缺少 identity/token: ${trimPreview(text)}`);
}
return { identity, token };
}
export async function callSpacetimeProcedureAuto(options, procedureName, input) {
if (options.useHttp) {
return callSpacetimeProcedure(options, procedureName, input);
@@ -266,7 +302,7 @@ function normalizeTableStats(value) {
});
}
function resolveServerUrl(options) {
export function resolveServerUrl(options) {
if (options.serverUrl) {
return options.serverUrl;
}