This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user