feat: 完善敲木鱼玩法模板链路

This commit is contained in:
2026-05-24 02:49:13 +08:00
parent 2ba4691bc0
commit 8638397faa
402 changed files with 2329 additions and 1781 deletions

View File

@@ -257,6 +257,96 @@ function requireCommand(command) {
}
}
function readWorkspaceSpacetimeVersion() {
const manifestText = readFileSync(manifestPath, 'utf8');
const match = /^spacetimedb\s*=\s*(?:"([^"]+)"|\{[^}]*version\s*=\s*"([^"]+)")/mu.exec(
manifestText,
);
const version = match?.[1] ?? match?.[2] ?? '';
if (!version) {
throw new Error('无法从 server-rs/Cargo.toml 读取 spacetimedb 版本');
}
return version;
}
function parseSpacetimeToolVersion(output) {
const match = /spacetimedb tool version\s+([0-9]+\.[0-9]+\.[0-9]+)/u.exec(output);
return match?.[1] ?? '';
}
function readSpacetimeToolVersion() {
const result = spawnSync('spacetime', ['--version'], {
cwd: repoRoot,
encoding: 'utf8',
shell: process.platform === 'win32',
});
if (result.error) {
throw new Error(`读取 spacetime 版本失败: ${result.error.message}`);
}
const output = `${result.stdout ?? ''}\n${result.stderr ?? ''}`;
const version = parseSpacetimeToolVersion(output);
if (!version) {
throw new Error(`无法解析 spacetime 版本输出: ${trimPreview(output)}`);
}
return version;
}
function assertSpacetimeToolVersionMatchesWorkspace({
toolVersion,
workspaceVersion,
}) {
if (toolVersion === workspaceVersion) {
return;
}
throw new Error(
[
`本机 spacetime CLI/standalone 版本 ${toolVersion} 与 server-rs 锁定的 SpacetimeDB ${workspaceVersion} 不一致。`,
'版本错位会导致 procedure 返回值 BSATN 反序列化失败,前端表现为 SpacetimeDB procedure 调用超时。',
`请执行 spacetime version install ${workspaceVersion} && spacetime version use ${workspaceVersion} 后重新运行本命令。`,
].join(''),
);
}
function assertReusableSpacetimeProcessVersionMatchesWorkspace({
dataDir,
serverUrl,
}) {
const recordedVersion = readRecordedSpacetimeToolVersion(dataDir);
const workspaceVersion = readWorkspaceSpacetimeVersion();
if (!recordedVersion) {
throw new Error(
[
`检测到正在运行的本地 SpacetimeDB: ${serverUrl},但缺少 SpacetimeDB 版本记录。`,
'为避免复用旧 standalone 导致 procedure 返回值 BSATN 反序列化失败和前端调用超时,请先停止该进程,再重新运行 npm run dev:spacetime。',
].join(''),
);
}
if (recordedVersion === workspaceVersion) {
return;
}
throw new Error(
[
`正在运行的本地 SpacetimeDB standalone 版本 ${recordedVersion} 与 server-rs 锁定的 SpacetimeDB ${workspaceVersion} 不一致。`,
'版本错位会导致 procedure 返回值 BSATN 反序列化失败,前端表现为 SpacetimeDB procedure 调用超时。',
'请停止当前 SpacetimeDB 进程,执行 spacetime version use ',
workspaceVersion,
' 后重新运行 npm run dev:spacetime。',
].join(''),
);
}
function ensureSpacetimeToolVersionMatchesWorkspace() {
assertSpacetimeToolVersionMatchesWorkspace({
toolVersion: readSpacetimeToolVersion(),
workspaceVersion: readWorkspaceSpacetimeVersion(),
});
}
function ensureRequiredFiles(command) {
const requiredFiles = [];
@@ -478,6 +568,9 @@ class DevRunner {
) {
requireCommand('spacetime');
}
if (this.shouldValidateSpacetimeToolVersion(command)) {
ensureSpacetimeToolVersionMatchesWorkspace();
}
await this.tryReuseExistingSpacetime(command);
await this.resolvePorts(command);
@@ -485,6 +578,19 @@ class DevRunner {
this.printSummary(command);
}
shouldValidateSpacetimeToolVersion(command) {
if (command === 'spacetime') {
return true;
}
if (command === 'all') {
return !this.options.skipSpacetime || !this.options.skipPublish;
}
if (command === 'api-server') {
return isLoopbackSpacetimeServer(this.state.spacetimeServer);
}
return false;
}
async tryReuseExistingSpacetime(command) {
if (this.options.skipSpacetime) {
return;
@@ -525,6 +631,11 @@ class DevRunner {
continue;
}
assertReusableSpacetimeProcessVersionMatchesWorkspace({
dataDir: this.options.spacetimeDataDir,
serverUrl: candidate,
});
const port = safeUrlPort(candidate);
if (Number.isInteger(port) && port > 0) {
this.options.spacetimePort = port;
@@ -705,6 +816,15 @@ class DevRunner {
const logFile = resolve(options.spacetimeDataDir, 'logs/dev-spacetime-start.log');
const logStream = createWriteStream(logFile, {flags: 'a', encoding: 'utf8'});
service.logStream = logStream;
const spacetimeToolVersion = readSpacetimeToolVersion();
assertSpacetimeToolVersionMatchesWorkspace({
toolVersion: spacetimeToolVersion,
workspaceVersion: readWorkspaceSpacetimeVersion(),
});
recordSpacetimeToolVersion(
options.spacetimeDataDir,
spacetimeToolVersion,
);
console.log(`[dev:spacetime] log: ${logFile}`);
const env = {
@@ -1357,6 +1477,15 @@ function readRecordedSpacetimeUrl(dataDir) {
return '';
}
function readRecordedSpacetimeToolVersion(dataDir) {
const versionPath = resolve(dataDir, 'dev-spacetime-tool-version');
if (!existsSync(versionPath)) {
return '';
}
return readFileSync(versionPath, 'utf8').split(/\r?\n/u)[0]?.trim() ?? '';
}
function readRecordedSpacetimePidState(dataDir) {
const pidPath = resolve(dataDir, 'spacetime.pid');
if (!existsSync(pidPath)) {
@@ -1389,6 +1518,16 @@ function readRecordedSpacetimePidState(dataDir) {
}
}
function recordSpacetimeToolVersion(dataDir, version) {
const versionPath = resolve(dataDir, 'dev-spacetime-tool-version');
ensureParentDir(versionPath);
try {
writeFileSync(versionPath, `${version}\n`, 'utf8');
} catch (error) {
console.warn(`[dev:spacetime] 写入版本记录失败 ${versionPath}: ${error.message}`);
}
}
function recordSpacetimeUrl(dataDir, serverUrl) {
const targets = [
resolve(dataDir, 'dev-spacetime-url'),
@@ -1580,10 +1719,13 @@ function isSpacetimePublishPermissionError(error) {
export {
DevRunner,
assertReusableSpacetimeProcessVersionMatchesWorkspace,
assertSpacetimeToolVersionMatchesWorkspace,
buildSpacetimePublishArgs,
createDevServerSpawnOptions,
createWatchConfigs,
isSpacetimePublishPermissionError,
parseSpacetimeToolVersion,
parseArgs,
shouldAcceptWatchEvent,
};